From 4af40141bd8679849e32cccd134c08f991579c4b Mon Sep 17 00:00:00 2001 From: Serdar Kocdemir Date: Tue, 30 Jun 2026 11:07:45 +0100 Subject: [PATCH 01/33] Fix validation checks on emulated textures Emulated textures will use a different format for the image creation parameters and their device format properties needs to be checked based on the actual format to be used. Fixes the issues on dEQP tests with astc/etc formats Bug: 514640182 Bug: 528235892 Test: dEQP-VK.api.*.blit_image.all_formats.color.2d.astc* Test: dEQP-VK.api.*.blit_image.all_formats.color.2d.etc* Test: run_deqp_runner.py on macOS Change-Id: I1b8fea2af52426ebedcdf87e7ea5e26962014d13 --- host/vulkan/vk_decoder_global_state.cpp | 28 ++++++++++++++----------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/host/vulkan/vk_decoder_global_state.cpp b/host/vulkan/vk_decoder_global_state.cpp index 3161cf00b..788cee220 100644 --- a/host/vulkan/vk_decoder_global_state.cpp +++ b/host/vulkan/vk_decoder_global_state.cpp @@ -3002,6 +3002,18 @@ class VkDecoderGlobalState::Impl { return VK_ERROR_OUT_OF_HOST_MEMORY; } + // Change creation parameters before the validation checks below as the + // creation format and its device properties may change + const bool needDecompression = deviceInfo->needEmulatedDecompression(pCreateInfo->format); + std::unique_ptr cmpInfo = nullptr; + VkImageCreateInfo decompInfo; + if (needDecompression) { + cmpInfo = std::make_unique(device, *pCreateInfo, + deviceInfo->decompPipelines.get()); + decompInfo = cmpInfo->getOutputCreateInfo(*pCreateInfo); + pCreateInfo = &decompInfo; + } + #ifdef __APPLE__ // TODO(b/438924843) this is probably not optimal as it might slow down image creation a // bit. Not validating the dimensions seems to be only fatal on macOS, and can create false @@ -3028,8 +3040,10 @@ class VkDecoderGlobalState::Impl { if (res != VK_SUCCESS) { GFXSTREAM_WARNING( - "vkCreateImage: vkGetPhysicalDeviceImageFormatProperties failed with %s", - string_VkResult(res)); + "vkCreateImage: vkGetPhysicalDeviceImageFormatProperties failed with %s on " + "format %s[%d]", + string_VkResult(res), string_VkFormat(pCreateInfo->format), + pCreateInfo->format); return VK_ERROR_VALIDATION_FAILED_EXT; } @@ -3047,16 +3061,6 @@ class VkDecoderGlobalState::Impl { } #endif - const bool needDecompression = deviceInfo->needEmulatedDecompression(pCreateInfo->format); - std::unique_ptr cmpInfo = nullptr; - VkImageCreateInfo decompInfo; - if (needDecompression) { - cmpInfo = std::make_unique(device, *pCreateInfo, - deviceInfo->decompPipelines.get()); - decompInfo = cmpInfo->getOutputCreateInfo(*pCreateInfo); - pCreateInfo = &decompInfo; - } - std::unique_ptr anbInfo = nullptr; const VkNativeBufferANDROID* nativeBufferANDROID = vk_find_struct(pCreateInfo); From 06d9fff9ece77dc656ee6853776be54c93ee6e2f Mon Sep 17 00:00:00 2001 From: Serdar Kocdemir Date: Wed, 1 Jul 2026 01:03:39 +0100 Subject: [PATCH 02/33] Add 64-bit unsigned integer feature type Bug: 528235892 Test: U64FeatureInfoTest Change-Id: I9a11bc711c3a059a45799ab0009711e928ac9c96 --- host/features/features.cpp | 41 +++++++++++++- host/features/features_unittest.cpp | 56 +++++++++++++++++++ .../include/gfxstream/host/features.h | 17 +++++- 3 files changed, 109 insertions(+), 5 deletions(-) diff --git a/host/features/features.cpp b/host/features/features.cpp index 52880599f..8da90e877 100644 --- a/host/features/features.cpp +++ b/host/features/features.cpp @@ -81,7 +81,7 @@ bool U32FeatureInfo::parseValue(std::string_view strValue) { uint32_t val; auto res = std::from_chars(strValue.data() + valueStart, strValue.data() + strValue.size(), val, valueBase); - if (res.ec == std::errc()) { + if (res.ec == std::errc() && res.ptr == strValue.data() + strValue.size()) { value = U32FeatureValue(val); return true; } @@ -95,13 +95,50 @@ std::string U32FeatureInfo::getValueReadable() const { return "(Unset)"; } - // E.g. '123 (0x7B)' + // E.g. '123 (0x7b)' const uint32_t val = u32ValueOpt.value(); std::ostringstream oss; oss << val << " (0x" << std::hex << val << ")"; return oss.str(); } +bool U64FeatureInfo::parseValue(std::string_view strValue) { + if (strValue.empty()) { + value = U64FeatureValue(std::nullopt); + return true; + } + int valueStart = 0; + int valueBase = 10; + // Check if the value is given as a hexadecimal value + if (strValue.size() > 2 && strValue[0] == '0' && + (strValue[1] == 'x' || strValue[1] == 'X')) { + valueStart = 2; + valueBase = 16; + } + uint64_t val; + auto res = std::from_chars(strValue.data() + valueStart, strValue.data() + strValue.size(), + val, valueBase); + if (res.ec == std::errc() && res.ptr == strValue.data() + strValue.size()) { + value = U64FeatureValue(val); + return true; + } + GFXSTREAM_ERROR("Cannot parse '%.*s' for feature '%s'", (int)strValue.size(), strValue.data(), name.c_str()); + return false; +} + +std::string U64FeatureInfo::getValueReadable() const { + auto u64ValueOpt = std::get(value); + if (!u64ValueOpt) { + return "(Unset)"; + } + + // E.g. '123 (0x7b)' + const uint64_t val = u64ValueOpt.value(); + std::ostringstream oss; + oss << val << " (0x" << std::hex << val << ")"; + return oss.str(); +} + bool VulkanVersionFeatureInfo::parseValue(std::string_view strValue) { // Parse vulkan version info, can be in 1.2, 1.2.3 or integer format if (strValue.find('.') != std::string_view::npos) { diff --git a/host/features/features_unittest.cpp b/host/features/features_unittest.cpp index 5db2781e5..d7cdd50f8 100644 --- a/host/features/features_unittest.cpp +++ b/host/features/features_unittest.cpp @@ -105,6 +105,62 @@ TEST_F(FeaturesTest, U32FeatureInfoTest) { EXPECT_FALSE(u32Feature.parseValue("invalid_number")); } +TEST_F(FeaturesTest, U64FeatureInfoTest) { + FeatureMap map; + U64FeatureInfo u64Feature("TestU64", "Description", &map); + + EXPECT_EQ(u64Feature.getName(), "TestU64"); + EXPECT_FALSE(u64Feature.getValue().has_value()); + EXPECT_EQ(u64Feature.getValueReadable(), "(Unset)"); + + EXPECT_TRUE(u64Feature.parseValue("123")); + ASSERT_TRUE(u64Feature.getValue().has_value()); + EXPECT_EQ(u64Feature.getValue().value(), 123uLL); + EXPECT_EQ(u64Feature.getValueReadable(), "123 (0x7b)"); + + EXPECT_TRUE(u64Feature.parseValue("0x7B")); + ASSERT_TRUE(u64Feature.getValue().has_value()); + EXPECT_EQ(u64Feature.getValue().value(), 123uLL); + EXPECT_EQ(u64Feature.getValueReadable(), "123 (0x7b)"); + + EXPECT_TRUE(u64Feature.parseValue("0")); + ASSERT_TRUE(u64Feature.getValue().has_value()); + EXPECT_EQ(u64Feature.getValue().value(), 0uLL); + EXPECT_EQ(u64Feature.getValueReadable(), "0 (0x0)"); + + // Test a number that requires > 32 bits, e.g. 5000000000 (0x12A05F200) + EXPECT_TRUE(u64Feature.parseValue("5000000000")); + ASSERT_TRUE(u64Feature.getValue().has_value()); + EXPECT_EQ(u64Feature.getValue().value(), 5000000000uLL); + EXPECT_EQ(u64Feature.getValueReadable(), "5000000000 (0x12a05f200)"); + + EXPECT_TRUE(u64Feature.parseValue("0x12A05F200")); + ASSERT_TRUE(u64Feature.getValue().has_value()); + EXPECT_EQ(u64Feature.getValue().value(), 5000000000uLL); + EXPECT_EQ(u64Feature.getValueReadable(), "5000000000 (0x12a05f200)"); + + EXPECT_TRUE(u64Feature.parseValue("")); + EXPECT_FALSE(u64Feature.getValue().has_value()); + EXPECT_EQ(u64Feature.getValueReadable(), "(Unset)"); + + EXPECT_FALSE(u64Feature.parseValue("invalid_number")); + + u64Feature.setValue(999uLL); + ASSERT_TRUE(u64Feature.getValue().has_value()); + EXPECT_EQ(u64Feature.getValue().value(), 999uLL); + EXPECT_EQ(u64Feature.getValueReadable(), "999 (0x3e7)"); + + u64Feature.setValue(18446744073709551615uLL); + ASSERT_TRUE(u64Feature.getValue().has_value()); + EXPECT_EQ(u64Feature.getValue().value(), 18446744073709551615uLL); + EXPECT_EQ(u64Feature.getValueReadable(), "18446744073709551615 (0xffffffffffffffff)"); + + EXPECT_TRUE(u64Feature.parseValue("18446744073709551615")); + ASSERT_TRUE(u64Feature.getValue().has_value()); + EXPECT_EQ(u64Feature.getValue().value(), 18446744073709551615uLL); + EXPECT_EQ(u64Feature.getValueReadable(), "18446744073709551615 (0xffffffffffffffff)"); +} + TEST_F(FeaturesTest, VulkanVersionFeatureInfoTest) { FeatureMap map; VulkanVersionFeatureInfo vkVersionFeature("TestVkVersion", "Description", &map); diff --git a/host/features/include/gfxstream/host/features.h b/host/features/include/gfxstream/host/features.h index 5e11fe3bb..66cfe82cf 100644 --- a/host/features/include/gfxstream/host/features.h +++ b/host/features/include/gfxstream/host/features.h @@ -32,7 +32,8 @@ using FeatureMap = std::map; // The potential types for the "value" of a given feature using StringFeatureValue = std::optional; using U32FeatureValue = std::optional; -using FeatureValue = std::variant; +using U64FeatureValue = std::optional; +using FeatureValue = std::variant; class FeatureInfoBase { public: @@ -96,13 +97,23 @@ class U32FeatureInfo : public FeatureInfoBase { std::string getValueReadable() const override; }; +class U64FeatureInfo : public FeatureInfoBase { + public: + U64FeatureInfo(std::string_view name, std::string_view description, FeatureMap* map) + : FeatureInfoBase(name, description, map, U64FeatureValue(std::nullopt)) {} + + U64FeatureValue getValue() const { return std::get(value); } + void setValue(uint64_t val) { value = U64FeatureValue(val); } + + bool parseValue(std::string_view strValue) override; + std::string getValueReadable() const override; +}; + class VulkanVersionFeatureInfo : public U32FeatureInfo { public: VulkanVersionFeatureInfo(std::string_view name, std::string_view description, FeatureMap* map) : U32FeatureInfo(name, description, map) {} - U32FeatureValue getValue() const { return std::get(value); } - bool parseValue(std::string_view strValue) override; std::string getValueReadable() const override; }; From 65e84045f0027b34d6b1cbbb54e32d0d00c260d4 Mon Sep 17 00:00:00 2001 From: Serdar Kocdemir Date: Wed, 1 Jul 2026 01:06:28 +0100 Subject: [PATCH 03/33] Add VulkanMaxSafeHeapSize feature This feature will limit the heap sizes for the guest to the value given. No limit will be applied if the value is not set, or if it's set to zero. Note that previous default behavior with 2GB limit is removed with this change as it can lead to some apps not work as expected. Limits should be set from a higher level during gfxstream initialization based on host and guest requirements. Bug: 528235892 Test: VkGuestMemoryUtilsTest Test: Benchmarking apps Change-Id: I28716f3c353a72d1b2711a98c04d471598763bf9 --- .../include/gfxstream/host/features.h | 5 + .../vk_emulated_physical_device_memory.cpp | 31 +-- .../vk_emulated_physical_device_memory.h | 12 +- ..._emulated_physical_device_memory_tests.cpp | 179 +++++++++++++++--- 4 files changed, 173 insertions(+), 54 deletions(-) diff --git a/host/features/include/gfxstream/host/features.h b/host/features/include/gfxstream/host/features.h index 66cfe82cf..98d00e589 100644 --- a/host/features/include/gfxstream/host/features.h +++ b/host/features/include/gfxstream/host/features.h @@ -449,6 +449,11 @@ struct FeatureSet { " not related to the host vulkan level available or used.", &map, }; + U64FeatureInfo VulkanMaxSafeHeapSize = { + "VulkanMaxSafeHeapSize", + "If set to a non-zero value, limits the memory heap size reported to the guest (in bytes).", + &map, + }; }; #define GFXSTREAM_SET_BOOL_FEATURE_ON_CONDITION(set, feature, condition) \ diff --git a/host/vulkan/vk_emulated_physical_device_memory.cpp b/host/vulkan/vk_emulated_physical_device_memory.cpp index eda5b8122..0006d0a7e 100644 --- a/host/vulkan/vk_emulated_physical_device_memory.cpp +++ b/host/vulkan/vk_emulated_physical_device_memory.cpp @@ -30,9 +30,7 @@ static constexpr const uint32_t kInvalidMemoryTypeIndex = std::numeric_limits mMaxSafeHeapSize) { - mGuestMemoryProperties.memoryHeaps[i].size = mMaxSafeHeapSize; + // Limit max safe memory heap size if the VulkanMaxSafeHeapSize feature is set to a non-zero + // value. + const uint64_t maxSafeHeapSizeLimit = features.VulkanMaxSafeHeapSize.getValue().value_or(0); + if (maxSafeHeapSizeLimit > 0) { + for (uint32_t i = 0; i < mHostMemoryProperties.memoryHeapCount; i++) { + if (mGuestMemoryProperties.memoryHeaps[i].size > maxSafeHeapSizeLimit) { + mGuestMemoryProperties.memoryHeaps[i].size = maxSafeHeapSizeLimit; + } } } @@ -82,10 +83,13 @@ EmulatedPhysicalDeviceMemoryProperties::EmulatedPhysicalDeviceMemoryProperties( // Let cached memory pretend as coherent on the guest side. if (features.VulkanDisableCoherentMemoryAndEmulate.enabled()) { for (uint32_t i = 0; i < mGuestMemoryProperties.memoryTypeCount; i++) { - if (mGuestMemoryProperties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) { - mGuestMemoryProperties.memoryTypes[i].propertyFlags |= VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + if (mGuestMemoryProperties.memoryTypes[i].propertyFlags & + VK_MEMORY_PROPERTY_HOST_CACHED_BIT) { + mGuestMemoryProperties.memoryTypes[i].propertyFlags |= + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; } else { - mGuestMemoryProperties.memoryTypes[i].propertyFlags &= ~(VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + mGuestMemoryProperties.memoryTypes[i].propertyFlags &= + ~(VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); } } } @@ -131,8 +135,9 @@ EmulatedPhysicalDeviceMemoryProperties::EmulatedPhysicalDeviceMemoryProperties( // memory. if (features.VulkanUseDedicatedAhbMemoryType.enabled()) { if (mGuestMemoryProperties.memoryTypeCount == VK_MAX_MEMORY_TYPES) { - GFXSTREAM_FATAL("Unable to create emulated AHB memory type because VK_MAX_MEMORY_TYPES " - "already in use."); + GFXSTREAM_FATAL( + "Unable to create emulated AHB memory type because VK_MAX_MEMORY_TYPES " + "already in use."); } uint32_t ahbMemoryTypeIndex = mGuestMemoryProperties.memoryTypeCount; diff --git a/host/vulkan/vk_emulated_physical_device_memory.h b/host/vulkan/vk_emulated_physical_device_memory.h index b130f096b..9d344dc5f 100644 --- a/host/vulkan/vk_emulated_physical_device_memory.h +++ b/host/vulkan/vk_emulated_physical_device_memory.h @@ -30,14 +30,9 @@ namespace vk { // guest, and helps to convert between both. class EmulatedPhysicalDeviceMemoryProperties { public: - // Hide any bogus heap sizes from bad drivers with a reasonable default that will not - // break the bank on 32-bit userspaces. - static constexpr VkDeviceSize kDefaultMaxSafeHeapSize = 2ULL * 1024ULL * 1024ULL * 1024ULL; - EmulatedPhysicalDeviceMemoryProperties(const VkPhysicalDeviceMemoryProperties& host, uint32_t hostColorBufferMemoryTypeIndex, - const gfxstream::host::FeatureSet& features, - VkDeviceSize maxSafeHeapSize = kDefaultMaxSafeHeapSize); + const gfxstream::host::FeatureSet& features); struct HostMemoryInfo { uint32_t index; @@ -55,9 +50,7 @@ class EmulatedPhysicalDeviceMemoryProperties { return mHostMemoryProperties; } - uint32_t getGuestColorBufferMemoryTypeIndex() const { - return mGuestColorBufferMemoryTypeIndex; - } + uint32_t getGuestColorBufferMemoryTypeIndex() const { return mGuestColorBufferMemoryTypeIndex; } void transformToGuestMemoryRequirements(VkMemoryRequirements* hostMemoryRequirements) const; @@ -66,7 +59,6 @@ class EmulatedPhysicalDeviceMemoryProperties { VkPhysicalDeviceMemoryBudgetPropertiesEXT* budgetProps) const; private: - VkDeviceSize mMaxSafeHeapSize; VkPhysicalDeviceMemoryProperties mGuestMemoryProperties; VkPhysicalDeviceMemoryProperties mHostMemoryProperties; uint32_t mGuestToHostMemoryTypeIndexMap[VK_MAX_MEMORY_TYPES]; diff --git a/host/vulkan/vk_emulated_physical_device_memory_tests.cpp b/host/vulkan/vk_emulated_physical_device_memory_tests.cpp index b4ac86fef..cb8167f5b 100644 --- a/host/vulkan/vk_emulated_physical_device_memory_tests.cpp +++ b/host/vulkan/vk_emulated_physical_device_memory_tests.cpp @@ -17,8 +17,8 @@ #include -#include "vk_emulated_physical_device_memory.h" #include "gfxstream/host/features.h" +#include "vk_emulated_physical_device_memory.h" namespace gfxstream { namespace host { @@ -259,6 +259,122 @@ TEST(VkGuestMemoryUtilsTest, VulkanAllocateDeviceMemoryOnly) { EXPECT_THAT(actualGuestMemoryProperties, EqsVkPhysicalDeviceMemoryProperties(expectedGuestMemoryProperties)); } + +TEST(VkGuestMemoryUtilsTest, VulkanMaxSafeHeapSizeUnset) { + const VkPhysicalDeviceMemoryProperties hostMemoryProperties = { + .memoryTypeCount = 1, + .memoryTypes = + { + { + .propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + .heapIndex = 0, + }, + }, + .memoryHeapCount = 2, + .memoryHeaps = + { + { + .size = 0x100000000ULL, // 4 GB + .flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT, + }, + { + .size = 0x200000000ULL, // 8 GB + .flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT, + }, + }, + }; + + gfxstream::host::FeatureSet features; + // VulkanMaxSafeHeapSize is left unset (default: zero, no limit) + + EmulatedPhysicalDeviceMemoryProperties helper(hostMemoryProperties, 0, features); + + const VkPhysicalDeviceMemoryProperties expectedGuestMemoryProperties = { + .memoryTypeCount = 1, + .memoryTypes = + { + { + .propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + .heapIndex = 0, + }, + }, + .memoryHeapCount = 2, + .memoryHeaps = + { + { + .size = 0x100000000ULL, + .flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT, + }, + { + .size = 0x200000000ULL, + .flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT, + }, + }, + }; + + const auto actualGuestMemoryProperties = helper.getGuestMemoryProperties(); + EXPECT_THAT(actualGuestMemoryProperties, + EqsVkPhysicalDeviceMemoryProperties(expectedGuestMemoryProperties)); +} + +TEST(VkGuestMemoryUtilsTest, VulkanMaxSafeHeapSizeSet) { + const VkPhysicalDeviceMemoryProperties hostMemoryProperties = { + .memoryTypeCount = 1, + .memoryTypes = + { + { + .propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + .heapIndex = 0, + }, + }, + .memoryHeapCount = 2, + .memoryHeaps = + { + { + .size = 0x100000000ULL, // 4 GB + .flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT, + }, + { + .size = 0x200000000ULL, // 8 GB + .flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT, + }, + }, + }; + + gfxstream::host::FeatureSet features; + // Set limit to 3 GB (0xC0000000 bytes) + features.VulkanMaxSafeHeapSize.parseValue("0xC0000000"); + + EmulatedPhysicalDeviceMemoryProperties helper(hostMemoryProperties, 0, features); + + const VkPhysicalDeviceMemoryProperties expectedGuestMemoryProperties = { + .memoryTypeCount = 1, + .memoryTypes = + { + { + .propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + .heapIndex = 0, + }, + }, + .memoryHeapCount = 2, + .memoryHeaps = + { + { + .size = 0xC0000000ULL, // Limited to 3 GB + .flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT, + }, + { + .size = 0xC0000000ULL, // Limited to 3 GB + .flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT, + }, + }, + }; + + const auto actualGuestMemoryProperties = helper.getGuestMemoryProperties(); + EXPECT_THAT(actualGuestMemoryProperties, + EqsVkPhysicalDeviceMemoryProperties(expectedGuestMemoryProperties)); +} + TEST(VkGuestMemoryUtilsTest, VulkanDisableCoherentMemoryAndEmulate) { const VkPhysicalDeviceMemoryProperties hostMemoryProperties = { .memoryTypeCount = 4, @@ -406,39 +522,40 @@ TEST(VkGuestMemoryUtilsTest, VulkanAMDCoherentFlagsNotLeakedToGuest) { // Standard types (types 0-3): hostMemoryProperties.memoryTypes[0] = {.propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, .heapIndex = 1}; - hostMemoryProperties.memoryTypes[1] = {.propertyFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - .heapIndex = 0}; + hostMemoryProperties.memoryTypes[1] = { + .propertyFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + .heapIndex = 0}; hostMemoryProperties.memoryTypes[2] = {.propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, .heapIndex = 1}; hostMemoryProperties.memoryTypes[3] = {.propertyFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | - VK_MEMORY_PROPERTY_HOST_CACHED_BIT, + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | + VK_MEMORY_PROPERTY_HOST_CACHED_BIT, .heapIndex = 0}; // AMD-specific types (types 4-7) with DEVICE_COHERENT and DEVICE_UNCACHED: - hostMemoryProperties.memoryTypes[4] = {.propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | - VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD | - VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD, - .heapIndex = 1}; - hostMemoryProperties.memoryTypes[5] = {.propertyFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | - VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD | - VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD, - .heapIndex = 0}; - hostMemoryProperties.memoryTypes[6] = {.propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | - VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD | - VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD, - .heapIndex = 1}; - hostMemoryProperties.memoryTypes[7] = {.propertyFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | - VK_MEMORY_PROPERTY_HOST_CACHED_BIT | - VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD | - VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD, - .heapIndex = 0}; + hostMemoryProperties.memoryTypes[4] = { + .propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | + VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD | + VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD, + .heapIndex = 1}; + hostMemoryProperties.memoryTypes[5] = { + .propertyFlags = + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | + VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD | VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD, + .heapIndex = 0}; + hostMemoryProperties.memoryTypes[6] = { + .propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | + VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD | + VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD, + .heapIndex = 1}; + hostMemoryProperties.memoryTypes[7] = { + .propertyFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT | + VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD | + VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD, + .heapIndex = 0}; gfxstream::host::FeatureSet features; EmulatedPhysicalDeviceMemoryProperties helper(hostMemoryProperties, 0, features); @@ -478,8 +595,7 @@ TEST(VkGuestMemoryUtilsTest, VulkanAMDCoherentFlagsNotLeakedToGuest) { } TEST(VkGuestMemoryUtilsTest, MemoryBudgetClampedToClampedGuestHeapSize) { - constexpr VkDeviceSize kMaxSafeHeapSize = - EmulatedPhysicalDeviceMemoryProperties::kDefaultMaxSafeHeapSize; + constexpr VkDeviceSize kMaxSafeHeapSize = 2ULL * 1024ULL * 1024ULL * 1024ULL; VkPhysicalDeviceMemoryProperties hostMemoryProperties = {}; hostMemoryProperties.memoryHeapCount = 2; @@ -491,6 +607,7 @@ TEST(VkGuestMemoryUtilsTest, MemoryBudgetClampedToClampedGuestHeapSize) { .heapIndex = 0}; gfxstream::host::FeatureSet features; + features.VulkanMaxSafeHeapSize.setValue(kMaxSafeHeapSize); EmulatedPhysicalDeviceMemoryProperties helper(hostMemoryProperties, 0, features); ASSERT_EQ(helper.getGuestMemoryProperties().memoryHeaps[0].size, kMaxSafeHeapSize); From b8500aa017614e797456fa84f2da1b15bbb7c0c1 Mon Sep 17 00:00:00 2001 From: Serdar Kocdemir Date: Fri, 3 Jul 2026 07:04:11 -0700 Subject: [PATCH 04/33] Add bounds check for vertex attribute buffer binding index. The code now verifies that the buffer binding index obtained from a vertex attribute pointer is within the valid range of the VAO's buffer bindings before accessing the buffer. This prevents potential out-of-bounds array access. Bug: 514119804 Test: CI Change-Id: I60292581793fbe4d4a59e143c060f4a7b8b1217f --- host/gl/glestranslator/common/gles_context.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/host/gl/glestranslator/common/gles_context.cpp b/host/gl/glestranslator/common/gles_context.cpp index 10aedb1a1..df539a4d5 100644 --- a/host/gl/glestranslator/common/gles_context.cpp +++ b/host/gl/glestranslator/common/gles_context.cpp @@ -364,9 +364,15 @@ bool GLEScontext::vertexAttributesBufferBacked() { const auto& info = m_currVaoState.attribInfo_const(); for (uint32_t i = 0; i < kMaxVertexAttributes; ++i) { const auto& pointerInfo = info[i]; - if (pointerInfo.isEnable() && - !m_currVaoState.bufferBindings()[pointerInfo.getBindingIndex()].buffer) { - return false; + if (pointerInfo.isEnable()) { + const auto bufferBindingIndex = pointerInfo.getBindingIndex(); + const auto& vaoBindings = m_currVaoState.bufferBindings(); + if (bufferBindingIndex >= vaoBindings.size()) { + return false; + } + if (!vaoBindings[bufferBindingIndex].buffer) { + return false; + } } } From 74cc8092dcee7bc96e2576765f60b1824edc85f4 Mon Sep 17 00:00:00 2001 From: Serdar Kocdemir Date: Fri, 3 Jul 2026 18:45:57 +0100 Subject: [PATCH 05/33] Fix compilation issues on Vulkan_unittests on macOS Bug: 524740795 Test: VkFormatUtilsTest Change-Id: I8f99cc47609406df14ee4eaa1bf768645e5b5f47 --- host/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index a09365316..d18a2a73e 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -358,7 +358,8 @@ endfunction() target_link_libraries( Vulkan_unittests PUBLIC - "-framework AppKit") + "-framework AppKit" + "-framework OpenGL") elseif (QNX) target_compile_definitions(Vulkan_unittests PRIVATE -DVK_USE_PLATFORM_SCREEN_QNX) elseif (UNIX) From abf60625e412d8537a59ed88c08628f77febfc2d Mon Sep 17 00:00:00 2001 From: Serdar Kocdemir Date: Wed, 8 Jul 2026 13:19:36 +0100 Subject: [PATCH 06/33] Merge remote-tracking branch 'goog/emu-main-dev' into main Bug: 476354031 Test: CI Change-Id: Idd4ea3f39134fbf3823ab0c2e8738b18c621640f --- host/Android.bp | 2 + host/common/address_space_operations.cpp | 8 + .../gfxstream/host/address_space_operations.h | 2 + host/features/features.cpp | 3 +- host/frame_buffer.cpp | 57 +++- host/frame_buffer.h | 2 +- host/frame_buffer_unittest.cpp | 81 ++++++ host/gl/color_buffer_gl.cpp | 2 +- host/gl/gles2_dec/gles_v2_decoder.cpp | 10 +- .../gfxstream/virtio-gpu-gfxstream-renderer.h | 15 ++ host/include/render-utils/Renderer.h | 2 +- host/render_thread.cpp | 1 + host/render_window.cpp | 2 +- host/renderer_impl.cpp | 6 +- host/renderer_impl.h | 2 +- .../tests/DefaultFramebufferBlit_unittest.cpp | 2 +- host/virtio_gpu_frontend.cpp | 5 +- host/virtio_gpu_gfxstream_renderer.cpp | 50 +++- host/vulkan/vk_common_operations.cpp | 9 +- host/vulkan/vk_decoder_global_state.cpp | 255 +++++++++++++----- host/vulkan/vk_decoder_global_state.h | 4 +- host/vulkan/vk_decoder_snapshot_utils.cpp | 77 ++++-- host/vulkan/vk_decoder_snapshot_utils.h | 8 +- third_party/rutabaga/BUILD.rutabaga.bazel | 4 +- 24 files changed, 476 insertions(+), 133 deletions(-) diff --git a/host/Android.bp b/host/Android.bp index 22ace077b..a8a569587 100644 --- a/host/Android.bp +++ b/host/Android.bp @@ -119,6 +119,7 @@ cc_defaults { "libgfxstream_host_tracing", "libgfxstream_host_gles2_dec", "libgfxstream_host_glsnapshot", + "libgfxstream_host_address_space", "libgfxstream_host_vulkan_cereal", ], shared_libs: [ @@ -201,6 +202,7 @@ cc_test_host { "libgfxstream_host_snapshot", "libgfxstream_host_test_support", "libgfxstream_host_vulkan_server", + "libgfxstream_host_address_space", "libgfxstream_oswindow_test_support", "libgmock", ], diff --git a/host/common/address_space_operations.cpp b/host/common/address_space_operations.cpp index 010a4f3b6..496420e79 100644 --- a/host/common/address_space_operations.cpp +++ b/host/common/address_space_operations.cpp @@ -33,5 +33,13 @@ const address_space_device_control_ops &get_gfxstream_address_space_ops() { return gAddressSpaceOps; } +uint32_t get_gfxstream_guest_page_size() { + if (const auto* hwFuncs = gAddressSpaceOps.control_get_hw_funcs()) { + return hwFuncs->getGuestPageSize(); + } + // Fallback to default + return 4096; +} + } // namespace host } // namespace gfxstream \ No newline at end of file diff --git a/host/common/include/gfxstream/host/address_space_operations.h b/host/common/include/gfxstream/host/address_space_operations.h index fb5aac36b..aa49eeec0 100644 --- a/host/common/include/gfxstream/host/address_space_operations.h +++ b/host/common/include/gfxstream/host/address_space_operations.h @@ -22,5 +22,7 @@ namespace host { void set_gfxstream_address_space_ops(const address_space_device_control_ops& ops); const address_space_device_control_ops& get_gfxstream_address_space_ops(); +uint32_t get_gfxstream_guest_page_size(); + } // namespace host } // namespace gfxstream diff --git a/host/features/features.cpp b/host/features/features.cpp index 8da90e877..2b598c4f6 100644 --- a/host/features/features.cpp +++ b/host/features/features.cpp @@ -151,7 +151,8 @@ bool VulkanVersionFeatureInfo::parseValue(std::string_view strValue) { pos = (ptr - strValue.data()) + 1; // Skip the dot } - value = VK_MAKE_API_VERSION(0, parts[0], parts[1], parts[2]); + uint32_t val = VK_MAKE_API_VERSION(0, parts[0], parts[1], parts[2]); + value = U32FeatureValue(val); return true; } diff --git a/host/frame_buffer.cpp b/host/frame_buffer.cpp index 2585ee199..579679079 100644 --- a/host/frame_buffer.cpp +++ b/host/frame_buffer.cpp @@ -490,7 +490,7 @@ class FrameBuffer::Impl : public gfxstream::base::EventNotificationSupport kMaxScreenshotDim || + *height <= 0 || *height > kMaxScreenshotDim) { + *cPixels = 0; + return -1; + } + + const uint64_t needed64 = + useSnipping ? (uint64_t)nChannels * rect.size.w * rect.size.h + : (uint64_t)nChannels * (*width) * (*height); - if (*cPixels < (size_t)needed) { - *cPixels = needed; + if (needed64 > SIZE_MAX || *cPixels < (size_t)needed64) { + *cPixels = needed64; return Renderer::GET_SCREENSHOT_RESULT_PIXELS_SIZE; } - *cPixels = needed; + *cPixels = needed64; if (desiredRotation == GFXSTREAM_ROTATION_90 || desiredRotation == GFXSTREAM_ROTATION_270) { std::swap(*width, *height); std::swap(screenWidth, screenHeight); @@ -3230,7 +3242,7 @@ AsyncResult FrameBuffer::Impl::composeWithCallback(uint32_t bufferSize, void* bu } } -void FrameBuffer::Impl::onSave(Stream* stream, const ITextureSaverPtr& textureSaver) { +bool FrameBuffer::Impl::onSave(Stream* stream, const ITextureSaverPtr& textureSaver) { // Things we do not need to snapshot: // m_eglSurface // m_eglContext @@ -3278,6 +3290,21 @@ void FrameBuffer::Impl::onSave(Stream* stream, const ITextureSaverPtr& textureSa s->putBe32(pair.second.dpiY); }); + // Save display ids created through createDisplay + std::vector displayIds; + int32_t currentId = -1; + uint32_t nextId; + while (get_gfxstream_multi_display_operations().get_next_display_info( + currentId, &nextId, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr)) { + displayIds.push_back(nextId); + currentId = nextId; + } + + stream->putBe32(displayIds.size()); + for (uint32_t id : displayIds) { + stream->putBe32(id); + } + stream->putBe32(m_useSubWindow); stream->putBe32(/*Obsolete m_eglContextInitialized =*/1); @@ -3342,7 +3369,10 @@ void FrameBuffer::Impl::onSave(Stream* stream, const ITextureSaverPtr& textureSa // Save Vulkan state if (m_features.VulkanSnapshots.enabled() && vk::VkDecoderGlobalState::get()) { - vk::VkDecoderGlobalState::get()->save(stream); + bool res = vk::VkDecoderGlobalState::get()->save(stream); + if (!res) { + return false; + } } #if GFXSTREAM_ENABLE_HOST_GLES @@ -3361,6 +3391,7 @@ void FrameBuffer::Impl::onSave(Stream* stream, const ITextureSaverPtr& textureSa EmulatedEglFenceSync::onSave(stream); } #endif + return true; } bool FrameBuffer::Impl::onLoad(Stream* stream, const ITextureLoaderPtr& textureLoader) { @@ -3499,6 +3530,12 @@ bool FrameBuffer::Impl::onLoad(Stream* stream, const ITextureLoaderPtr& textureL return {idx, {w, h, dpiX, dpiY}}; }); + uint32_t numDisplays = stream->getBe32(); + for (uint32_t i = 0; i < numDisplays; ++i) { + uint32_t displayId = stream->getBe32(); + get_gfxstream_multi_display_operations().create_display(&displayId); + } + // TODO: resize the window // m_useSubWindow = stream->getBe32(); @@ -5262,8 +5299,8 @@ AsyncResult FrameBuffer::composeWithCallback(uint32_t bufferSize, void* buffer, return mImpl->composeWithCallback(bufferSize, buffer, callback); } -void FrameBuffer::onSave(gfxstream::Stream* stream, const ITextureSaverPtr& textureSaver) { - mImpl->onSave(stream, textureSaver); +bool FrameBuffer::onSave(gfxstream::Stream* stream, const ITextureSaverPtr& textureSaver) { + return mImpl->onSave(stream, textureSaver); } bool FrameBuffer::onLoad(gfxstream::Stream* stream, const ITextureLoaderPtr& textureLoader) { diff --git a/host/frame_buffer.h b/host/frame_buffer.h index 865f31424..71e8bc7de 100644 --- a/host/frame_buffer.h +++ b/host/frame_buffer.h @@ -312,7 +312,7 @@ class FrameBuffer : public gfxstream::base::EventNotificationSupport #include +#include +#include +#include +#include "render_channel_impl.h" #include "render_thread_info.h" #include "gfxstream/common/testing/graphics_test_environment.h" @@ -891,6 +895,83 @@ TEST_F(FrameBufferTest, ComposeMultiDisplay) { mFb->destroyEmulatedEglWindowSurface(surface); } +class RenderThreadDeadlockTest : public ::testing::Test { + protected: + static void SetUpTestSuite() { + ASSERT_THAT(gfxstream::testing::SetupGraphicsTestEnvironment(), ::testing::IsTrue()) + << "Failed to configure graphics test environment!"; + } + + void SetUp() override { + const EGLDispatch* egl = LazyLoadedEGLDispatch::get(); + ASSERT_NE(nullptr, egl); + ASSERT_NE(nullptr, LazyLoadedGLESv2Dispatch::get()); + + bool useHostGpu = shouldUseHostGpu(); + + FeatureSet features = {}; + features.EglOnEgl.setEnabled(!useHostGpu); + features.Vulkan.setEnabled(true); + features.VulkanQueueSubmitWithCommands.setEnabled(true); + + gfxstream::base::setEnvironmentVariable("ANDROID_EMU_HEADLESS", "1"); + EXPECT_TRUE(FrameBuffer::initialize(256, 256, features, false)); + } + + void TearDown() override { + FrameBuffer::finalize(); + } +}; + +TEST_F(RenderThreadDeadlockTest, ReproDeadlockOnTeardown) { + auto fb = FrameBuffer::getFB(); + ASSERT_NE(nullptr, fb); + if (!fb->hasEmulationVk()) { + GTEST_SKIP() << "Vulkan emulation not supported on this host."; + } + + const uint32_t contextId = 12345; + fb->createGraphicsProcessResources(contextId); + + auto channel = std::make_unique(nullptr, contextId); + ASSERT_NE(nullptr, channel->renderThread()); + + RenderChannel::Buffer buffer; + uint32_t flags = 0; + uint32_t opcode = 200000000; // OP_vkCreateInstance + uint32_t packetLen = 12; + uint32_t seqno = 2; + + buffer.resize(16); + std::memcpy(buffer.data(), &flags, sizeof(flags)); + std::memcpy(buffer.data() + 4, &opcode, sizeof(opcode)); + std::memcpy(buffer.data() + 8, &packetLen, sizeof(packetLen)); + std::memcpy(buffer.data() + 12, &seqno, sizeof(seqno)); + + channel->tryWrite(std::move(buffer)); + + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + + std::promise teardownPromise; + std::future teardownFuture = teardownPromise.get_future(); + + std::thread teardownThread([&]() { + channel->stop(); + channel.reset(); + teardownPromise.set_value(); + }); + + std::future_status status = teardownFuture.wait_for(std::chrono::seconds(3)); + if (status == std::future_status::timeout) { + teardownThread.detach(); + ADD_FAILURE() << "Deadlock detected! Channel teardown timed out after 3 seconds."; + } else { + teardownThread.join(); + } + + fb->removeGraphicsProcessResources(contextId); +} + } // namespace } // namespace host } // namespace gfxstream diff --git a/host/gl/color_buffer_gl.cpp b/host/gl/color_buffer_gl.cpp index 5577fbdf2..f56fbd7e8 100644 --- a/host/gl/color_buffer_gl.cpp +++ b/host/gl/color_buffer_gl.cpp @@ -638,7 +638,7 @@ bool ColorBufferGl::readPixelsScaled(int width, int height, int rotation, const std::vector tmpPixels; void* readPixelsDst = pixels; if (needConvert4To3Channel) { - tmpPixels.resize(width * height * 4); + tmpPixels.resize((uint64_t)width * (uint64_t)height * 4); pixelDataComponents = GL_RGBA; readPixelsDst = tmpPixels.data(); } diff --git a/host/gl/gles2_dec/gles_v2_decoder.cpp b/host/gl/gles2_dec/gles_v2_decoder.cpp index 4f43038dc..fe2bacb72 100644 --- a/host/gl/gles2_dec/gles_v2_decoder.cpp +++ b/host/gl/gles2_dec/gles_v2_decoder.cpp @@ -27,6 +27,7 @@ #include #include +#include "gfxstream/host/address_space_operations.h" #include "gfxstream/host/dma_device.h" #include "gfxstream/host/vm_operations.h" #include "gfxstream/synchronization/Lock.h" @@ -452,15 +453,14 @@ void GLESv2Decoder::s_glUnmapBufferDMA(void* self, GLenum target, GLintptr offse static std::pair align_pointer_size(void* ptr, GLsizeiptr length) { - constexpr size_t kPageBits = 12; - constexpr size_t kPageSize = 1u << kPageBits; - constexpr size_t kPageOffsetMask = kPageSize - 1; + const size_t page_size = gfxstream::host::get_gfxstream_guest_page_size(); + const size_t page_offset_mask = page_size - 1; uintptr_t addr = reinterpret_cast(ptr); - uintptr_t page_offset = addr & kPageOffsetMask; + uintptr_t page_offset = addr & page_offset_mask; return { reinterpret_cast(addr - page_offset), - ((length + page_offset + kPageSize - 1) >> kPageBits) << kPageBits + (GLsizeiptr)((length + page_offset + page_size - 1) & ~page_offset_mask) }; } diff --git a/host/include/gfxstream/virtio-gpu-gfxstream-renderer.h b/host/include/gfxstream/virtio-gpu-gfxstream-renderer.h index afb20f532..83580c411 100644 --- a/host/include/gfxstream/virtio-gpu-gfxstream-renderer.h +++ b/host/include/gfxstream/virtio-gpu-gfxstream-renderer.h @@ -118,6 +118,20 @@ typedef void (*stream_renderer_fence_callback)(void* user_data, typedef void (*stream_renderer_debug_callback)(void* user_data, struct stream_renderer_debug* debug); +/** + * Extended debug data with location information. + */ +struct stream_renderer_debug_ex { + uint32_t debug_type; /**< The type of the debug message. */ + const char* file; /**< The source file where the log was generated. */ + int line; /**< The line number in the source file. */ + const char* function; /**< The function name where the log was generated. */ + const char* message; /**< The actual log message. */ +}; + +typedef void (*stream_renderer_debug_callback_ex)(void* user_data, + struct stream_renderer_debug_ex* debug); + // Parameters - data passed to initialize the renderer, with the goal of avoiding FFI breakages. // To change the data a parameter is passing safely, you should create a new parameter and // deprecate the old one. The old parameter may be removed after sufficient time. @@ -139,6 +153,7 @@ typedef void (*stream_renderer_debug_callback)(void* user_data, #define STREAM_RENDERER_PARAM_WIN0_WIDTH 4 #define STREAM_RENDERER_PARAM_WIN0_HEIGHT 5 #define STREAM_RENDERER_PARAM_DEBUG_CALLBACK 6 +#define STREAM_RENDERER_PARAM_DEBUG_CALLBACK_EX 7 // An entry in the stream renderer parameters list. // The key should be one of STREAM_RENDERER_PARAM_* diff --git a/host/include/render-utils/Renderer.h b/host/include/render-utils/Renderer.h index f38e840c5..0a1cf4bf6 100644 --- a/host/include/render-utils/Renderer.h +++ b/host/include/render-utils/Renderer.h @@ -297,7 +297,7 @@ class Renderer { // Resumes all channels after snapshot saving or loading. virtual void resumeAll() = 0; - virtual void save( + virtual bool save( Stream* stream, const ITextureSaverPtr& textureSaver) = 0; virtual bool load( diff --git a/host/render_thread.cpp b/host/render_thread.cpp index 055a2a872..ce31969bf 100644 --- a/host/render_thread.cpp +++ b/host/render_thread.cpp @@ -224,6 +224,7 @@ bool RenderThread::saveSnapshot(const SnapshotObjects& objects) { } void RenderThread::waitForFinished() { + mDecodersShouldStop.store(true, std::memory_order_relaxed); AutoLock lock(mLock); while (!mFinished.load(std::memory_order_relaxed)) { mFinishedSignal.wait(&lock); diff --git a/host/render_window.cpp b/host/render_window.cpp index c06fd847a..173f09d6d 100644 --- a/host/render_window.cpp +++ b/host/render_window.cpp @@ -554,7 +554,7 @@ bool RenderWindow::setupSubWindow(FBNativeWindowType window, bool RenderWindow::removeSubWindow() { D("Entering mHasSubWindow=%s", mHasSubWindow ? "true" : "false"); if (!mHasSubWindow) { - return false; + return true; } mHasSubWindow = false; if (!useThread()) { diff --git a/host/renderer_impl.cpp b/host/renderer_impl.cpp index 3b9d457e9..7c7322705 100644 --- a/host/renderer_impl.cpp +++ b/host/renderer_impl.cpp @@ -370,15 +370,15 @@ void RendererImpl::resumeAll() { repaintOpenGLDisplay(); } -void RendererImpl::save(gfxstream::Stream* stream, +bool RendererImpl::save(gfxstream::Stream* stream, const ITextureSaverPtr& textureSaver) { stream->putByte(mStopped); if (mStopped) { - return; + return true; } auto fb = FrameBuffer::getFB(); assert(fb); - fb->onSave(stream, textureSaver); + return fb->onSave(stream, textureSaver); } bool RendererImpl::load(gfxstream::Stream* stream, diff --git a/host/renderer_impl.h b/host/renderer_impl.h index 9944ac98f..c41a18113 100644 --- a/host/renderer_impl.h +++ b/host/renderer_impl.h @@ -106,7 +106,7 @@ class RendererImpl final : public Renderer { void pauseAllPreSave() final; void resumeAll() final; - void save(gfxstream::Stream* stream, + bool save(gfxstream::Stream* stream, const ITextureSaverPtr& textureSaver) final; bool load(gfxstream::Stream* stream, const ITextureLoaderPtr& textureLoader) final; diff --git a/host/tests/DefaultFramebufferBlit_unittest.cpp b/host/tests/DefaultFramebufferBlit_unittest.cpp index d9c1e5345..b351cbe30 100644 --- a/host/tests/DefaultFramebufferBlit_unittest.cpp +++ b/host/tests/DefaultFramebufferBlit_unittest.cpp @@ -160,7 +160,7 @@ class ClearColor final : public SampleApplication { mFb->readColorBuffer( mColorBuffer, 0, 0, mWidth, mHeight, - GfxstreamFormat::R8G8B8A8_UNORM, forRead.data()); + GfxstreamFormat::R8G8B8A8_UNORM, forRead.data(), forRead.size()); EXPECT_TRUE( ImageMatches(mWidth, mHeight, 4, mWidth, targetBuffer.data(), forRead.data())); diff --git a/host/virtio_gpu_frontend.cpp b/host/virtio_gpu_frontend.cpp index 622406467..0fbf39c58 100644 --- a/host/virtio_gpu_frontend.cpp +++ b/host/virtio_gpu_frontend.cpp @@ -1067,7 +1067,10 @@ int VirtioGpuFrontend::snapshotRenderer(const char* directory) { GFXSTREAM_ERROR("Failed to snapshot renderer: renderer not available."); return -EINVAL; } - mRenderer->save(&stream, nullptr); + if (!mRenderer->save(&stream, nullptr)) { + GFXSTREAM_ERROR("Failed to snapshot renderer: mRenderer->save failed."); + return -EINVAL; + } return 0; } diff --git a/host/virtio_gpu_gfxstream_renderer.cpp b/host/virtio_gpu_gfxstream_renderer.cpp index a8a1768d1..250f106d6 100644 --- a/host/virtio_gpu_gfxstream_renderer.cpp +++ b/host/virtio_gpu_gfxstream_renderer.cpp @@ -596,6 +596,7 @@ VG_EXPORT int stream_renderer_init(struct stream_renderer_param* stream_renderer {STREAM_RENDERER_PARAM_WIN0_WIDTH, "WIN0_WIDTH"}, {STREAM_RENDERER_PARAM_WIN0_HEIGHT, "WIN0_HEIGHT"}, {STREAM_RENDERER_PARAM_DEBUG_CALLBACK, "DEBUG_CALLBACK"}, + {STREAM_RENDERER_PARAM_DEBUG_CALLBACK_EX, "DEBUG_CALLBACK_EX"}, {STREAM_RENDERER_SKIP_OPENGLES_INIT, "SKIP_OPENGLES_INIT"}, }; @@ -626,6 +627,7 @@ VG_EXPORT int stream_renderer_init(struct stream_renderer_param* stream_renderer std::string renderer_features_str; stream_renderer_fence_callback fence_callback = nullptr; stream_renderer_debug_callback log_callback = nullptr; + stream_renderer_debug_callback_ex log_callback_ex = nullptr; bool rendererInitializedExternally = false; // Iterate all parameters that we support. @@ -676,6 +678,12 @@ VG_EXPORT int stream_renderer_init(struct stream_renderer_param* stream_renderer static_cast(param.value)); break; } + case STREAM_RENDERER_PARAM_DEBUG_CALLBACK_EX: { + GFXSTREAM_DEBUG("STREAM_RENDERER_PARAM_DEBUG_CALLBACK_EX passed"); + log_callback_ex = reinterpret_cast( + static_cast(param.value)); + break; + } case STREAM_RENDERER_SKIP_OPENGLES_INIT: { // AEMU currently does its own initialization in // qemu/android/android-emu/android/opengles.cpp. @@ -697,7 +705,47 @@ VG_EXPORT int stream_renderer_init(struct stream_renderer_param* stream_renderer } } - if (log_callback) { + if (log_callback_ex) { + gfxstream::host::SetGfxstreamLogCallback([log_callback_ex, log_user_data = renderer_cookie]( + LogLevel level, const char* file, int line, + const char* function, const char* message) { + stream_renderer_debug_ex log_info = { + .file = file, + .line = line, + .function = function, + .message = message, + }; + + switch (level) { + case LogLevel::kFatal: { + log_info.debug_type = STREAM_RENDERER_DEBUG_ERROR; + break; + } + case LogLevel::kError: { + log_info.debug_type = STREAM_RENDERER_DEBUG_ERROR; + break; + } + case LogLevel::kWarning: { + log_info.debug_type = STREAM_RENDERER_DEBUG_WARN; + break; + } + case LogLevel::kInfo: { + log_info.debug_type = STREAM_RENDERER_DEBUG_INFO; + break; + } + case LogLevel::kDebug: { + log_info.debug_type = STREAM_RENDERER_DEBUG_DEBUG; + break; + } + case LogLevel::kVerbose: { + log_info.debug_type = STREAM_RENDERER_DEBUG_DEBUG; + break; + } + } + + log_callback_ex(log_user_data, &log_info); + }); + } else if (log_callback) { gfxstream::host::SetGfxstreamLogCallback([log_callback, log_user_data = renderer_cookie]( LogLevel level, const char* file, int line, const char* function, const char* message) { diff --git a/host/vulkan/vk_common_operations.cpp b/host/vulkan/vk_common_operations.cpp index a88948fce..d33d3acbf 100644 --- a/host/vulkan/vk_common_operations.cpp +++ b/host/vulkan/vk_common_operations.cpp @@ -3029,11 +3029,12 @@ bool VkEmulation::createVkColorBufferLocked(uint32_t width, uint32_t height, // Requesting invalid texture sizes can crash some drivers, early out to gracefully handle // the errors and avoid total emulator crash. - if (width > mDeviceInfo.physdevProps.limits.maxFramebufferWidth || + if (width == 0 || width > mDeviceInfo.physdevProps.limits.maxFramebufferWidth || height == 0 || height > mDeviceInfo.physdevProps.limits.maxFramebufferHeight) { GFXSTREAM_ERROR( - "%s: Cannot create color buffer(%u) with size '%u x %u', driver limits: '%u x %u'", - __func__, colorBufferHandle, width, height, + "%s: Cannot create color buffer(%u) with size '%u x %u' and format '%s', driver " + "limits: '%u x %u'", + __func__, colorBufferHandle, width, height, ToString(format).c_str(), mDeviceInfo.physdevProps.limits.maxFramebufferWidth, mDeviceInfo.physdevProps.limits.maxFramebufferHeight); return false; @@ -3784,7 +3785,7 @@ bool VkEmulation::readColorBufferPixelsScaledGpu(uint32_t colorBufferHandle, int // Check if we need to stage to GPU const int outBpp = (pixelsFormat == GfxstreamFormat::R8G8B8_UNORM) ? 3 : 4; - const uint64_t outPixelsSize = outBpp * pixelsWidth * pixelsHeight; + const uint64_t outPixelsSize = (uint64_t)outBpp * (uint64_t)pixelsWidth * (uint64_t)pixelsHeight; const int readbackBpp = 4; int readbackWidth = sourceCbInfo->width; int readbackHeight = sourceCbInfo->height; diff --git a/host/vulkan/vk_decoder_global_state.cpp b/host/vulkan/vk_decoder_global_state.cpp index 788cee220..ad7f23cdf 100644 --- a/host/vulkan/vk_decoder_global_state.cpp +++ b/host/vulkan/vk_decoder_global_state.cpp @@ -446,7 +446,7 @@ class VkDecoderGlobalState::Impl { stateBlock->deviceDispatch->vkDestroyCommandPool(stateBlock->device, stateBlock->commandPool, nullptr); } - void save(gfxstream::Stream* stream) { + bool save(gfxstream::Stream* stream) { GFXSTREAM_DEBUG("VulkanSnapshots save (begin)"); std::lock_guard lock(mMutex); @@ -534,7 +534,10 @@ class VkDecoderGlobalState::Impl { StateBlock stateBlock = createSnapshotStateBlock(imageInfo.device); // TODO(b/294277842): make sure the queue is empty before using. - saveImageContent(stream, &stateBlock, unboxedImage, &imageInfo); + if (!saveImageContent(stream, &stateBlock, unboxedImage, &imageInfo)) { + releaseSnapshotStateBlock(&stateBlock); + return false; + } releaseSnapshotStateBlock(&stateBlock); } @@ -560,7 +563,10 @@ class VkDecoderGlobalState::Impl { StateBlock stateBlock = createSnapshotStateBlock(bufferInfo.device); // TODO(b/294277842): make sure the queue is empty before using. - saveBufferContent(stream, &stateBlock, unboxedBuffer, &bufferInfo); + if (!saveBufferContent(stream, &stateBlock, unboxedBuffer, &bufferInfo)) { + releaseSnapshotStateBlock(&stateBlock); + return false; + } releaseSnapshotStateBlock(&stateBlock); } @@ -705,12 +711,16 @@ class VkDecoderGlobalState::Impl { unboxed_to_boxed_non_dispatchable_VkBufferView(entry.bufferView); stream->write(&bufferView, sizeof(bufferView)); } break; - case DescriptorSetInfo::DescriptorWriteType::InlineUniformBlock: + case DescriptorSetInfo::DescriptorWriteType::InlineUniformBlock: { + uint32_t dataSize = entry.inlineUniformBlockBuffer.size(); + stream->putBe32(dataSize); + stream->write(entry.inlineUniformBlockBuffer.data(), dataSize); + } break; case DescriptorSetInfo::DescriptorWriteType::AccelerationStructure: - // TODO - GFXSTREAM_FATAL("Encountered pending inline uniform block or acceleration " - "structure desc write, abort (NYI)"); - break; + GFXSTREAM_ERROR( + "Encountered pending acceleration " + "structure desc write, abort (NYI)"); + return false; default: break; } @@ -743,9 +753,10 @@ class VkDecoderGlobalState::Impl { mSnapshotState = SnapshotState::Normal; GFXSTREAM_DEBUG("VulkanSnapshots save (end)"); + return true; } - void load(gfxstream::Stream* stream, GfxApiLogger& gfxLogger) { + bool load(gfxstream::Stream* stream, GfxApiLogger& gfxLogger) { // assume that we already destroyed all instances // from FrameBuffer's onLoad method. GFXSTREAM_DEBUG("VulkanSnapshots load (begin)"); @@ -804,8 +815,13 @@ class VkDecoderGlobalState::Impl { .processName = nullptr, .gfxApiLogger = &gfxLogger, }; - decoderForLoading.decode(decoderReplayBuffer.data(), decoderReplayBuffer.size(), - &trivialStream, resources.get(), context); + size_t consumed = decoderForLoading.decode(decoderReplayBuffer.data(), decoderReplayBuffer.size(), + &trivialStream, resources.get(), context); + if (consumed != decoderReplayBuffer.size()) { + GFXSTREAM_ERROR("Failed to completely decode snapshot replay buffer. Consumed %zu of %zu bytes", + consumed, decoderReplayBuffer.size()); + return false; + } } { @@ -819,11 +835,13 @@ class VkDecoderGlobalState::Impl { VkDeviceMemory unboxedMemory = unbox_VkDeviceMemory(boxedMemory); auto it = mMemoryInfo.find(unboxedMemory); if (it == mMemoryInfo.end()) { - GFXSTREAM_FATAL("Snapshot load failure: cannot find memory handle for VkDeviceMemory:%p", boxedMemory); + GFXSTREAM_ERROR("Snapshot load failure: cannot find memory handle for VkDeviceMemory:%p", boxedMemory); + return false; } VkDeviceSize size = stream->getBe64(); if (size != it->second.size || !it->second.ptr) { - GFXSTREAM_FATAL("Snapshot load failure: memory size does not match for VkDeviceMemory:%p", boxedMemory); + GFXSTREAM_ERROR("Snapshot load failure: memory size does not match for VkDeviceMemory:%p", boxedMemory); + return false; } stream->read(it->second.ptr, size); } @@ -862,7 +880,10 @@ class VkDecoderGlobalState::Impl { imageInfo.layout = static_cast(stream->getBe32()); StateBlock stateBlock = createSnapshotStateBlock(imageInfo.device); // TODO(b/294277842): make sure the queue is empty before using. - loadImageContent(stream, &stateBlock, unboxedImage, &imageInfo); + if (!loadImageContent(stream, &stateBlock, unboxedImage, &imageInfo)) { + releaseSnapshotStateBlock(&stateBlock); + return false; + } releaseSnapshotStateBlock(&stateBlock); } @@ -883,7 +904,10 @@ class VkDecoderGlobalState::Impl { // TODO: add a special case for host mapped memory StateBlock stateBlock = createSnapshotStateBlock(bufferInfo.device); // TODO(b/294277842): make sure the queue is empty before using. - loadBufferContent(stream, &stateBlock, unboxedBuffer, &bufferInfo); + if (!loadBufferContent(stream, &stateBlock, unboxedBuffer, &bufferInfo)) { + releaseSnapshotStateBlock(&stateBlock); + return false; + } releaseSnapshotStateBlock(&stateBlock); } @@ -922,6 +946,9 @@ class VkDecoderGlobalState::Impl { std::vector> tmpImageInfos; std::vector> tmpBufferInfos; std::vector> tmpBufferViews; + std::vector> + tmpInlineUniformBlocks; + std::vector> tmpInlineUniformBlockBuffers; for (uint64_t poolId : allpoolIds) { bool allocated = stream->getByte(); @@ -978,12 +1005,38 @@ class VkDecoderGlobalState::Impl { stream->read(&bufferView, sizeof(bufferView)); bufferView = unbox_VkBufferView(bufferView); } break; - case DescriptorSetInfo::DescriptorWriteType::InlineUniformBlock: + case DescriptorSetInfo::DescriptorWriteType::InlineUniformBlock: { + uint32_t dataSize = stream->getBe32(); + tmpInlineUniformBlockBuffers.push_back( + std::vector(dataSize)); + stream->read(tmpInlineUniformBlockBuffers.back().data(), dataSize); + tmpInlineUniformBlocks.push_back( + std::make_unique()); + VkWriteDescriptorSetInlineUniformBlockEXT& inlineUniformBlock = + *tmpInlineUniformBlocks.back(); + inlineUniformBlock.sType = + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT; + inlineUniformBlock.pNext = nullptr; + inlineUniformBlock.dataSize = dataSize; + inlineUniformBlock.pData = + tmpInlineUniformBlockBuffers.back().data(); + writeDescriptorSet.pNext = &inlineUniformBlock; + // Note: following is redundant, as arrayElement is guarantee to be + // 0 due to the way descriptor is handled in snapshot. it just + // serves to clarify that we are updating the whole buffer, to + // account the possibility of accumulative updating + writeDescriptorSet.dstArrayElement = 0; + // Note: following is important to indicate we are updating + // the whole buffer, as it could accumulate multiple update before + // snapshot is taken + writeDescriptorSet.descriptorCount = dataSize; + } break; case DescriptorSetInfo::DescriptorWriteType::AccelerationStructure: // TODO - GFXSTREAM_FATAL("Encountered pending inline uniform block or acceleration " - "structure desc write, abort (NYI)"); - break; + GFXSTREAM_ERROR( + "Encountered pending acceleration " + "structure desc write, abort (NYI)"); + return false; default: break; } @@ -1015,7 +1068,8 @@ class VkDecoderGlobalState::Impl { VkFence unboxedFence = unbox_VkFence(boxedFence); auto it = mFenceInfo.find(unboxedFence); if (it == mFenceInfo.end()) { - GFXSTREAM_FATAL("Snapshot load failure: unrecognized VkFence"); + GFXSTREAM_ERROR("Snapshot load failure: unrecognized VkFence"); + return false; } const auto& device = it->second.device; const auto& deviceInfo = gfxstream::base::find(mDeviceInfo, device); @@ -1038,6 +1092,7 @@ class VkDecoderGlobalState::Impl { mSnapshotState = SnapshotState::Normal; } GFXSTREAM_DEBUG("VulkanSnapshots load (end)"); + return true; } std::optional getContextIdForDeviceLocked(VkDevice device) REQUIRES(mMutex) { @@ -1937,10 +1992,6 @@ class VkDecoderGlobalState::Impl { shouldPassthrough = shouldPassthrough && !(m_vkEmulation->getExternalMemoryMode() == ExternalMemory::Mode::Metal); #endif - if (shouldPassthrough) { - return vk->vkEnumerateDeviceExtensionProperties(physicalDevice, pLayerName, - pPropertyCount, pProperties); - } #if defined(_WIN32) // Temporary fix to get old system images working with lavapipe @@ -1952,6 +2003,11 @@ class VkDecoderGlobalState::Impl { } #endif + if (shouldPassthrough) { + return vk->vkEnumerateDeviceExtensionProperties(physicalDevice, pLayerName, + pPropertyCount, pProperties); + } + // If MoltenVK is supported on host, we need to ensure that we include // VK_MVK_moltenvk extenstion in returned properties. std::vector properties; @@ -3159,6 +3215,11 @@ class VkDecoderGlobalState::Impl { auto original_underlying_image = bimi->image; auto original_boxed_image = unboxed_to_boxed_non_dispatchable_VkImage(original_underlying_image); + if (!original_boxed_image) { + GFXSTREAM_ERROR("Original boxed image not found for deferred AHB bind."); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + VkImageCreateInfo ici = {}; { std::lock_guard lock(mMutex); @@ -4623,31 +4684,17 @@ class VkDecoderGlobalState::Impl { static DescriptorSetInfo::DescriptorWrite* GetDescriptorSetElementEntryWrapping( std::vector>& descriptorSetTable, uint32_t& bindingIndex, uint32_t& arrayElementIndex) { - if (bindingIndex >= descriptorSetTable.size()) { - return nullptr; - } - - std::vector& bindingTable = - descriptorSetTable[bindingIndex]; - if (arrayElementIndex < bindingTable.size()) { - return &bindingTable[arrayElementIndex]; - } - - // Descriptor writes wrap to the next binding. See - // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkWriteDescriptorSet.html - ++bindingIndex; - arrayElementIndex = 0; - - if (bindingIndex >= descriptorSetTable.size()) { - return nullptr; - } - - std::vector& nextBindingTable = - descriptorSetTable[bindingIndex]; - if (arrayElementIndex < nextBindingTable.size()) { - return &nextBindingTable[arrayElementIndex]; + while (bindingIndex < descriptorSetTable.size()) { + std::vector& bindingTable = + descriptorSetTable[bindingIndex]; + if (arrayElementIndex < bindingTable.size()) { + return &bindingTable[arrayElementIndex]; + } + // Descriptor writes wrap to the next binding. See + // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkWriteDescriptorSet.html + ++bindingIndex; + arrayElementIndex = 0; } - return nullptr; } @@ -4752,10 +4799,13 @@ class VkDecoderGlobalState::Impl { if (entry == nullptr) break; entry->inlineUniformBlock = *descInlineUniformBlock; - entry->inlineUniformBlockBuffer.assign( - static_cast(descInlineUniformBlock->pData), - static_cast(descInlineUniformBlock->pData) + - descInlineUniformBlock->dataSize); + if (entry->inlineUniformBlockBuffer.size() < + dstArrayElement + descInlineUniformBlock->dataSize) { + entry->inlineUniformBlockBuffer.resize(dstArrayElement + + descInlineUniformBlock->dataSize); + } + memcpy(entry->inlineUniformBlockBuffer.data() + dstArrayElement, + descInlineUniformBlock->pData, descInlineUniformBlock->dataSize); entry->writeType = DescriptorSetInfo::DescriptorWriteType::InlineUniformBlock; entry->descriptorType = descType; entry->dstArrayElement = dstArrayElement; @@ -4770,11 +4820,80 @@ class VkDecoderGlobalState::Impl { } } } - // TODO: bookkeep pDescriptorCopies - // Our primary use case vkQueueCommitDescriptorSetUpdatesGOOGLE does not use - // pDescriptorCopies. Thus skip its implementation for now. - if (descriptorCopyCount && snapshotsEnabled()) { - GFXSTREAM_ERROR("%s: Snapshot does not support descriptor copy yet\n"); + for (uint32_t copyIdx = 0; copyIdx < descriptorCopyCount; copyIdx++) { + const VkCopyDescriptorSet& descriptorCopy = pDescriptorCopies[copyIdx]; + auto srcIte = mDescriptorSetInfo.find(descriptorCopy.srcSet); + if (srcIte == mDescriptorSetInfo.end()) { + continue; + } + auto dstIte = mDescriptorSetInfo.find(descriptorCopy.dstSet); + if (dstIte == mDescriptorSetInfo.end()) { + continue; + } + + DescriptorSetInfo& srcDescriptorSetInfo = srcIte->second; + DescriptorSetInfo& dstDescriptorSetInfo = dstIte->second; + + auto& srcTable = srcDescriptorSetInfo.allWrites; + auto& dstTable = dstDescriptorSetInfo.allWrites; + + uint32_t srcBinding = descriptorCopy.srcBinding; + uint32_t srcArrayElement = descriptorCopy.srcArrayElement; + uint32_t dstBinding = descriptorCopy.dstBinding; + uint32_t dstArrayElement = descriptorCopy.dstArrayElement; + uint32_t descriptorCount = descriptorCopy.descriptorCount; + + uint32_t srcBindingCheck = srcBinding; + uint32_t srcArrayElementCheck = srcArrayElement; + auto* srcCheckEntry = GetDescriptorSetElementEntryWrapping(srcTable, srcBindingCheck, + srcArrayElementCheck); + + uint32_t dstBindingCheck = dstBinding; + uint32_t dstArrayElementCheck = dstArrayElement; + auto* dstCheckEntry = GetDescriptorSetElementEntryWrapping(dstTable, dstBindingCheck, + dstArrayElementCheck); + + if (srcCheckEntry && dstCheckEntry && + isDescriptorTypeInlineUniformBlock(srcCheckEntry->descriptorType)) { + uint32_t zero1 = 0; + uint32_t zero2 = 0; + auto* srcEntry = + GetDescriptorSetElementEntryWrapping(srcTable, srcBindingCheck, zero1); + auto* dstEntry = + GetDescriptorSetElementEntryWrapping(dstTable, dstBindingCheck, zero2); + + if (srcEntry && dstEntry) { + if (dstEntry->inlineUniformBlockBuffer.size() < + dstArrayElementCheck + descriptorCount) { + dstEntry->inlineUniformBlockBuffer.resize(dstArrayElementCheck + + descriptorCount); + } + if (srcEntry->inlineUniformBlockBuffer.size() > srcArrayElementCheck) { + uint32_t copySize = std::min( + descriptorCount, (uint32_t)srcEntry->inlineUniformBlockBuffer.size() - + srcArrayElementCheck); + memcpy(dstEntry->inlineUniformBlockBuffer.data() + dstArrayElementCheck, + srcEntry->inlineUniformBlockBuffer.data() + srcArrayElementCheck, + copySize); + } + dstEntry->writeType = + DescriptorSetInfo::DescriptorWriteType::InlineUniformBlock; + dstEntry->descriptorType = srcEntry->descriptorType; + } + continue; + } + + for (uint32_t writeElemIdx = 0; writeElemIdx < descriptorCount; + ++writeElemIdx, ++srcArrayElement, ++dstArrayElement) { + auto* srcEntry = + GetDescriptorSetElementEntryWrapping(srcTable, srcBinding, srcArrayElement); + auto* dstEntry = + GetDescriptorSetElementEntryWrapping(dstTable, dstBinding, dstArrayElement); + + if (srcEntry == nullptr || dstEntry == nullptr) break; + + *dstEntry = *srcEntry; + } } bool needEmulateWriteDescriptor = false; // c++ seems to allow for 0-size array allocation @@ -6004,15 +6123,14 @@ class VkDecoderGlobalState::Impl { info->guestPhysAddr = physAddr; - constexpr size_t kPageBits = 12; - constexpr size_t kPageSize = 1u << kPageBits; - constexpr size_t kPageOffsetMask = kPageSize - 1; + const size_t pageSize = gfxstream::host::get_gfxstream_guest_page_size(); + const size_t pageOffsetMask = pageSize - 1; uintptr_t addr = reinterpret_cast(info->ptr); - uintptr_t pageOffset = addr & kPageOffsetMask; + uintptr_t pageOffset = addr & pageOffsetMask; info->pageAlignedHva = reinterpret_cast(addr - pageOffset); - info->sizeToPage = ((info->size + pageOffset + kPageSize - 1) >> kPageBits) << kPageBits; + info->sizeToPage = (info->size + pageOffset + pageSize - 1) & ~pageOffsetMask; if (mLogging) { GFXSTREAM_VERBOSE("%s: map: %p, %p -> [0x%llx 0x%llx]", __func__, info->ptr, @@ -6587,9 +6705,10 @@ class VkDecoderGlobalState::Impl { // Determine size and alignment requirements and allocate a PrivateMemory VkDeviceSize alignmentSize = m_vkEmulation->externalMemoryHostProperties().minImportedHostPointerAlignment; - if (createBlobInfoPtr && alignmentSize < kPageSizeforBlob) { + const size_t guestPageSize = gfxstream::host::get_gfxstream_guest_page_size(); + if (createBlobInfoPtr && alignmentSize < guestPageSize) { // Align blob allocations to the page size - alignmentSize = kPageSizeforBlob; + alignmentSize = guestPageSize; } VkDeviceSize alignedSize = ALIGN(localAllocInfo.allocationSize, alignmentSize); @@ -11124,10 +11243,12 @@ const gfxstream::host::FeatureSet& VkDecoderGlobalState::getFeatures() const { r bool VkDecoderGlobalState::vkCleanupEnabled() const { return mImpl->vkCleanupEnabled(); } -void VkDecoderGlobalState::save(gfxstream::Stream* stream) { mImpl->save(stream); } +bool VkDecoderGlobalState::save(gfxstream::Stream* stream) { + return mImpl->save(stream); +} -void VkDecoderGlobalState::load(gfxstream::Stream* stream, GfxApiLogger& gfxLogger) { - mImpl->load(stream, gfxLogger); +bool VkDecoderGlobalState::load(gfxstream::Stream* stream, GfxApiLogger& gfxLogger) { + return mImpl->load(stream, gfxLogger); } PFN_vkVoidFunction VkDecoderGlobalState::on_vkGetInstanceProcAddr( diff --git a/host/vulkan/vk_decoder_global_state.h b/host/vulkan/vk_decoder_global_state.h index 8e8429fd8..204e2e51b 100644 --- a/host/vulkan/vk_decoder_global_state.h +++ b/host/vulkan/vk_decoder_global_state.h @@ -89,8 +89,8 @@ class VkDecoderGlobalState { // bug 149997534 bool vkCleanupEnabled() const; - void save(gfxstream::Stream* stream); - void load(gfxstream::Stream* stream, gfxstream::host::GfxApiLogger& gfxLogger); + bool save(gfxstream::Stream* stream); + bool load(gfxstream::Stream* stream, gfxstream::host::GfxApiLogger& gfxLogger); PFN_vkVoidFunction on_vkGetInstanceProcAddr(gfxstream::base::BumpPool* pool, VkSnapshotApiCallHandle apiCallHandle, diff --git a/host/vulkan/vk_decoder_snapshot_utils.cpp b/host/vulkan/vk_decoder_snapshot_utils.cpp index 993087125..9be1e10c4 100644 --- a/host/vulkan/vk_decoder_snapshot_utils.cpp +++ b/host/vulkan/vk_decoder_snapshot_utils.cpp @@ -54,16 +54,16 @@ constexpr uint32_t kBadImageSnapshot = 0xbaadbeef; constexpr uint32_t kGoodImageSnapshot = 0x900df00d; } // namespace -void saveImageContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkImage image, +bool saveImageContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkImage image, const ImageInfo* imageInfo) { if (imageInfo->layout == VK_IMAGE_LAYOUT_UNDEFINED) { stream->putBe32(kBadImageSnapshot); - return; + return true; } // TODO(b/333936705): snapshot multi-sample images if (imageInfo->imageCreateInfoShallow.samples != VK_SAMPLE_COUNT_1_BIT) { stream->putBe32(kBadImageSnapshot); - return; + return true; } VulkanDispatch* dispatch = stateBlock->deviceDispatch; @@ -73,7 +73,7 @@ void saveImageContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkImage if (!getFormatTransferInfo(imageCreateInfo.format, imageCreateInfo.extent, &transferInfo) || !transferInfo.stagingBufferCopySize) { stream->putBe32(kBadImageSnapshot); - return; + return true; } VkDeviceSize stagingBufferSize = transferInfo.stagingBufferCopySize; @@ -123,8 +123,11 @@ void saveImageContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkImage dispatch->vkBindBufferMemory(stateBlock->device, readbackBuffer, readbackMemory, 0)); void* mapped = nullptr; - VK_CHECK(dispatch->vkMapMemory(stateBlock->device, readbackMemory, 0, VK_WHOLE_SIZE, - VkMemoryMapFlags{}, &mapped)); + if (dispatch->vkMapMemory(stateBlock->device, readbackMemory, 0, VK_WHOLE_SIZE, + VkMemoryMapFlags{}, &mapped) != VK_SUCCESS || mapped == nullptr) { + GFXSTREAM_ERROR("Failed to map memory for image snapshot save"); + return false; + } for (uint32_t mipLevel = 0; mipLevel < imageInfo->imageCreateInfoShallow.mipLevels; mipLevel++) { @@ -135,12 +138,14 @@ void saveImageContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkImage .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, }; if (dispatch->vkBeginCommandBuffer(commandBuffer, &beginInfo) != VK_SUCCESS) { - GFXSTREAM_FATAL("Failed to start command buffer on snapshot save"); + GFXSTREAM_ERROR("Failed to start command buffer on snapshot save"); + return false; } VkExtent3D mipmapExtent = getMipmapExtent(imageCreateInfo.extent, mipLevel); if (!getFormatTransferInfo(imageCreateInfo.format, mipmapExtent, &transferInfo)) { - GFXSTREAM_FATAL("Failed to get transfer info for snapshot save"); + GFXSTREAM_ERROR("Failed to get transfer info for snapshot save"); + return false; } VkDeviceSize mipmapStagingBufferSize = transferInfo.stagingBufferCopySize; std::vector& bufferImageCopies = transferInfo.bufferImageCopies; @@ -209,13 +214,14 @@ void saveImageContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkImage dispatch->vkDestroyBuffer(stateBlock->device, readbackBuffer, nullptr); dispatch->vkFreeMemory(stateBlock->device, readbackMemory, nullptr); dispatch->vkFreeCommandBuffers(stateBlock->device, stateBlock->commandPool, 1, &commandBuffer); + return true; } -void loadImageContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkImage image, +bool loadImageContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkImage image, const ImageInfo* imageInfo) { const bool validImage = (stream->getBe32() == kGoodImageSnapshot); if (!validImage) { - return; + return true; } VulkanDispatch* dispatch = stateBlock->deviceDispatch; @@ -223,7 +229,7 @@ void loadImageContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkImage TransferInfo transferInfo; if (!getFormatTransferInfo(imageCreateInfo.format, imageCreateInfo.extent, &transferInfo)) { - return; + return true; } VkDeviceSize stagingBufferSize = transferInfo.stagingBufferCopySize; @@ -287,7 +293,7 @@ void loadImageContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkImage dispatch->vkDestroyFence(stateBlock->device, fence, nullptr); dispatch->vkFreeCommandBuffers(stateBlock->device, stateBlock->commandPool, 1, &commandBuffer); - return; + return true; } VkBufferCreateInfo bufferCreateInfo = { .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, @@ -321,8 +327,11 @@ void loadImageContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkImage dispatch->vkBindBufferMemory(stateBlock->device, stagingBuffer, stagingMemory, 0)); void* mapped = nullptr; - VK_CHECK(dispatch->vkMapMemory(stateBlock->device, stagingMemory, 0, VK_WHOLE_SIZE, - VkMemoryMapFlags{}, &mapped)); + if (dispatch->vkMapMemory(stateBlock->device, stagingMemory, 0, VK_WHOLE_SIZE, + VkMemoryMapFlags{}, &mapped) != VK_SUCCESS || mapped == nullptr) { + GFXSTREAM_ERROR("Failed to map memory for image snapshot load"); + return false; + } for (uint32_t mipLevel = 0; mipLevel < imageInfo->imageCreateInfoShallow.mipLevels; mipLevel++) { @@ -333,12 +342,14 @@ void loadImageContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkImage .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, }; if (dispatch->vkBeginCommandBuffer(commandBuffer, &beginInfo) != VK_SUCCESS) { - GFXSTREAM_FATAL("Failed to start command buffer on snapshot save"); + GFXSTREAM_ERROR("Failed to start command buffer on snapshot load"); + return false; } VkExtent3D mipmapExtent = getMipmapExtent(imageCreateInfo.extent, mipLevel); if (!getFormatTransferInfo(imageCreateInfo.format, mipmapExtent, &transferInfo)) { - GFXSTREAM_FATAL("Failed to get transfer info for snapshot load"); + GFXSTREAM_ERROR("Failed to get transfer info for snapshot load"); + return false; } // Require the serialized size to match the expected per-mip transfer size. @@ -408,14 +419,15 @@ void loadImageContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkImage dispatch->vkDestroyBuffer(stateBlock->device, stagingBuffer, nullptr); dispatch->vkFreeMemory(stateBlock->device, stagingMemory, nullptr); dispatch->vkFreeCommandBuffers(stateBlock->device, stateBlock->commandPool, 1, &commandBuffer); + return true; } -void saveBufferContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkBuffer buffer, +bool saveBufferContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkBuffer buffer, const BufferInfo* bufferInfo) { VkBufferUsageFlags requiredUsages = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; if ((bufferInfo->usage & requiredUsages) != requiredUsages) { - return; + return true; } VulkanDispatch* dispatch = stateBlock->deviceDispatch; VkCommandBufferAllocateInfo allocInfo{ @@ -463,8 +475,11 @@ void saveBufferContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkBuff dispatch->vkBindBufferMemory(stateBlock->device, readbackBuffer, readbackMemory, 0)); void* mapped = nullptr; - VK_CHECK(dispatch->vkMapMemory(stateBlock->device, readbackMemory, 0, VK_WHOLE_SIZE, - VkMemoryMapFlags{}, &mapped)); + if (dispatch->vkMapMemory(stateBlock->device, readbackMemory, 0, VK_WHOLE_SIZE, + VkMemoryMapFlags{}, &mapped) != VK_SUCCESS || mapped == nullptr) { + GFXSTREAM_ERROR("Failed to map memory for buffer snapshot save"); + return false; + } VkBufferCopy bufferCopy = { .srcOffset = 0, @@ -476,7 +491,8 @@ void saveBufferContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkBuff .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, }; if (dispatch->vkBeginCommandBuffer(commandBuffer, &beginInfo) != VK_SUCCESS) { - GFXSTREAM_FATAL("Failed to start command buffer on snapshot save"); + GFXSTREAM_ERROR("Failed to start command buffer on snapshot save"); + return false; } dispatch->vkCmdCopyBuffer(commandBuffer, buffer, readbackBuffer, 1, &bufferCopy); VkBufferMemoryBarrier barrier{.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, @@ -510,6 +526,7 @@ void saveBufferContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkBuff dispatch->vkDestroyBuffer(stateBlock->device, readbackBuffer, nullptr); dispatch->vkFreeMemory(stateBlock->device, readbackMemory, nullptr); dispatch->vkFreeCommandBuffers(stateBlock->device, stateBlock->commandPool, 1, &commandBuffer); + return true; } void setEventInQueue(StateBlock* stateBlock, VkEvent event, uint64_t eventflags) { @@ -570,12 +587,12 @@ void signalSemaphore(StateBlock* stateBlock, VkSemaphore unboxed_semaphore) { dispatch->vkDestroyFence(stateBlock->device, fence, nullptr); } -void loadBufferContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkBuffer buffer, +bool loadBufferContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkBuffer buffer, const BufferInfo* bufferInfo) { VkBufferUsageFlags requiredUsages = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; if ((bufferInfo->usage & requiredUsages) != requiredUsages) { - return; + return true; } VulkanDispatch* dispatch = stateBlock->deviceDispatch; VkCommandBufferAllocateInfo allocInfo{ @@ -623,11 +640,15 @@ void loadBufferContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkBuff dispatch->vkBindBufferMemory(stateBlock->device, stagingBuffer, stagingMemory, 0)); void* mapped = nullptr; - VK_CHECK(dispatch->vkMapMemory(stateBlock->device, stagingMemory, 0, VK_WHOLE_SIZE, - VkMemoryMapFlags{}, &mapped)); + if (dispatch->vkMapMemory(stateBlock->device, stagingMemory, 0, VK_WHOLE_SIZE, + VkMemoryMapFlags{}, &mapped) != VK_SUCCESS || mapped == nullptr) { + GFXSTREAM_ERROR("Failed to map memory for buffer snapshot load"); + return false; + } size_t bufferSize = stream->getBe64(); if (bufferSize != bufferInfo->size) { - GFXSTREAM_FATAL("Failed to read buffer on snapshot load"); + GFXSTREAM_ERROR("Failed to read buffer on snapshot load"); + return false; } stream->read(mapped, bufferInfo->size); @@ -641,7 +662,8 @@ void loadBufferContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkBuff .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, }; if (dispatch->vkBeginCommandBuffer(commandBuffer, &beginInfo) != VK_SUCCESS) { - GFXSTREAM_FATAL("Failed to start command buffer on snapshot load"); + GFXSTREAM_ERROR("Failed to start command buffer on snapshot load"); + return false; } dispatch->vkCmdCopyBuffer(commandBuffer, stagingBuffer, buffer, 1, &bufferCopy); VkBufferMemoryBarrier barrier{.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, @@ -673,6 +695,7 @@ void loadBufferContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkBuff dispatch->vkDestroyBuffer(stateBlock->device, stagingBuffer, nullptr); dispatch->vkFreeMemory(stateBlock->device, stagingMemory, nullptr); dispatch->vkFreeCommandBuffers(stateBlock->device, stateBlock->commandPool, 1, &commandBuffer); + return true; } } // namespace vk diff --git a/host/vulkan/vk_decoder_snapshot_utils.h b/host/vulkan/vk_decoder_snapshot_utils.h index 9d4f2c9b0..4f5504783 100644 --- a/host/vulkan/vk_decoder_snapshot_utils.h +++ b/host/vulkan/vk_decoder_snapshot_utils.h @@ -27,18 +27,18 @@ struct StateBlock { VkQueue queue; VkCommandPool commandPool; }; -void saveImageContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkImage image, +bool saveImageContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkImage image, const ImageInfo* imageInfo); -void loadImageContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkImage image, +bool loadImageContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkImage image, const ImageInfo* imageInfo); -void saveBufferContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkBuffer buffer, +bool saveBufferContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkBuffer buffer, const BufferInfo* bufferInfo); void setEventInQueue(StateBlock* stateBlock, VkEvent event, uint64_t eventflags); void signalSemaphore(StateBlock* stateBlock, VkSemaphore unboxed_semaphore); -void loadBufferContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkBuffer buffer, +bool loadBufferContent(gfxstream::Stream* stream, StateBlock* stateBlock, VkBuffer buffer, const BufferInfo* bufferInfo); } // namespace vk } // namespace host diff --git a/third_party/rutabaga/BUILD.rutabaga.bazel b/third_party/rutabaga/BUILD.rutabaga.bazel index 42b796ada..6a77c2e29 100644 --- a/third_party/rutabaga/BUILD.rutabaga.bazel +++ b/third_party/rutabaga/BUILD.rutabaga.bazel @@ -1,5 +1,5 @@ -load("@rules_cc//cc:defs.bzl", "cc_library") -load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_library", "rust_static_library") +load("@rules_cc//cc:defs.bzl", "cc_library") # @unused +load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_library") package( default_visibility = ["@//:gfxstream"], From 42d4f2d1f0a562ebe05b4298cffaa3e6fe83d23e Mon Sep 17 00:00:00 2001 From: Serdar Kocdemir Date: Thu, 16 Jul 2026 10:41:40 +0100 Subject: [PATCH 07/33] Add end2end tests for Y8Cb8Cr8_420 Bug: 524740795 Test: tests/end2end:gfxstream_end2end_tests Change-Id: I4a984567366185d21c4aa821e478391dabda6d98 --- .../gfxstream_end2end_composition_tests.cpp | 220 ++++++++++++++++++ .../gfxstream_end2end_gralloc_tests.cpp | 83 +++++++ tests/end2end/gfxstream_end2end_tests.cpp | 7 + 3 files changed, 310 insertions(+) diff --git a/tests/end2end/gfxstream_end2end_composition_tests.cpp b/tests/end2end/gfxstream_end2end_composition_tests.cpp index 0ca46f114..499040647 100644 --- a/tests/end2end/gfxstream_end2end_composition_tests.cpp +++ b/tests/end2end/gfxstream_end2end_composition_tests.cpp @@ -235,6 +235,63 @@ TEST_P(GfxstreamEnd2EndCompositionTest, BlitYV12) { GFXSTREAM_ASSERT(AhbIsEntirely(resultAhb, rgbaColor)); } +TEST_P(GfxstreamEnd2EndCompositionTest, BlitYCbCr888420) { + constexpr const uint32_t kWidth = 32; + constexpr const uint32_t kHeight = 32; + + ScopedRenderControlDevice rcDevice(*mRc); + + const PixelR8G8B8A8 rgbaColor = PixelR8G8B8A8(66, 99, 160, 255); + + const auto yuvColor = PixelY8U8V8::FromR8G8B8A8(rgbaColor); + const auto yuvAhb = GFXSTREAM_ASSERT( + CreateAHBWithColor(kWidth, kHeight, GFXSTREAM_AHB_FORMAT_Y8Cb8Cr8_420, yuvColor)); + + auto resultAhb = GFXSTREAM_ASSERT(ScopedAHardwareBuffer::Allocate( + *mGralloc, kWidth, kHeight, GFXSTREAM_AHB_FORMAT_B8G8R8A8_UNORM)); + + const RenderControlComposition composition = { + .displayId = 0, + .compositionResultColorBufferHandle = mGralloc->getHostHandle(resultAhb), + }; + const std::vector compositionLayers = {{ + { + .colorBufferHandle = mGralloc->getHostHandle(yuvAhb), + .composeMode = HWC2_COMPOSITION_DEVICE, + .displayFrame = + { + .left = 0, + .top = 0, + .right = kWidth, + .bottom = kHeight, + }, + .crop = + { + .left = 0, + .top = 0, + .right = static_cast(kWidth), + .bottom = static_cast(kHeight), + }, + .blendMode = HWC2_BLEND_MODE_NONE, + .alpha = 1.0, + .color = + { + .r = 0, + .g = 0, + .b = 0, + .a = 0, + }, + .transform = static_cast(0), + }, + }}; + ASSERT_THAT( + mRc->rcCompose(rcDevice, &composition, static_cast(compositionLayers.size()), + compositionLayers.data()), + Eq(0)); + + GFXSTREAM_ASSERT(AhbIsEntirely(resultAhb, rgbaColor)); +} + TEST_P(GfxstreamEnd2EndCompositionTest, BasicCompositionYV12) { ScopedRenderControlDevice rcDevice(*mRc); @@ -316,6 +373,87 @@ TEST_P(GfxstreamEnd2EndCompositionTest, BasicCompositionYV12) { GFXSTREAM_ASSERT(CompareAHBWithGolden(resultAhb, "256x256_golden_basic_yv12.png")); } +TEST_P(GfxstreamEnd2EndCompositionTest, BasicCompositionYCbCr888420) { + ScopedRenderControlDevice rcDevice(*mRc); + + auto layer1Ahb = GFXSTREAM_ASSERT(CreateAHBFromImage("256x256_android.png")); + + const auto layer2RgbaColor = PixelR8G8B8A8(66, 99, 160, 255); + const auto layer2YuvColor = PixelY8U8V8::FromR8G8B8A8(layer2RgbaColor); + auto layer2Ahb = + GFXSTREAM_ASSERT(CreateAHBWithColor(32, 32, GFXSTREAM_AHB_FORMAT_Y8Cb8Cr8_420, layer2YuvColor)); + + auto resultAhb = GFXSTREAM_ASSERT( + ScopedAHardwareBuffer::Allocate(*mGralloc, 256, 256, GFXSTREAM_AHB_FORMAT_B8G8R8A8_UNORM)); + + const RenderControlComposition composition = { + .displayId = 0, + .compositionResultColorBufferHandle = mGralloc->getHostHandle(resultAhb), + }; + const RenderControlCompositionLayer compositionLayers[2] = { + { + .colorBufferHandle = mGralloc->getHostHandle(layer1Ahb), + .composeMode = HWC2_COMPOSITION_DEVICE, + .displayFrame = + { + .left = 0, + .top = 0, + .right = 256, + .bottom = 256, + }, + .crop = + { + .left = 0, + .top = 0, + .right = static_cast(256), + .bottom = static_cast(256), + }, + .blendMode = HWC2_BLEND_MODE_NONE, + .alpha = 1.0, + .color = + { + .r = 0, + .g = 0, + .b = 0, + .a = 0, + }, + .transform = static_cast(0), + }, + { + .colorBufferHandle = mGralloc->getHostHandle(layer2Ahb), + .composeMode = HWC2_COMPOSITION_DEVICE, + .displayFrame = + { + .left = 64, + .top = 32, + .right = 128, + .bottom = 160, + }, + .crop = + { + .left = 0, + .top = 0, + .right = static_cast(256), + .bottom = static_cast(256), + }, + .blendMode = HWC2_BLEND_MODE_NONE, + .alpha = 1.0, + .color = + { + .r = 0, + .g = 0, + .b = 0, + .a = 0, + }, + .transform = static_cast(0), + }, + }; + + ASSERT_THAT(mRc->rcCompose(rcDevice, &composition, 2, compositionLayers), Eq(0)); + + GFXSTREAM_ASSERT(CompareAHBWithGolden(resultAhb, "256x256_golden_basic_yv12.png")); +} + TEST_P(GfxstreamEnd2EndCompositionTest, RotatedCompositionRGBA) { ScopedRenderControlDevice rcDevice(*mRc); @@ -478,6 +616,88 @@ TEST_P(GfxstreamEnd2EndCompositionTest, RotatedCompositionYV12) { GFXSTREAM_ASSERT(CompareAHBWithGolden(resultAhb, "256x256_golden_rotated_yv12.png")); } +TEST_P(GfxstreamEnd2EndCompositionTest, RotatedCompositionYCbCr888420) { + ScopedRenderControlDevice rcDevice(*mRc); + + const auto rgbaColor1 = PixelR8G8B8A8(66, 99, 160, 255); + const auto rgbaColor2 = PixelR8G8B8A8(222, 16, 0, 255); + const auto yuvColor1 = PixelY8U8V8::FromR8G8B8A8(rgbaColor1); + const auto yuvColor2 = PixelY8U8V8::FromR8G8B8A8(rgbaColor2); + + auto layer1Ahb = GFXSTREAM_ASSERT(CreateAHBFromImage("256x256_android.png")); + auto layer2Ahb = GFXSTREAM_ASSERT( + CreateAHBWithCheckerboard(256, 256, 64, GFXSTREAM_AHB_FORMAT_Y8Cb8Cr8_420, yuvColor1, yuvColor2)); + auto resultAhb = GFXSTREAM_ASSERT( + ScopedAHardwareBuffer::Allocate(*mGralloc, 256, 256, GFXSTREAM_AHB_FORMAT_R8G8B8A8_UNORM)); + + const RenderControlComposition composition = { + .displayId = 0, + .compositionResultColorBufferHandle = mGralloc->getHostHandle(resultAhb), + }; + const RenderControlCompositionLayer compositionLayers[2] = { + { + .colorBufferHandle = mGralloc->getHostHandle(layer1Ahb), + .composeMode = HWC2_COMPOSITION_DEVICE, + .displayFrame = + { + .left = 0, + .top = 0, + .right = 256, + .bottom = 256, + }, + .crop = + { + .left = 0, + .top = 0, + .right = static_cast(256), + .bottom = static_cast(256), + }, + .blendMode = HWC2_BLEND_MODE_NONE, + .alpha = 1.0, + .color = + { + .r = 0, + .g = 0, + .b = 0, + .a = 0, + }, + .transform = static_cast(0), + }, + { + .colorBufferHandle = mGralloc->getHostHandle(layer2Ahb), + .composeMode = HWC2_COMPOSITION_DEVICE, + .displayFrame = + { + .left = 64, + .top = 32, + .right = 128, + .bottom = 160, + }, + .crop = + { + .left = 0, + .top = 0, + .right = static_cast(256), + .bottom = static_cast(256), + }, + .blendMode = HWC2_BLEND_MODE_NONE, + .alpha = 1.0, + .color = + { + .r = 0, + .g = 0, + .b = 0, + .a = 0, + }, + .transform = HWC_TRANSFORM_ROT_90, + }, + }; + + ASSERT_THAT(mRc->rcCompose(rcDevice, &composition, 2, compositionLayers), Eq(0)); + + GFXSTREAM_ASSERT(CompareAHBWithGolden(resultAhb, "256x256_golden_rotated_yv12.png")); +} + INSTANTIATE_TEST_SUITE_P(GfxstreamEnd2EndTests, GfxstreamEnd2EndCompositionTest, ::testing::ValuesIn({ TestParams{ diff --git a/tests/end2end/gfxstream_end2end_gralloc_tests.cpp b/tests/end2end/gfxstream_end2end_gralloc_tests.cpp index 26149bef2..e120536b0 100644 --- a/tests/end2end/gfxstream_end2end_gralloc_tests.cpp +++ b/tests/end2end/gfxstream_end2end_gralloc_tests.cpp @@ -34,6 +34,13 @@ TEST_P(GfxstreamEnd2EndGrallocTests, Allocate_YV12) { *mGralloc, 32, 32, GFXSTREAM_AHB_FORMAT_YV12)); } +TEST_P(GfxstreamEnd2EndGrallocTests, Allocate_YCbCr888420) { + ASSERT_THAT(false, Eq(true)); + + auto ahb = GFXSTREAM_ASSERT(ScopedAHardwareBuffer::Allocate( + *mGralloc, 32, 32, GFXSTREAM_AHB_FORMAT_Y8Cb8Cr8_420)); +} + TEST_P(GfxstreamEnd2EndGrallocTests, AllocateTransfer_RGBA8888) { constexpr const uint32_t kWidth = 32; constexpr const uint32_t kHeight = 32; @@ -149,6 +156,82 @@ TEST_P(GfxstreamEnd2EndGrallocTests, AllocateTransfer_YV12) { } } +TEST_P(GfxstreamEnd2EndGrallocTests, AllocateTransfer_YCbCr888420) { + constexpr const uint32_t kWidth = 32; + constexpr const uint32_t kHeight = 32; + + auto ahb = GFXSTREAM_ASSERT(ScopedAHardwareBuffer::Allocate( + *mGralloc, kWidth, kHeight, GFXSTREAM_AHB_FORMAT_Y8Cb8Cr8_420)); + + const PixelR8G8B8A8 color = PixelR8G8B8A8(11, 22, 33, 44); + + uint8_t colorY; + uint8_t colorU; + uint8_t colorV; + RGBToYUV(color.r, color.g, color.b, &colorY, &colorU, &colorV); + + { + std::vector ahbPlanes = + GFXSTREAM_ASSERT(ahb.LockPlanes()); + const Gralloc::LockedPlane& yPlane = ahbPlanes[0]; + const Gralloc::LockedPlane& uPlane = ahbPlanes[1]; + const Gralloc::LockedPlane& vPlane = ahbPlanes[2]; + + for (uint32_t y = 0; y < kHeight; y++) { + for (uint32_t x = 0; x < kWidth; x++) { + uint8_t* dstY = yPlane.data + + (y * yPlane.rowStrideBytes) + + (x * yPlane.pixelStrideBytes); + *dstY = colorY; + } + } + for (uint32_t y = 0; y < kHeight / 2; y++) { + for (uint32_t x = 0; x < kWidth / 2; x++) { + uint8_t* dstU = uPlane.data + + (y * uPlane.rowStrideBytes) + + (x * uPlane.pixelStrideBytes); + uint8_t* dstV = vPlane.data + + (y * vPlane.rowStrideBytes) + + (x * vPlane.pixelStrideBytes); + *dstU = colorU; + *dstV = colorV; + } + } + + ahb.Unlock(); + } + { + std::vector ahbPlanes = + GFXSTREAM_ASSERT(ahb.LockPlanes()); + const Gralloc::LockedPlane& yPlane = ahbPlanes[0]; + const Gralloc::LockedPlane& uPlane = ahbPlanes[1]; + const Gralloc::LockedPlane& vPlane = ahbPlanes[2]; + + for (uint32_t y = 0; y < kHeight; y++) { + for (uint32_t x = 0; x < kWidth; x++) { + const uint8_t* actualY = yPlane.data + + (y * yPlane.rowStrideBytes) + + (x * yPlane.pixelStrideBytes); + ASSERT_THAT(*actualY, Eq(colorY)); + } + } + for (uint32_t y = 0; y < kHeight / 2; y++) { + for (uint32_t x = 0; x < kWidth / 2; x++) { + const uint8_t* actualU = uPlane.data + + (y * uPlane.rowStrideBytes) + + (x * uPlane.pixelStrideBytes); + const uint8_t* actualV = vPlane.data + + (y * vPlane.rowStrideBytes) + + (x * vPlane.pixelStrideBytes); + ASSERT_THAT(*actualU, Eq(colorU)); + ASSERT_THAT(*actualV, Eq(colorV)); + } + } + + ahb.Unlock(); + } +} + TEST_P(GfxstreamEnd2EndGrallocTests, AllocateTransfer_Depth32FloatStencil8) { constexpr const uint32_t kWidth = 32; constexpr const uint32_t kHeight = 32; diff --git a/tests/end2end/gfxstream_end2end_tests.cpp b/tests/end2end/gfxstream_end2end_tests.cpp index dc493bc6a..740afd67a 100644 --- a/tests/end2end/gfxstream_end2end_tests.cpp +++ b/tests/end2end/gfxstream_end2end_tests.cpp @@ -475,6 +475,13 @@ Result ScopedAHardwareBuffer::Allocate(Gralloc& gralloc, std::to_string(width)); } } + if (format == GFXSTREAM_AHB_FORMAT_Y8Cb8Cr8_420) { + if ((width % 2) != 0) { + return gfxstream::unexpected( + "Failed to allocate Y8Cb8Cr8_420 AHB with non multiple of 2 width: " + + std::to_string(width)); + } + } AHardwareBuffer* ahb = nullptr; int status = gralloc.allocate(width, height, format, -1, &ahb); From f8b48d8ba692d08d3bd0f3f933ab7748367027ce Mon Sep 17 00:00:00 2001 From: Serdar Kocdemir Date: Mon, 13 Jul 2026 12:12:36 +0000 Subject: [PATCH 08/33] Add DmaBuf external memory mode This change implements `ExternalMemory::Mode::DmaBuf` support for Linux and other Unix-based platforms, replacing the legacy `supportsDmaBuf` boolean and manual addition of external memory bit flags by moving the main handlings into the new mode. Change also adds support check for some mandatory formats on DmaBuf mode, to avoid dependency on a block list for the correct enablement of the feature. Bug: 451503041 Bug: 400999642 Test: -gpu host on radv Change-Id: Ifb64bf6145b0b27a517a58d90a1f282d3b6c62f3 --- host/vulkan/external_memory.cpp | 128 ++++++++++++++++++++++-- host/vulkan/external_memory.h | 24 +++-- host/vulkan/vk_common_operations.cpp | 90 ++++++----------- host/vulkan/vk_common_operations.h | 3 - host/vulkan/vk_decoder_global_state.cpp | 40 ++------ 5 files changed, 176 insertions(+), 109 deletions(-) diff --git a/host/vulkan/external_memory.cpp b/host/vulkan/external_memory.cpp index d7de24fda..4663d7c25 100644 --- a/host/vulkan/external_memory.cpp +++ b/host/vulkan/external_memory.cpp @@ -38,6 +38,8 @@ const char* ExternalMemory::to_string(const ExternalMemory::Mode mode) { return "QnxScreenBuffer"; case Mode::HostAllocation: return "HostAllocation"; + case Mode::DmaBuf: + return "DmaBuf"; } return "Unhandled"; } @@ -51,11 +53,17 @@ std::optional ExternalMemory::getMode(std::string modeStr) return std::nullopt; } -bool ExternalMemory::modeSupported(const ExternalMemory::Mode mode, - const std::vector& deviceExts, - const VkPhysicalDeviceMemoryProperties& memoryProps) { +bool ExternalMemory::modeSupported( + const ExternalMemory::Mode mode, const std::vector& deviceExts, + const VkPhysicalDeviceMemoryProperties& memoryProps, std::string_view driverVendor, + VkPhysicalDevice physicalDevice, + PFN_vkGetPhysicalDeviceImageFormatProperties2KHR getImageFormatProperties2Func) { std::vector extRequired; getDeviceExtensionsForMode(mode, extRequired); + + if (!vk_util::extensionsSupported(deviceExts, extRequired)) { + return false; + } if (mode == Mode::HostAllocation) { // TODO(b/469094646): Check this during the initial gpu selection // Host allocation mode is designed for software renderers and only supported @@ -69,12 +77,103 @@ bool ExternalMemory::modeSupported(const ExternalMemory::Mode mode, } } - return vk_util::extensionsSupported(deviceExts, extRequired); + if (mode == Mode::DmaBuf) { +#if defined(__QNX__) + // TODO(aruby@qnx.com): Remove once dmabuf extension support has been flushed out on QNX + GFXSTREAM_INFO("External memory mode DmaBuf is not supported on QNX"); + return false; +#endif + if (physicalDevice == VK_NULL_HANDLE || getImageFormatProperties2Func == nullptr) { + // DmaBuf mode requires format support check, which needs valid device and function + GFXSTREAM_INFO("Cannot use external memory mode DmaBuf without valid device and function"); + return false; + } + + // Check if must-support image formats are supported, to avoid runtime crashes + // This check is only done for DmaBuf mode for now to avoid regressions. + const std::vector kFormatsToCheck = { + VK_FORMAT_R8G8B8A8_UNORM, + VK_FORMAT_R8G8B8A8_SRGB, + }; + for (const auto& format : kFormatsToCheck) { + VkPhysicalDeviceImageFormatInfo2 formatInfo2 = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, + .pNext = nullptr, + .format = format, + .type = VK_IMAGE_TYPE_2D, + .tiling = VK_IMAGE_TILING_OPTIMAL, + .usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | + VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, + .flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT, + }; + + VkPhysicalDeviceExternalImageFormatInfo extInfo = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO, + .pNext = nullptr, + .handleType = getHandleType(mode), + }; + + formatInfo2.pNext = &extInfo; + + VkImageFormatProperties2 outProps2 = { + .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2, + .pNext = nullptr, + }; + + VkExternalImageFormatProperties outExternalProps = { + .sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES, + .pNext = nullptr, + }; + + outProps2.pNext = &outExternalProps; + + VkResult res = getImageFormatProperties2Func(physicalDevice, &formatInfo2, &outProps2); + if (res == VK_ERROR_FORMAT_NOT_SUPPORTED) { + GFXSTREAM_INFO( + "%s: Mandatory format %s is not supported for external memory mode %s", + __func__, string_VkFormat(format), to_string(mode)); + return false; + } else if (res != VK_SUCCESS) { + GFXSTREAM_WARNING( + "%s: vkGetPhysicalDeviceImageFormatProperties2 failed for mode %s: %s", + __func__, to_string(mode), string_VkResult(res)); + return false; + } + + VkExternalMemoryFeatureFlags featureFlags = + outExternalProps.externalMemoryProperties.externalMemoryFeatures; + if (!(featureFlags & VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT) || + !(featureFlags & VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT)) { + GFXSTREAM_INFO( + "%s: format %s does not support required export/import features for mode %s", + __func__, string_VkFormat(format), to_string(mode)); + return false; + } + } + + // Lastly, check for some known problematic drivers + // This list should be removed once all issues are found through format support checks. + bool dmaBufBlockList = (driverVendor == "NVIDIA (Vendor 0x10de)"); +#ifdef CONFIG_AEMU + // TODO(b/400999642): dma_buf support should be checked with image format support + dmaBufBlockList |= (driverVendor == "radv (Vendor 0x1002)"); +#endif + if (dmaBufBlockList) { + GFXSTREAM_INFO("External memory mode DmaBuf is not supported on this device"); + return false; + } + } + + // All checks passed, the mode can be used. + return true; } ExternalMemory::Mode ExternalMemory::calculateMode( const std::vector& deviceExts, - const VkPhysicalDeviceMemoryProperties& memoryProps, std::optional modeStrOpt) { + const VkPhysicalDeviceMemoryProperties& memoryProps, std::optional modeStrOpt, + std::string_view driverVendor, VkPhysicalDevice physicalDevice, + PFN_vkGetPhysicalDeviceImageFormatProperties2KHR getImageFormatProperties2Func) { if (modeStrOpt) { auto mode = getMode(*modeStrOpt); if (!mode) { @@ -86,11 +185,12 @@ ExternalMemory::Mode ExternalMemory::calculateMode( return Mode::Unknown; } - if (!modeSupported(*mode, deviceExts, memoryProps)) { + if (!modeSupported(*mode, deviceExts, memoryProps, driverVendor, physicalDevice, + getImageFormatProperties2Func)) { GFXSTREAM_ERROR( "%s(): Vulkan driver does not support the memory mode provided by the " "VulkanExternalMemoryMode string: %s", - __func__, to_string(*mode)); + __func__, modeStrOpt->c_str()); return Mode::NotSupported; } @@ -118,13 +218,15 @@ ExternalMemory::Mode ExternalMemory::calculateMode( Mode::OpaqueFd, }; #else - std::array supportedModes = { + std::array supportedModes = { + Mode::DmaBuf, Mode::OpaqueFd, }; #endif for (auto mode : supportedModes) { - if (modeSupported(mode, deviceExts, memoryProps)) { + if (modeSupported(mode, deviceExts, memoryProps, driverVendor, physicalDevice, + getImageFormatProperties2Func)) { // Supported modes are in-order of preference, return the first one supported return mode; } @@ -138,6 +240,8 @@ VkExternalMemoryHandleTypeFlagBits ExternalMemory::getHandleType(const ExternalM switch (mode) { case Mode::OpaqueFd: return VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; + case Mode::DmaBuf: + return VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; case Mode::OpaqueWin32: return VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; case Mode::Metal: @@ -168,6 +272,12 @@ void ExternalMemory::getDeviceExtensionsForMode(const ExternalMemory::Mode mode, case Mode::OpaqueFd: outDeviceExtensions.push_back(VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME); break; + case Mode::DmaBuf: + // A dma-buf is a Linux kernel construct, commonly used with open-source DRM drivers. + // See https://docs.kernel.org/driver-api/dma-buf.html for details. + outDeviceExtensions.push_back(VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME); + outDeviceExtensions.push_back(VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME); + break; #ifdef VK_USE_PLATFORM_WIN32_KHR case Mode::OpaqueWin32: outDeviceExtensions.push_back(VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME); diff --git a/host/vulkan/external_memory.h b/host/vulkan/external_memory.h index e69570e27..028ea8686 100644 --- a/host/vulkan/external_memory.h +++ b/host/vulkan/external_memory.h @@ -17,6 +17,7 @@ #include #include +#include #include namespace gfxstream { @@ -35,25 +36,30 @@ class ExternalMemory { AndroidAHB, // VK_ANDROID_external_memory_android_hardware_buffer QnxScreenBuffer, // VK_QNX_external_memory_screen_buffer HostAllocation, // VK_EXT_external_memory_host + DmaBuf, // VK_EXT_external_memory_dma_buf }; - static inline const auto kAllValidModes = {Mode::OpaqueFd, Mode::OpaqueWin32, - Mode::Metal, Mode::AndroidAHB, - Mode::QnxScreenBuffer, Mode::HostAllocation}; + static inline const auto kAllValidModes = { + Mode::OpaqueFd, Mode::DmaBuf, Mode::OpaqueWin32, Mode::Metal, + Mode::AndroidAHB, Mode::QnxScreenBuffer, Mode::HostAllocation}; static const char* to_string(const Mode mode); - static Mode calculateMode(const std::vector& deviceExts, - const VkPhysicalDeviceMemoryProperties& memoryProps, - std::optional modeStrOpt); + static Mode calculateMode( + const std::vector& deviceExts, + const VkPhysicalDeviceMemoryProperties& memoryProps, std::optional modeStrOpt, + std::string_view driverVendor, VkPhysicalDevice physicalDevice, + PFN_vkGetPhysicalDeviceImageFormatProperties2KHR getImageFormatProperties2Func); static VkExternalMemoryHandleTypeFlagBits getHandleType(const Mode mode); static void getDeviceExtensionsForMode(const Mode mode, std::vector& outDeviceExtensions); private: static std::optional getMode(std::string modeStr); - static bool modeSupported(const ExternalMemory::Mode mode, - const std::vector& deviceExts, - const VkPhysicalDeviceMemoryProperties& memoryProps); + static bool modeSupported( + const ExternalMemory::Mode mode, const std::vector& deviceExts, + const VkPhysicalDeviceMemoryProperties& memoryProps, std::string_view driverVendor, + VkPhysicalDevice physicalDevice, + PFN_vkGetPhysicalDeviceImageFormatProperties2KHR getImageFormatProperties2Func); }; } // namespace vk diff --git a/host/vulkan/vk_common_operations.cpp b/host/vulkan/vk_common_operations.cpp index d33d3acbf..738486fca 100644 --- a/host/vulkan/vk_common_operations.cpp +++ b/host/vulkan/vk_common_operations.cpp @@ -1084,13 +1084,6 @@ std::unique_ptr VkEmulation::create(VulkanDispatch* gvk, ivk->vkEnumerateDeviceExtensionProperties(physicalDevices[i], nullptr, &deviceExtensionCount, deviceExts.data()); - deviceInfos[i].externalMemoryMode = ExternalMemory::calculateMode( - deviceExts, deviceInfos[i].memProps, features.VulkanExternalMemoryMode.getValue()); - - deviceInfos[i].supportsExternalMemoryImport = false; - deviceInfos[i].supportsExternalMemoryExport = false; - deviceInfos[i].glInteropSupported = 0; // set later - #if defined(__APPLE__) if (useMoltenVK && !vk_util::extensionsSupported(deviceExts, moltenVkDeviceExtNames)) { GFXSTREAM_ERROR("MoltenVK enabled but necessary device extensions are not supported."); @@ -1098,23 +1091,6 @@ std::unique_ptr VkEmulation::create(VulkanDispatch* gvk, } #endif - if (emulation->mInstanceSupportsExternalMemoryCapabilities && - deviceInfos[i].externalMemoryMode != ExternalMemory::Mode::NotSupported) { - std::vector externalMemoryDeviceExtNames; - ExternalMemory::getDeviceExtensionsForMode( - deviceInfos[i].externalMemoryMode, externalMemoryDeviceExtNames); - - deviceInfos[i].supportsExternalMemoryExport = - deviceInfos[i].supportsExternalMemoryImport = - vk_util::extensionsSupported(deviceExts, externalMemoryDeviceExtNames); - - // External memory export not supported by VK_QNX_external_memory_screen_buffer - if (deviceInfos[i].externalMemoryMode == ExternalMemory::Mode::QnxScreenBuffer) { - deviceInfos[i].supportsExternalMemoryExport = false; - } - - } - if (emulation->mInstanceSupportsGetPhysicalDeviceProperties2) { deviceInfos[i].supportsDriverProperties = vk_util::extensionSupported(deviceExts, VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME) || @@ -1176,17 +1152,30 @@ std::unique_ptr VkEmulation::create(VulkanDispatch* gvk, deviceInfos[i].driverInfo = driverProps.driverInfo; } -// TODO(aruby@qnx.com): Remove once dmabuf extension support has been flushed out on QNX -#if !defined(__QNX__) - bool dmaBufBlockList = (deviceInfos[i].driverVendor == "NVIDIA (Vendor 0x10de)"); -#ifdef CONFIG_AEMU - // TODO(b/400999642): dma_buf support should be checked with image format support - dmaBufBlockList |= (deviceInfos[i].driverVendor == "radv (Vendor 0x1002)"); -#endif - deviceInfos[i].supportsDmaBuf = - vk_util::extensionSupported(deviceExts, VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME) && - !dmaBufBlockList; -#endif + deviceInfos[i].externalMemoryMode = ExternalMemory::calculateMode( + deviceExts, deviceInfos[i].memProps, features.VulkanExternalMemoryMode.getValue(), + deviceInfos[i].driverVendor, physicalDevices[i], + emulation->mGetImageFormatProperties2Func); + + deviceInfos[i].supportsExternalMemoryImport = false; + deviceInfos[i].supportsExternalMemoryExport = false; + deviceInfos[i].glInteropSupported = 0; // set later + + if (emulation->mInstanceSupportsExternalMemoryCapabilities && + deviceInfos[i].externalMemoryMode != ExternalMemory::Mode::NotSupported) { + std::vector externalMemoryDeviceExtNames; + ExternalMemory::getDeviceExtensionsForMode(deviceInfos[i].externalMemoryMode, + externalMemoryDeviceExtNames); + + deviceInfos[i].supportsExternalMemoryExport = + deviceInfos[i].supportsExternalMemoryImport = + vk_util::extensionsSupported(deviceExts, externalMemoryDeviceExtNames); + + // External memory export not supported by VK_QNX_external_memory_screen_buffer + if (deviceInfos[i].externalMemoryMode == ExternalMemory::Mode::QnxScreenBuffer) { + deviceInfos[i].supportsExternalMemoryExport = false; + } + } deviceInfos[i].hasSamplerYcbcrConversionExtension = vk_util::extensionSupported(deviceExts, VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME); @@ -1357,8 +1346,6 @@ std::unique_ptr VkEmulation::create(VulkanDispatch* gvk, emulation->mDeviceInfo.supportsExternalMemoryImport ? "true" : "false"); GFXSTREAM_DEBUG(" supportsExternalMemoryExport = %s", emulation->mDeviceInfo.supportsExternalMemoryExport ? "true" : "false"); - GFXSTREAM_DEBUG(" supportsDmaBuf = %s", - emulation->mDeviceInfo.supportsDmaBuf ? "true" : "false"); GFXSTREAM_DEBUG(" supportsDriverProperties = %s", emulation->mDeviceInfo.supportsDriverProperties ? "true" : "false"); GFXSTREAM_DEBUG(" supportsExternalMemoryHostProps = %s", @@ -1426,12 +1413,6 @@ std::unique_ptr VkEmulation::create(VulkanDispatch* gvk, } } -#if defined(__linux__) - if (emulation->mDeviceInfo.supportsDmaBuf) { - selectedDeviceExtensionNames.emplace(VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME); - } -#endif - // We need to enable swapchain extensions to be able to use this device // to do VK_IMAGE_LAYOUT_PRESENT_SRC_KHR transition operations done // in releaseColorBufferForGuestUse for the apps using Vulkan swapchain. @@ -1845,8 +1826,6 @@ bool VkEmulation::supportsExternalMemoryImport() const { return mDeviceInfo.supportsExternalMemoryImport; } -bool VkEmulation::supportsDmaBuf() const { return mDeviceInfo.supportsDmaBuf; } - bool VkEmulation::supportsExternalMemoryHostProperties() const { return mDeviceInfo.supportsExternalMemoryHostProps; } @@ -2176,10 +2155,6 @@ bool VkEmulation::allocExternalMemory(VulkanDispatch* vk, VkEmulation::ExternalM exportAi.handleTypes = static_cast(getDefaultExternalMemoryHandleType()); - if (mDeviceInfo.supportsDmaBuf) { - exportAi.handleTypes |= VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; - } - vk_append_struct(&allocInfoChain, &exportAi); } @@ -2486,14 +2461,13 @@ bool VkEmulation::allocExternalMemory(VulkanDispatch* vk, VkEmulation::ExternalM bool validHandle = false; switch (mDeviceInfo.externalMemoryMode) { + case ExternalMemory::Mode::DmaBuf: case ExternalMemory::Mode::OpaqueFd: { - streamHandleType = STREAM_HANDLE_TYPE_MEM_OPAQUE_FD; + streamHandleType = (mDeviceInfo.externalMemoryMode == ExternalMemory::Mode::DmaBuf) + ? STREAM_HANDLE_TYPE_MEM_DMABUF + : STREAM_HANDLE_TYPE_MEM_OPAQUE_FD; VkExternalMemoryHandleTypeFlagBits vkHandleType = - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; - if (mDeviceInfo.supportsDmaBuf) { - vkHandleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; - streamHandleType = STREAM_HANDLE_TYPE_MEM_DMABUF; - } + ExternalMemory::getHandleType(mDeviceInfo.externalMemoryMode); VkMemoryGetFdInfoKHR getFdInfo = { VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR, @@ -2680,6 +2654,7 @@ bool VkEmulation::importExternalMemory(VulkanDispatch* vk, VkDevice targetDevice const void* importInfoPtr = nullptr; switch (mDeviceInfo.externalMemoryMode) { case ExternalMemory::Mode::AndroidAHB: + case ExternalMemory::Mode::DmaBuf: case ExternalMemory::Mode::OpaqueFd: { auto dupHandle = dupExternalMemory(handleInfo); if (!dupHandle) { @@ -2692,7 +2667,7 @@ bool VkEmulation::importExternalMemory(VulkanDispatch* vk, VkDevice targetDevice importInfoFd = { VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR, dedicatedAllocInfoPtr, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT, + ExternalMemory::getHandleType(mDeviceInfo.externalMemoryMode), static_cast(dupHandle->handle), }; importInfoPtr = &importInfoFd; @@ -4873,7 +4848,8 @@ VkExternalMemoryHandleTypeFlags VkEmulation::transformExternalMemoryHandleTypeFl // If the host does not support dmabuf, replace guest Linux DMA_BUF bits with // the host's default external memory bits, - if (!mDeviceInfo.supportsDmaBuf && (bits & VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT)) { + if (mDeviceInfo.externalMemoryMode != ExternalMemory::Mode::DmaBuf && + (bits & VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT)) { res &= ~VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; res |= getDefaultExternalMemoryHandleType(); } diff --git a/host/vulkan/vk_common_operations.h b/host/vulkan/vk_common_operations.h index 8ba6a0e1d..c29439eac 100644 --- a/host/vulkan/vk_common_operations.h +++ b/host/vulkan/vk_common_operations.h @@ -145,8 +145,6 @@ class VkEmulation { bool supportsExternalMemoryImport() const; - bool supportsDmaBuf() const; - bool supportsExternalMemoryHostProperties() const; bool isSwapchainEnabled() const; @@ -484,7 +482,6 @@ class VkEmulation { bool hasComputeQueueFamily = false; bool supportsExternalMemoryImport = false; bool supportsExternalMemoryExport = false; - bool supportsDmaBuf = false; bool supportsDriverProperties = false; bool supportsExternalMemoryHostProps = false; bool supportsSwapchain = false; diff --git a/host/vulkan/vk_decoder_global_state.cpp b/host/vulkan/vk_decoder_global_state.cpp index ad7f23cdf..fc0f5732a 100644 --- a/host/vulkan/vk_decoder_global_state.cpp +++ b/host/vulkan/vk_decoder_global_state.cpp @@ -6493,8 +6493,6 @@ class VkDecoderGlobalState::Impl { uint32_t virtioGpuContextId = 0; VkMemoryPropertyFlags memoryPropertyFlags; - bool deviceHasDmabufExt = false; - // Map guest memory index to host memory index and lookup memory properties: { std::lock_guard lock(mMutex); @@ -6512,9 +6510,6 @@ class VkDecoderGlobalState::Impl { GFXSTREAM_FATAL("No info available for VkPhysicalDevice:%p", deviceInfo->physicalDevice); } - deviceHasDmabufExt = - hasDeviceExtension(device, VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME); - const auto hostMemoryInfoOpt = physicalDeviceInfo->memoryPropertiesHelper ->getHostMemoryInfoFromGuestMemoryTypeIndex(localAllocInfo.memoryTypeIndex); @@ -6590,7 +6585,7 @@ class VkDecoderGlobalState::Impl { return VK_ERROR_OUT_OF_DEVICE_MEMORY; } - if (!m_vkEmulation->supportsDmaBuf() || !deviceHasDmabufExt) { + if (m_vkEmulation->getExternalMemoryMode() != ExternalMemory::Mode::DmaBuf) { GFXSTREAM_ERROR("dmabuf not supported"); return VK_ERROR_OUT_OF_DEVICE_MEMORY; } @@ -6600,7 +6595,6 @@ class VkDecoderGlobalState::Impl { vk_append_struct(&structChainIter, &importFdInfo); #else (void)virtioGpuContextId; // suppress warnings - (void)deviceHasDmabufExt; GFXSTREAM_ERROR("Guest Handle flow should not work here"); return VK_ERROR_OUT_OF_DEVICE_MEMORY; #endif @@ -6639,7 +6633,7 @@ class VkDecoderGlobalState::Impl { // Import operation takes ownership of descriptor #if defined(__linux__) - if (!m_vkEmulation->supportsDmaBuf() || !deviceHasDmabufExt) { + if (m_vkEmulation->getExternalMemoryMode() != ExternalMemory::Mode::DmaBuf) { GFXSTREAM_ERROR("dmabuf not supported"); return VK_ERROR_OUT_OF_DEVICE_MEMORY; } @@ -6681,12 +6675,6 @@ class VkDecoderGlobalState::Impl { } else if (m_vkEmulation->getFeatures().ExternalBlob.enabled()) { VkExternalMemoryHandleTypeFlags handleTypes = m_vkEmulation->getDefaultExternalMemoryHandleType(); -#ifdef __linux__ - if (m_vkEmulation->supportsDmaBuf() && deviceHasDmabufExt) { - handleTypes |= VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; - } -#endif - exportAllocateInfo = { .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO, .pNext = NULL, @@ -10155,14 +10143,6 @@ class VkDecoderGlobalState::Impl { } #endif -#if defined(__linux__) - // A dma-buf is a Linux kernel construct, commonly used with open-source DRM drivers. - // See https://docs.kernel.org/driver-api/dma-buf.html for details. - if (m_vkEmulation->supportsDmaBuf()) { - hostAlwaysDeviceExtensions.push_back(VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME); - } -#endif - // Enable all the device extensions that should always be enabled on the host (if available) for (auto extName : hostAlwaysDeviceExtensions) { if (hasDeviceExtension(properties, extName)) { @@ -10353,6 +10333,7 @@ class VkDecoderGlobalState::Impl { const auto extMemMode = m_vkEmulation->getExternalMemoryMode(); switch (extMemMode) { #if defined(__unix__) && !defined(__ANDROID__) + case ExternalMemory::Mode::DmaBuf: case ExternalMemory::Mode::OpaqueFd: { if (!vk->vkGetMemoryFdKHR) { GFXSTREAM_ERROR("%s: External memory function not supported.", __func__); @@ -10362,16 +10343,13 @@ class VkDecoderGlobalState::Impl { .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR, .pNext = nullptr, .memory = memory, - .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT, + .handleType = (extMemMode == ExternalMemory::Mode::DmaBuf) + ? VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT + : VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT, }; - ret.streamHandleType = STREAM_HANDLE_TYPE_MEM_OPAQUE_FD; - -#if defined(__linux__) - if (m_vkEmulation->supportsDmaBuf()) { - memoryGetFdInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; - ret.streamHandleType = STREAM_HANDLE_TYPE_MEM_DMABUF; - } -#endif + ret.streamHandleType = (extMemMode == ExternalMemory::Mode::DmaBuf) + ? STREAM_HANDLE_TYPE_MEM_DMABUF + : STREAM_HANDLE_TYPE_MEM_OPAQUE_FD; int fd = -1; VkResult res = vk->vkGetMemoryFdKHR(device, &memoryGetFdInfo, &fd); From 9f0a11b0770f864287987f79cacd43077beb6b50 Mon Sep 17 00:00:00 2001 From: Jeongik Cha Date: Sun, 26 Jul 2026 22:21:12 -0700 Subject: [PATCH 09/33] Revert "Add DmaBuf external memory mode" This reverts commit 0c19b8d24a5a7c24355bda612570e2718572e94f. Reason for revert: b/539295062 Bug: 451503041 Bug: 400999642 Change-Id: I13b04cc120dad28cd7de757f5feb5db55b69d7b0 --- host/vulkan/external_memory.cpp | 128 ++---------------------- host/vulkan/external_memory.h | 24 ++--- host/vulkan/vk_common_operations.cpp | 90 +++++++++++------ host/vulkan/vk_common_operations.h | 3 + host/vulkan/vk_decoder_global_state.cpp | 40 ++++++-- 5 files changed, 109 insertions(+), 176 deletions(-) diff --git a/host/vulkan/external_memory.cpp b/host/vulkan/external_memory.cpp index 4663d7c25..d7de24fda 100644 --- a/host/vulkan/external_memory.cpp +++ b/host/vulkan/external_memory.cpp @@ -38,8 +38,6 @@ const char* ExternalMemory::to_string(const ExternalMemory::Mode mode) { return "QnxScreenBuffer"; case Mode::HostAllocation: return "HostAllocation"; - case Mode::DmaBuf: - return "DmaBuf"; } return "Unhandled"; } @@ -53,17 +51,11 @@ std::optional ExternalMemory::getMode(std::string modeStr) return std::nullopt; } -bool ExternalMemory::modeSupported( - const ExternalMemory::Mode mode, const std::vector& deviceExts, - const VkPhysicalDeviceMemoryProperties& memoryProps, std::string_view driverVendor, - VkPhysicalDevice physicalDevice, - PFN_vkGetPhysicalDeviceImageFormatProperties2KHR getImageFormatProperties2Func) { +bool ExternalMemory::modeSupported(const ExternalMemory::Mode mode, + const std::vector& deviceExts, + const VkPhysicalDeviceMemoryProperties& memoryProps) { std::vector extRequired; getDeviceExtensionsForMode(mode, extRequired); - - if (!vk_util::extensionsSupported(deviceExts, extRequired)) { - return false; - } if (mode == Mode::HostAllocation) { // TODO(b/469094646): Check this during the initial gpu selection // Host allocation mode is designed for software renderers and only supported @@ -77,103 +69,12 @@ bool ExternalMemory::modeSupported( } } - if (mode == Mode::DmaBuf) { -#if defined(__QNX__) - // TODO(aruby@qnx.com): Remove once dmabuf extension support has been flushed out on QNX - GFXSTREAM_INFO("External memory mode DmaBuf is not supported on QNX"); - return false; -#endif - if (physicalDevice == VK_NULL_HANDLE || getImageFormatProperties2Func == nullptr) { - // DmaBuf mode requires format support check, which needs valid device and function - GFXSTREAM_INFO("Cannot use external memory mode DmaBuf without valid device and function"); - return false; - } - - // Check if must-support image formats are supported, to avoid runtime crashes - // This check is only done for DmaBuf mode for now to avoid regressions. - const std::vector kFormatsToCheck = { - VK_FORMAT_R8G8B8A8_UNORM, - VK_FORMAT_R8G8B8A8_SRGB, - }; - for (const auto& format : kFormatsToCheck) { - VkPhysicalDeviceImageFormatInfo2 formatInfo2 = { - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, - .pNext = nullptr, - .format = format, - .type = VK_IMAGE_TYPE_2D, - .tiling = VK_IMAGE_TILING_OPTIMAL, - .usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | - VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | - VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, - .flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT, - }; - - VkPhysicalDeviceExternalImageFormatInfo extInfo = { - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO, - .pNext = nullptr, - .handleType = getHandleType(mode), - }; - - formatInfo2.pNext = &extInfo; - - VkImageFormatProperties2 outProps2 = { - .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2, - .pNext = nullptr, - }; - - VkExternalImageFormatProperties outExternalProps = { - .sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES, - .pNext = nullptr, - }; - - outProps2.pNext = &outExternalProps; - - VkResult res = getImageFormatProperties2Func(physicalDevice, &formatInfo2, &outProps2); - if (res == VK_ERROR_FORMAT_NOT_SUPPORTED) { - GFXSTREAM_INFO( - "%s: Mandatory format %s is not supported for external memory mode %s", - __func__, string_VkFormat(format), to_string(mode)); - return false; - } else if (res != VK_SUCCESS) { - GFXSTREAM_WARNING( - "%s: vkGetPhysicalDeviceImageFormatProperties2 failed for mode %s: %s", - __func__, to_string(mode), string_VkResult(res)); - return false; - } - - VkExternalMemoryFeatureFlags featureFlags = - outExternalProps.externalMemoryProperties.externalMemoryFeatures; - if (!(featureFlags & VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT) || - !(featureFlags & VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT)) { - GFXSTREAM_INFO( - "%s: format %s does not support required export/import features for mode %s", - __func__, string_VkFormat(format), to_string(mode)); - return false; - } - } - - // Lastly, check for some known problematic drivers - // This list should be removed once all issues are found through format support checks. - bool dmaBufBlockList = (driverVendor == "NVIDIA (Vendor 0x10de)"); -#ifdef CONFIG_AEMU - // TODO(b/400999642): dma_buf support should be checked with image format support - dmaBufBlockList |= (driverVendor == "radv (Vendor 0x1002)"); -#endif - if (dmaBufBlockList) { - GFXSTREAM_INFO("External memory mode DmaBuf is not supported on this device"); - return false; - } - } - - // All checks passed, the mode can be used. - return true; + return vk_util::extensionsSupported(deviceExts, extRequired); } ExternalMemory::Mode ExternalMemory::calculateMode( const std::vector& deviceExts, - const VkPhysicalDeviceMemoryProperties& memoryProps, std::optional modeStrOpt, - std::string_view driverVendor, VkPhysicalDevice physicalDevice, - PFN_vkGetPhysicalDeviceImageFormatProperties2KHR getImageFormatProperties2Func) { + const VkPhysicalDeviceMemoryProperties& memoryProps, std::optional modeStrOpt) { if (modeStrOpt) { auto mode = getMode(*modeStrOpt); if (!mode) { @@ -185,12 +86,11 @@ ExternalMemory::Mode ExternalMemory::calculateMode( return Mode::Unknown; } - if (!modeSupported(*mode, deviceExts, memoryProps, driverVendor, physicalDevice, - getImageFormatProperties2Func)) { + if (!modeSupported(*mode, deviceExts, memoryProps)) { GFXSTREAM_ERROR( "%s(): Vulkan driver does not support the memory mode provided by the " "VulkanExternalMemoryMode string: %s", - __func__, modeStrOpt->c_str()); + __func__, to_string(*mode)); return Mode::NotSupported; } @@ -218,15 +118,13 @@ ExternalMemory::Mode ExternalMemory::calculateMode( Mode::OpaqueFd, }; #else - std::array supportedModes = { - Mode::DmaBuf, + std::array supportedModes = { Mode::OpaqueFd, }; #endif for (auto mode : supportedModes) { - if (modeSupported(mode, deviceExts, memoryProps, driverVendor, physicalDevice, - getImageFormatProperties2Func)) { + if (modeSupported(mode, deviceExts, memoryProps)) { // Supported modes are in-order of preference, return the first one supported return mode; } @@ -240,8 +138,6 @@ VkExternalMemoryHandleTypeFlagBits ExternalMemory::getHandleType(const ExternalM switch (mode) { case Mode::OpaqueFd: return VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; - case Mode::DmaBuf: - return VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; case Mode::OpaqueWin32: return VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; case Mode::Metal: @@ -272,12 +168,6 @@ void ExternalMemory::getDeviceExtensionsForMode(const ExternalMemory::Mode mode, case Mode::OpaqueFd: outDeviceExtensions.push_back(VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME); break; - case Mode::DmaBuf: - // A dma-buf is a Linux kernel construct, commonly used with open-source DRM drivers. - // See https://docs.kernel.org/driver-api/dma-buf.html for details. - outDeviceExtensions.push_back(VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME); - outDeviceExtensions.push_back(VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME); - break; #ifdef VK_USE_PLATFORM_WIN32_KHR case Mode::OpaqueWin32: outDeviceExtensions.push_back(VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME); diff --git a/host/vulkan/external_memory.h b/host/vulkan/external_memory.h index 028ea8686..e69570e27 100644 --- a/host/vulkan/external_memory.h +++ b/host/vulkan/external_memory.h @@ -17,7 +17,6 @@ #include #include -#include #include namespace gfxstream { @@ -36,30 +35,25 @@ class ExternalMemory { AndroidAHB, // VK_ANDROID_external_memory_android_hardware_buffer QnxScreenBuffer, // VK_QNX_external_memory_screen_buffer HostAllocation, // VK_EXT_external_memory_host - DmaBuf, // VK_EXT_external_memory_dma_buf }; - static inline const auto kAllValidModes = { - Mode::OpaqueFd, Mode::DmaBuf, Mode::OpaqueWin32, Mode::Metal, - Mode::AndroidAHB, Mode::QnxScreenBuffer, Mode::HostAllocation}; + static inline const auto kAllValidModes = {Mode::OpaqueFd, Mode::OpaqueWin32, + Mode::Metal, Mode::AndroidAHB, + Mode::QnxScreenBuffer, Mode::HostAllocation}; static const char* to_string(const Mode mode); - static Mode calculateMode( - const std::vector& deviceExts, - const VkPhysicalDeviceMemoryProperties& memoryProps, std::optional modeStrOpt, - std::string_view driverVendor, VkPhysicalDevice physicalDevice, - PFN_vkGetPhysicalDeviceImageFormatProperties2KHR getImageFormatProperties2Func); + static Mode calculateMode(const std::vector& deviceExts, + const VkPhysicalDeviceMemoryProperties& memoryProps, + std::optional modeStrOpt); static VkExternalMemoryHandleTypeFlagBits getHandleType(const Mode mode); static void getDeviceExtensionsForMode(const Mode mode, std::vector& outDeviceExtensions); private: static std::optional getMode(std::string modeStr); - static bool modeSupported( - const ExternalMemory::Mode mode, const std::vector& deviceExts, - const VkPhysicalDeviceMemoryProperties& memoryProps, std::string_view driverVendor, - VkPhysicalDevice physicalDevice, - PFN_vkGetPhysicalDeviceImageFormatProperties2KHR getImageFormatProperties2Func); + static bool modeSupported(const ExternalMemory::Mode mode, + const std::vector& deviceExts, + const VkPhysicalDeviceMemoryProperties& memoryProps); }; } // namespace vk diff --git a/host/vulkan/vk_common_operations.cpp b/host/vulkan/vk_common_operations.cpp index 738486fca..d33d3acbf 100644 --- a/host/vulkan/vk_common_operations.cpp +++ b/host/vulkan/vk_common_operations.cpp @@ -1084,6 +1084,13 @@ std::unique_ptr VkEmulation::create(VulkanDispatch* gvk, ivk->vkEnumerateDeviceExtensionProperties(physicalDevices[i], nullptr, &deviceExtensionCount, deviceExts.data()); + deviceInfos[i].externalMemoryMode = ExternalMemory::calculateMode( + deviceExts, deviceInfos[i].memProps, features.VulkanExternalMemoryMode.getValue()); + + deviceInfos[i].supportsExternalMemoryImport = false; + deviceInfos[i].supportsExternalMemoryExport = false; + deviceInfos[i].glInteropSupported = 0; // set later + #if defined(__APPLE__) if (useMoltenVK && !vk_util::extensionsSupported(deviceExts, moltenVkDeviceExtNames)) { GFXSTREAM_ERROR("MoltenVK enabled but necessary device extensions are not supported."); @@ -1091,6 +1098,23 @@ std::unique_ptr VkEmulation::create(VulkanDispatch* gvk, } #endif + if (emulation->mInstanceSupportsExternalMemoryCapabilities && + deviceInfos[i].externalMemoryMode != ExternalMemory::Mode::NotSupported) { + std::vector externalMemoryDeviceExtNames; + ExternalMemory::getDeviceExtensionsForMode( + deviceInfos[i].externalMemoryMode, externalMemoryDeviceExtNames); + + deviceInfos[i].supportsExternalMemoryExport = + deviceInfos[i].supportsExternalMemoryImport = + vk_util::extensionsSupported(deviceExts, externalMemoryDeviceExtNames); + + // External memory export not supported by VK_QNX_external_memory_screen_buffer + if (deviceInfos[i].externalMemoryMode == ExternalMemory::Mode::QnxScreenBuffer) { + deviceInfos[i].supportsExternalMemoryExport = false; + } + + } + if (emulation->mInstanceSupportsGetPhysicalDeviceProperties2) { deviceInfos[i].supportsDriverProperties = vk_util::extensionSupported(deviceExts, VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME) || @@ -1152,30 +1176,17 @@ std::unique_ptr VkEmulation::create(VulkanDispatch* gvk, deviceInfos[i].driverInfo = driverProps.driverInfo; } - deviceInfos[i].externalMemoryMode = ExternalMemory::calculateMode( - deviceExts, deviceInfos[i].memProps, features.VulkanExternalMemoryMode.getValue(), - deviceInfos[i].driverVendor, physicalDevices[i], - emulation->mGetImageFormatProperties2Func); - - deviceInfos[i].supportsExternalMemoryImport = false; - deviceInfos[i].supportsExternalMemoryExport = false; - deviceInfos[i].glInteropSupported = 0; // set later - - if (emulation->mInstanceSupportsExternalMemoryCapabilities && - deviceInfos[i].externalMemoryMode != ExternalMemory::Mode::NotSupported) { - std::vector externalMemoryDeviceExtNames; - ExternalMemory::getDeviceExtensionsForMode(deviceInfos[i].externalMemoryMode, - externalMemoryDeviceExtNames); - - deviceInfos[i].supportsExternalMemoryExport = - deviceInfos[i].supportsExternalMemoryImport = - vk_util::extensionsSupported(deviceExts, externalMemoryDeviceExtNames); - - // External memory export not supported by VK_QNX_external_memory_screen_buffer - if (deviceInfos[i].externalMemoryMode == ExternalMemory::Mode::QnxScreenBuffer) { - deviceInfos[i].supportsExternalMemoryExport = false; - } - } +// TODO(aruby@qnx.com): Remove once dmabuf extension support has been flushed out on QNX +#if !defined(__QNX__) + bool dmaBufBlockList = (deviceInfos[i].driverVendor == "NVIDIA (Vendor 0x10de)"); +#ifdef CONFIG_AEMU + // TODO(b/400999642): dma_buf support should be checked with image format support + dmaBufBlockList |= (deviceInfos[i].driverVendor == "radv (Vendor 0x1002)"); +#endif + deviceInfos[i].supportsDmaBuf = + vk_util::extensionSupported(deviceExts, VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME) && + !dmaBufBlockList; +#endif deviceInfos[i].hasSamplerYcbcrConversionExtension = vk_util::extensionSupported(deviceExts, VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME); @@ -1346,6 +1357,8 @@ std::unique_ptr VkEmulation::create(VulkanDispatch* gvk, emulation->mDeviceInfo.supportsExternalMemoryImport ? "true" : "false"); GFXSTREAM_DEBUG(" supportsExternalMemoryExport = %s", emulation->mDeviceInfo.supportsExternalMemoryExport ? "true" : "false"); + GFXSTREAM_DEBUG(" supportsDmaBuf = %s", + emulation->mDeviceInfo.supportsDmaBuf ? "true" : "false"); GFXSTREAM_DEBUG(" supportsDriverProperties = %s", emulation->mDeviceInfo.supportsDriverProperties ? "true" : "false"); GFXSTREAM_DEBUG(" supportsExternalMemoryHostProps = %s", @@ -1413,6 +1426,12 @@ std::unique_ptr VkEmulation::create(VulkanDispatch* gvk, } } +#if defined(__linux__) + if (emulation->mDeviceInfo.supportsDmaBuf) { + selectedDeviceExtensionNames.emplace(VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME); + } +#endif + // We need to enable swapchain extensions to be able to use this device // to do VK_IMAGE_LAYOUT_PRESENT_SRC_KHR transition operations done // in releaseColorBufferForGuestUse for the apps using Vulkan swapchain. @@ -1826,6 +1845,8 @@ bool VkEmulation::supportsExternalMemoryImport() const { return mDeviceInfo.supportsExternalMemoryImport; } +bool VkEmulation::supportsDmaBuf() const { return mDeviceInfo.supportsDmaBuf; } + bool VkEmulation::supportsExternalMemoryHostProperties() const { return mDeviceInfo.supportsExternalMemoryHostProps; } @@ -2155,6 +2176,10 @@ bool VkEmulation::allocExternalMemory(VulkanDispatch* vk, VkEmulation::ExternalM exportAi.handleTypes = static_cast(getDefaultExternalMemoryHandleType()); + if (mDeviceInfo.supportsDmaBuf) { + exportAi.handleTypes |= VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; + } + vk_append_struct(&allocInfoChain, &exportAi); } @@ -2461,13 +2486,14 @@ bool VkEmulation::allocExternalMemory(VulkanDispatch* vk, VkEmulation::ExternalM bool validHandle = false; switch (mDeviceInfo.externalMemoryMode) { - case ExternalMemory::Mode::DmaBuf: case ExternalMemory::Mode::OpaqueFd: { - streamHandleType = (mDeviceInfo.externalMemoryMode == ExternalMemory::Mode::DmaBuf) - ? STREAM_HANDLE_TYPE_MEM_DMABUF - : STREAM_HANDLE_TYPE_MEM_OPAQUE_FD; + streamHandleType = STREAM_HANDLE_TYPE_MEM_OPAQUE_FD; VkExternalMemoryHandleTypeFlagBits vkHandleType = - ExternalMemory::getHandleType(mDeviceInfo.externalMemoryMode); + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; + if (mDeviceInfo.supportsDmaBuf) { + vkHandleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; + streamHandleType = STREAM_HANDLE_TYPE_MEM_DMABUF; + } VkMemoryGetFdInfoKHR getFdInfo = { VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR, @@ -2654,7 +2680,6 @@ bool VkEmulation::importExternalMemory(VulkanDispatch* vk, VkDevice targetDevice const void* importInfoPtr = nullptr; switch (mDeviceInfo.externalMemoryMode) { case ExternalMemory::Mode::AndroidAHB: - case ExternalMemory::Mode::DmaBuf: case ExternalMemory::Mode::OpaqueFd: { auto dupHandle = dupExternalMemory(handleInfo); if (!dupHandle) { @@ -2667,7 +2692,7 @@ bool VkEmulation::importExternalMemory(VulkanDispatch* vk, VkDevice targetDevice importInfoFd = { VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR, dedicatedAllocInfoPtr, - ExternalMemory::getHandleType(mDeviceInfo.externalMemoryMode), + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT, static_cast(dupHandle->handle), }; importInfoPtr = &importInfoFd; @@ -4848,8 +4873,7 @@ VkExternalMemoryHandleTypeFlags VkEmulation::transformExternalMemoryHandleTypeFl // If the host does not support dmabuf, replace guest Linux DMA_BUF bits with // the host's default external memory bits, - if (mDeviceInfo.externalMemoryMode != ExternalMemory::Mode::DmaBuf && - (bits & VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT)) { + if (!mDeviceInfo.supportsDmaBuf && (bits & VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT)) { res &= ~VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; res |= getDefaultExternalMemoryHandleType(); } diff --git a/host/vulkan/vk_common_operations.h b/host/vulkan/vk_common_operations.h index c29439eac..8ba6a0e1d 100644 --- a/host/vulkan/vk_common_operations.h +++ b/host/vulkan/vk_common_operations.h @@ -145,6 +145,8 @@ class VkEmulation { bool supportsExternalMemoryImport() const; + bool supportsDmaBuf() const; + bool supportsExternalMemoryHostProperties() const; bool isSwapchainEnabled() const; @@ -482,6 +484,7 @@ class VkEmulation { bool hasComputeQueueFamily = false; bool supportsExternalMemoryImport = false; bool supportsExternalMemoryExport = false; + bool supportsDmaBuf = false; bool supportsDriverProperties = false; bool supportsExternalMemoryHostProps = false; bool supportsSwapchain = false; diff --git a/host/vulkan/vk_decoder_global_state.cpp b/host/vulkan/vk_decoder_global_state.cpp index fc0f5732a..ad7f23cdf 100644 --- a/host/vulkan/vk_decoder_global_state.cpp +++ b/host/vulkan/vk_decoder_global_state.cpp @@ -6493,6 +6493,8 @@ class VkDecoderGlobalState::Impl { uint32_t virtioGpuContextId = 0; VkMemoryPropertyFlags memoryPropertyFlags; + bool deviceHasDmabufExt = false; + // Map guest memory index to host memory index and lookup memory properties: { std::lock_guard lock(mMutex); @@ -6510,6 +6512,9 @@ class VkDecoderGlobalState::Impl { GFXSTREAM_FATAL("No info available for VkPhysicalDevice:%p", deviceInfo->physicalDevice); } + deviceHasDmabufExt = + hasDeviceExtension(device, VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME); + const auto hostMemoryInfoOpt = physicalDeviceInfo->memoryPropertiesHelper ->getHostMemoryInfoFromGuestMemoryTypeIndex(localAllocInfo.memoryTypeIndex); @@ -6585,7 +6590,7 @@ class VkDecoderGlobalState::Impl { return VK_ERROR_OUT_OF_DEVICE_MEMORY; } - if (m_vkEmulation->getExternalMemoryMode() != ExternalMemory::Mode::DmaBuf) { + if (!m_vkEmulation->supportsDmaBuf() || !deviceHasDmabufExt) { GFXSTREAM_ERROR("dmabuf not supported"); return VK_ERROR_OUT_OF_DEVICE_MEMORY; } @@ -6595,6 +6600,7 @@ class VkDecoderGlobalState::Impl { vk_append_struct(&structChainIter, &importFdInfo); #else (void)virtioGpuContextId; // suppress warnings + (void)deviceHasDmabufExt; GFXSTREAM_ERROR("Guest Handle flow should not work here"); return VK_ERROR_OUT_OF_DEVICE_MEMORY; #endif @@ -6633,7 +6639,7 @@ class VkDecoderGlobalState::Impl { // Import operation takes ownership of descriptor #if defined(__linux__) - if (m_vkEmulation->getExternalMemoryMode() != ExternalMemory::Mode::DmaBuf) { + if (!m_vkEmulation->supportsDmaBuf() || !deviceHasDmabufExt) { GFXSTREAM_ERROR("dmabuf not supported"); return VK_ERROR_OUT_OF_DEVICE_MEMORY; } @@ -6675,6 +6681,12 @@ class VkDecoderGlobalState::Impl { } else if (m_vkEmulation->getFeatures().ExternalBlob.enabled()) { VkExternalMemoryHandleTypeFlags handleTypes = m_vkEmulation->getDefaultExternalMemoryHandleType(); +#ifdef __linux__ + if (m_vkEmulation->supportsDmaBuf() && deviceHasDmabufExt) { + handleTypes |= VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; + } +#endif + exportAllocateInfo = { .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO, .pNext = NULL, @@ -10143,6 +10155,14 @@ class VkDecoderGlobalState::Impl { } #endif +#if defined(__linux__) + // A dma-buf is a Linux kernel construct, commonly used with open-source DRM drivers. + // See https://docs.kernel.org/driver-api/dma-buf.html for details. + if (m_vkEmulation->supportsDmaBuf()) { + hostAlwaysDeviceExtensions.push_back(VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME); + } +#endif + // Enable all the device extensions that should always be enabled on the host (if available) for (auto extName : hostAlwaysDeviceExtensions) { if (hasDeviceExtension(properties, extName)) { @@ -10333,7 +10353,6 @@ class VkDecoderGlobalState::Impl { const auto extMemMode = m_vkEmulation->getExternalMemoryMode(); switch (extMemMode) { #if defined(__unix__) && !defined(__ANDROID__) - case ExternalMemory::Mode::DmaBuf: case ExternalMemory::Mode::OpaqueFd: { if (!vk->vkGetMemoryFdKHR) { GFXSTREAM_ERROR("%s: External memory function not supported.", __func__); @@ -10343,13 +10362,16 @@ class VkDecoderGlobalState::Impl { .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR, .pNext = nullptr, .memory = memory, - .handleType = (extMemMode == ExternalMemory::Mode::DmaBuf) - ? VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT - : VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT, + .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT, }; - ret.streamHandleType = (extMemMode == ExternalMemory::Mode::DmaBuf) - ? STREAM_HANDLE_TYPE_MEM_DMABUF - : STREAM_HANDLE_TYPE_MEM_OPAQUE_FD; + ret.streamHandleType = STREAM_HANDLE_TYPE_MEM_OPAQUE_FD; + +#if defined(__linux__) + if (m_vkEmulation->supportsDmaBuf()) { + memoryGetFdInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; + ret.streamHandleType = STREAM_HANDLE_TYPE_MEM_DMABUF; + } +#endif int fd = -1; VkResult res = vk->vkGetMemoryFdKHR(device, &memoryGetFdInfo, &fd); From 8785c03251679c01385e2f4bc8820cddd97285cb Mon Sep 17 00:00:00 2001 From: Sharjeel Khan Date: Thu, 30 Jul 2026 22:38:29 +0000 Subject: [PATCH 10/33] Fix unused variable warning in gfxstream Mark static variable sEgl2Egl as [[maybe_unused]] to fix -Wunused-but-set-global warning in Android builds. TAG=agy CONV=b9bc84d8-2e07-4da5-85e0-cfcaabb1f25b Bug: 540570071 Test: none Flag: EXEMPT bugfix Change-Id: I100646d242250b828ad1e27d68fa593aaad5505a --- host/gl/glestranslator/egl/egl_global_info.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/host/gl/glestranslator/egl/egl_global_info.cpp b/host/gl/glestranslator/egl/egl_global_info.cpp index 03acc2259..7056a7920 100644 --- a/host/gl/glestranslator/egl/egl_global_info.cpp +++ b/host/gl/glestranslator/egl/egl_global_info.cpp @@ -25,7 +25,7 @@ namespace { -static EGLBoolean sEgl2Egl = false; +[[maybe_unused]] static EGLBoolean sEgl2Egl = false; static EglGlobalInfo* sSingleton(bool nullEgl = false) { static EglGlobalInfo* i = new EglGlobalInfo(nullEgl); From 4b083b83bf7a40a19a6943fda9232d28cc086fee Mon Sep 17 00:00:00 2001 From: Jason Macnak Date: Thu, 23 Jul 2026 11:07:13 -0700 Subject: [PATCH 11/33] Introduce ColorBuffer interface ... and replace existing ColorBuffer with ColorBufferCoordinator which implements ColorBuffer. This new interface does not depend on either of the GL or VK implementations which will allow us to decouple and remove the circular dependencies between the GL and VK backends and the main host server. Bug: 537737772 Test: bazel test //host/... Low-Coverage-Reason: REFACTOR_ONLY Change-Id: If7e42959acbeb74c8ffcaead0c3930dd8dea9640 --- host/color_buffer.cpp | 96 +++++++++---------- host/color_buffer.h | 63 +++++------- .../gfxstream/host/color_buffer_interface.h | 54 +++++++++++ host/frame_buffer.cpp | 76 +++++++++------ host/frame_buffer.h | 10 +- host/frame_buffer_unittest.cpp | 6 +- host/gl/display_gl.cpp | 21 ++-- host/gl/display_gl.h | 32 +++---- host/gl/emulated_egl_window_surface.cpp | 20 ++-- host/gl/emulated_egl_window_surface.h | 20 ++-- host/gl/emulation_gl.cpp | 7 +- host/gl/emulation_gl.h | 16 ++-- host/gl/readback_worker_gl.cpp | 20 ++-- host/gl/readback_worker_gl.h | 11 +-- host/post_commands.h | 1 + host/post_worker.cpp | 6 +- host/post_worker.h | 7 +- host/post_worker_gl.cpp | 6 +- host/post_worker_gl.h | 4 +- host/readback_worker.h | 9 +- host/vulkan/post_worker_vk.cpp | 8 +- host/vulkan/post_worker_vk.h | 2 +- 22 files changed, 276 insertions(+), 219 deletions(-) create mode 100644 host/common/include/gfxstream/host/color_buffer_interface.h diff --git a/host/color_buffer.cpp b/host/color_buffer.cpp index e150110de..455fa5802 100644 --- a/host/color_buffer.cpp +++ b/host/color_buffer.cpp @@ -45,16 +45,11 @@ bool shouldAttemptExternalMemorySharing(GfxstreamFormat format) { class ColorBuffer::Impl : public LazySnapshotObj { public: - static std::unique_ptr create(gl::EmulationGl* emulationGl, - vk::VkEmulation* emulationVk, - uint32_t width, - uint32_t height, - GfxstreamFormat format, - HandleType handle, - gfxstream::Stream* stream = nullptr); - - static std::unique_ptr onLoad(gl::EmulationGl* emulationGl, - vk::VkEmulation* emulationVk, + static std::unique_ptr create(gl::EmulationGl* emulationGl, vk::VkEmulation* emulationVk, + uint32_t width, uint32_t height, GfxstreamFormat format, + HandleType handle, gfxstream::Stream* stream = nullptr); + + static std::unique_ptr onLoad(gl::EmulationGl* emulationGl, vk::VkEmulation* emulationVk, gfxstream::Stream* stream); void onSave(gfxstream::Stream* stream); @@ -88,6 +83,16 @@ class ColorBuffer::Impl : public LazySnapshotObj { std::optional exportBlob(); + gl::ColorBufferGl* getColorBufferGl() const { +#if GFXSTREAM_ENABLE_HOST_GLES + return mColorBufferGl.get(); +#else + return nullptr; +#endif + } + + vk::ColorBufferVk* getColorBufferVk() const { return mColorBufferVk.get(); } + #if GFXSTREAM_ENABLE_HOST_GLES bool canUseGlOps(); bool glOpBlitFromCurrentReadBuffer(); @@ -128,10 +133,7 @@ class ColorBuffer::Impl : public LazySnapshotObj { }; ColorBuffer::Impl::Impl(HandleType handle, uint32_t width, uint32_t height, GfxstreamFormat format) - : mHandle(handle), - mWidth(width), - mHeight(height), - mFormat(format) {} + : mHandle(handle), mWidth(width), mHeight(height), mFormat(format) {} /*static*/ std::unique_ptr ColorBuffer::Impl::create( @@ -183,15 +185,14 @@ std::unique_ptr ColorBuffer::Impl::create( #if GFXSTREAM_ENABLE_HOST_GLES bool vkSnapshotEnabled = emulationVk && emulationVk->getFeatures().VulkanSnapshots.enabled(); - if ((!stream || vkSnapshotEnabled) && colorBuffer->mColorBufferGl && colorBuffer->mColorBufferVk && - shouldAttemptExternalMemorySharing(format)) { + if ((!stream || vkSnapshotEnabled) && colorBuffer->mColorBufferGl && + colorBuffer->mColorBufferVk && shouldAttemptExternalMemorySharing(format)) { colorBuffer->touch(); auto memoryExport = emulationVk->exportColorBufferMemory(handle); if (memoryExport) { if (colorBuffer->mColorBufferGl->importMemory( - memoryExport->handleInfo.toManagedDescriptor(), - memoryExport->size, memoryExport->dedicatedAllocation, - memoryExport->linearTiling)) { + memoryExport->handleInfo.toManagedDescriptor(), memoryExport->size, + memoryExport->dedicatedAllocation, memoryExport->linearTiling)) { colorBuffer->mGlAndVkAreSharingExternalMemory = true; } else { GFXSTREAM_ERROR("Failed to import memory to ColorBufferGl:%d", handle); @@ -219,8 +220,8 @@ std::unique_ptr ColorBuffer::Impl::onLoad(gl::EmulationGl* em const auto height = static_cast(stream->getBe32()); const auto format = static_cast(stream->getBe32()); - std::unique_ptr colorBuffer = Impl::create(emulationGl, emulationVk, width, height, - format, handle, stream); + std::unique_ptr colorBuffer = + Impl::create(emulationGl, emulationVk, width, height, format, handle, stream); return colorBuffer; } @@ -251,14 +252,9 @@ void ColorBuffer::Impl::restore() { #endif } -void ColorBuffer::Impl::readToBytes( - int x, - int y, - int width, - int height, - GfxstreamFormat pixelsFormat, - void* outPixels, - uint64_t outPixelsSize) { +void ColorBuffer::Impl::readToBytes(int x, int y, int width, int height, + GfxstreamFormat pixelsFormat, void* outPixels, + uint64_t outPixelsSize) { touch(); #if GFXSTREAM_ENABLE_HOST_GLES @@ -283,14 +279,15 @@ void ColorBuffer::Impl::readToBytesScaled( #if GFXSTREAM_ENABLE_HOST_GLES if (mColorBufferGl) { - mColorBufferGl->readPixelsScaled(pixelsWidth, pixelsHeight, pixelsRotation, - rect, pixelsFormat, outPixels, colorTransform); + mColorBufferGl->readPixelsScaled(pixelsWidth, pixelsHeight, pixelsRotation, rect, + pixelsFormat, outPixels, colorTransform); return; } #endif if (mColorBufferVk) { - mColorBufferVk->readPixelsScaled(pixelsWidth, pixelsHeight, pixelsRotation, rect, pixelsFormat, outPixels, colorTransform); + mColorBufferVk->readPixelsScaled(pixelsWidth, pixelsHeight, pixelsRotation, rect, + pixelsFormat, outPixels, colorTransform); return; } @@ -316,8 +313,9 @@ void ColorBuffer::Impl::readYuvToBytes(int x, int y, int width, int height, void GFXSTREAM_FATAL("%s: No ColorBuffer impl", __func__); } -bool ColorBuffer::Impl::updateFromBytes(int x, int y, int width, int height, GfxstreamFormat pixelsFormat, - const void* pixels, void* metadata) { +bool ColorBuffer::Impl::updateFromBytes(int x, int y, int width, int height, + GfxstreamFormat pixelsFormat, const void* pixels, + void* metadata) { touch(); #if GFXSTREAM_ENABLE_HOST_GLES @@ -513,9 +511,7 @@ std::optional ColorBuffer::Impl::exportBlob() { } #if GFXSTREAM_ENABLE_HOST_GLES -bool ColorBuffer::Impl::canUseGlOps() { - return (mColorBufferGl != nullptr); -} +bool ColorBuffer::Impl::canUseGlOps() { return (mColorBufferGl != nullptr); } bool ColorBuffer::Impl::glOpBlitFromCurrentReadBuffer() { if (!mColorBufferGl) { @@ -618,7 +614,7 @@ bool ColorBuffer::Impl::glOpIsFastBlitSupported() const { } bool ColorBuffer::Impl::glOpPostLayer(const ComposeLayer& l, int frameWidth, int frameHeight, - const std::optional>& colorTransform) { + const std::optional>& colorTransform) { if (!mColorBufferGl) { GFXSTREAM_ERROR("%s: ColorBufferGl not available", __func__); return false; @@ -645,16 +641,13 @@ bool ColorBuffer::Impl::glOpPostViewportScaledWithOverlay( /*static*/ std::shared_ptr ColorBuffer::create(gl::EmulationGl* emulationGl, - vk::VkEmulation* emulationVk, - uint32_t width, - uint32_t height, - GfxstreamFormat format, - HandleType handle, - gfxstream::Stream* stream) { + vk::VkEmulation* emulationVk, uint32_t width, + uint32_t height, GfxstreamFormat format, + HandleType handle, gfxstream::Stream* stream) { std::shared_ptr colorbuffer(new ColorBuffer()); - colorbuffer->mImpl = ColorBuffer::Impl::create(emulationGl, emulationVk, width, height, format, - handle, stream); + colorbuffer->mImpl = + ColorBuffer::Impl::create(emulationGl, emulationVk, width, height, format, handle, stream); if (!colorbuffer->mImpl) { return nullptr; } @@ -681,8 +674,14 @@ void ColorBuffer::onSave(gfxstream::Stream* stream) { mImpl->onSave(stream); } void ColorBuffer::restore() { mImpl->touch(); } +void ColorBuffer::touch() { mImpl->touch(); } + HandleType ColorBuffer::getHndl() const { return mImpl->getHndl(); } +gl::ColorBufferGl* ColorBuffer::getColorBufferGl() { return mImpl->getColorBufferGl(); } + +vk::ColorBufferVk* ColorBuffer::getColorBufferVk() { return mImpl->getColorBufferVk(); } + uint32_t ColorBuffer::getWidth() const { return mImpl->getWidth(); } uint32_t ColorBuffer::getHeight() const { return mImpl->getHeight(); } @@ -706,8 +705,7 @@ void ColorBuffer::readYuvToBytes(int x, int y, int width, int height, void* outP mImpl->readYuvToBytes(x, y, width, height, outPixels, outPixelsSize); } -bool ColorBuffer::updateFromBytes(int x, int y, int width, int height, - GfxstreamFormat pixelsFormat, +bool ColorBuffer::updateFromBytes(int x, int y, int width, int height, GfxstreamFormat pixelsFormat, const void* pixels, void* metadata) { return mImpl->updateFromBytes(x, y, width, height, pixelsFormat, pixels, metadata); } @@ -769,7 +767,7 @@ bool ColorBuffer::glOpSwapYuvTexturesAndUpdate(GLenum format, GLenum type, bool ColorBuffer::glOpIsFastBlitSupported() const { return mImpl->glOpIsFastBlitSupported(); } bool ColorBuffer::glOpPostLayer(const ComposeLayer& l, int frameWidth, int frameHeight, - const std::optional>& colorTransform) { + const std::optional>& colorTransform) { return mImpl->glOpPostLayer(l, frameWidth, frameHeight, colorTransform); } diff --git a/host/color_buffer.h b/host/color_buffer.h index 8d38af36d..4fdc712a1 100644 --- a/host/color_buffer.h +++ b/host/color_buffer.h @@ -24,6 +24,7 @@ #include "framework_formats.h" #include "gfxstream/host/borrowed_image.h" +#include "gfxstream/host/color_buffer_interface.h" #include "gfxstream/host/external_object_manager.h" #include "gfxstream/host/gfxstream_format.h" #include "handle.h" @@ -51,42 +52,37 @@ class VkEmulation; namespace gfxstream { namespace host { -class ColorBuffer : public LazySnapshotObj { +class ColorBuffer : public IColorBuffer, public LazySnapshotObj { public: static std::shared_ptr create(gl::EmulationGl* emulationGl, - vk::VkEmulation* emulationVk, - uint32_t width, - uint32_t height, - GfxstreamFormat format, - HandleType handle, - Stream* stream = nullptr); + vk::VkEmulation* emulationVk, uint32_t width, + uint32_t height, GfxstreamFormat format, + HandleType handle, Stream* stream = nullptr); static std::shared_ptr onLoad(gl::EmulationGl* emulationGl, - vk::VkEmulation* emulationVk, - Stream* stream); + vk::VkEmulation* emulationVk, Stream* stream); void onSave(Stream* stream); void restore(); + void touch() override; - HandleType getHndl() const; - uint32_t getWidth() const; - uint32_t getHeight() const; + gl::ColorBufferGl* getColorBufferGl() override; + vk::ColorBufferVk* getColorBufferVk() override; + + HandleType getHndl() const override; + uint32_t getWidth() const override; + uint32_t getHeight() const override; GfxstreamFormat getFormat() const; - void readToBytes(int x, int y, int width, int height, - GfxstreamFormat pixelsFormat, + void readToBytes(int x, int y, int width, int height, GfxstreamFormat pixelsFormat, void* outPixels, uint64_t outPixelsSize); void readToBytesScaled(int pixelsWidth, int pixelsHeight, int pixelsRotation, const Rect& rect, GfxstreamFormat pixelsFormat, void* outPixels, const std::optional>& colorTransform); - void readYuvToBytes(int x, int y, int width, int height, void* outPixels, uint32_t outPixelsSize); - - bool updateFromBytes(int x, - int y, - int width, - int height, - GfxstreamFormat pixelsFormat, - const void* pixels, - void* metadata = nullptr); + void readYuvToBytes(int x, int y, int width, int height, void* outPixels, + uint32_t outPixelsSize); + + bool updateFromBytes(int x, int y, int width, int height, GfxstreamFormat pixelsFormat, + const void* pixels, void* metadata = nullptr); bool updateGlFromBytes(const void* bytes, std::size_t bytesSize); enum class UsedApi { @@ -117,7 +113,7 @@ class ColorBuffer : public LazySnapshotObj { GLuint* textures); bool glOpIsFastBlitSupported() const; bool glOpPostLayer(const ComposeLayer& l, int frameWidth, int frameHeight, - const std::optional>& colorTransform); + const std::optional>& colorTransform); bool glOpPostViewportScaledWithOverlay( float rotation, float dx, float dy, float scaleX, float scaleY, const std::optional>& colorTransform); @@ -130,24 +126,9 @@ class ColorBuffer : public LazySnapshotObj { std::unique_ptr mImpl; }; -typedef std::shared_ptr ColorBufferPtr; - -struct ColorBufferRef { - ColorBufferPtr cb; - uint32_t refcount; // number of client-side references - - // Tracks whether opened at least once. In O+, - // color buffers can be created/closed immediately, - // but then registered (opened) afterwards. - bool opened; - - // Tracks the time when this buffer got a close request while not being - // opened yet. - uint64_t closedTs; -}; +using ColorBufferPtr = std::shared_ptr; -typedef std::unordered_map ColorBufferMap; -typedef std::unordered_multiset ColorBufferSet; +using ColorBufferSet = std::unordered_multiset; } // namespace host } // namespace gfxstream diff --git a/host/common/include/gfxstream/host/color_buffer_interface.h b/host/common/include/gfxstream/host/color_buffer_interface.h new file mode 100644 index 000000000..5b8246dff --- /dev/null +++ b/host/common/include/gfxstream/host/color_buffer_interface.h @@ -0,0 +1,54 @@ +// Copyright 2026 The Android Open Source Project +// +// 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 expresso or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +namespace gfxstream { +namespace host { + +namespace gl { +class ColorBufferGl; +} // namespace gl + +namespace vk { +class ColorBufferVk; +} // namespace vk + +// A (mostly) generic interface to a `ColorBuffer` so that the various backends +// interact with `ColorBuffer`s without needing to depend on all of the various +// underlying `ColorBuffer` implementations. +class IColorBuffer { + public: + virtual ~IColorBuffer() = default; + + virtual uint32_t getHndl() const = 0; + virtual uint32_t getWidth() const = 0; + virtual uint32_t getHeight() const = 0; + + virtual void touch() = 0; + + virtual gl::ColorBufferGl* getColorBufferGl() = 0; + virtual vk::ColorBufferVk* getColorBufferVk() = 0; +}; + +// A (mostly) generic shared owning reference to a `ColorBuffer` so that the +// various backends can have shared ownership of a `ColorBuffer` without needed +// to depend on the underlying `ColorBuffer` implementations. +using IColorBufferRef = std::shared_ptr; + +} // namespace host +} // namespace gfxstream diff --git a/host/frame_buffer.cpp b/host/frame_buffer.cpp index 579679079..65f88873e 100644 --- a/host/frame_buffer.cpp +++ b/host/frame_buffer.cpp @@ -345,6 +345,13 @@ typedef std::unordered_map ProcOwnedEmulate typedef std::unordered_map ProcOwnedEmulatedEGLImages; #endif // GFXSTREAM_ENABLE_HOST_GLES +struct ReferenceCountedColorBuffer { + ColorBufferPtr cb; + uint32_t refcount; // number of client-side references + bool opened; + uint64_t closedTs; +}; + typedef std::unordered_map BufferMap; typedef std::unordered_multiset BufferSet; typedef std::unordered_map ProcOwnedBuffers; @@ -493,7 +500,8 @@ class FrameBuffer::Impl : public gfxstream::base::EventNotificationSupport cleanupProcGLObjects_locked(uint64_t puid, bool forced = false); - void markOpened(ColorBufferRef* cbRef); + void markOpened(ReferenceCountedColorBuffer* cbRef); // Returns true if the color buffer was erased. bool closeColorBufferLocked(HandleType p_colorbuffer, bool forced = false); // Returns true if this was the last ref and we need to destroy stuff. @@ -862,7 +870,7 @@ class FrameBuffer::Impl : public gfxstream::base::EventNotificationSupport m_colorbuffers; BufferMap m_buffers; // A collection of color buffers that were closed without any usages @@ -2163,13 +2171,14 @@ bool FrameBuffer::Impl::createColorBufferWithResourceHandleLocked(int p_width, i // Explicitly set refcount to 1 to avoid the colorbuffer being added to // m_colorBufferDelayedCloseList in FrameBuffer::Impl::onLoad(). if (m_refCountPipeEnabled) { - m_colorbuffers.try_emplace(handle, ColorBufferRef{std::move(cb), 1, false, 0}); + m_colorbuffers.try_emplace(handle, ReferenceCountedColorBuffer{std::move(cb), 1, false, 0}); } else { const int apiLevel = get_gfxstream_guest_android_api_level(); // pre-O and post-O use different color buffer memory management // logic if (apiLevel > 0 && apiLevel < 26) { - m_colorbuffers.try_emplace(handle, ColorBufferRef{std::move(cb), 1, false, 0}); + m_colorbuffers.try_emplace(handle, + ReferenceCountedColorBuffer{std::move(cb), 1, false, 0}); RenderThreadInfo* tInfo = RenderThreadInfo::get(); uint64_t puid = tInfo->m_puid; @@ -2178,7 +2187,8 @@ bool FrameBuffer::Impl::createColorBufferWithResourceHandleLocked(int p_width, i } } else { - m_colorbuffers.try_emplace(handle, ColorBufferRef{std::move(cb), 0, false, 0}); + m_colorbuffers.try_emplace(handle, + ReferenceCountedColorBuffer{std::move(cb), 0, false, 0}); } } @@ -2230,10 +2240,9 @@ int FrameBuffer::Impl::openColorBuffer(HandleType p_colorbuffer) { AutoLock mutex(m_lock); - ColorBufferMap::iterator c; { AutoLock colorBuffermapLock(m_colorBufferMapLock); - c = m_colorbuffers.find(p_colorbuffer); + auto c = m_colorbuffers.find(p_colorbuffer); if (c == m_colorbuffers.end()) { // bad colorbuffer handle GFXSTREAM_ERROR("FB: openColorBuffer cb handle %d not found", p_colorbuffer); @@ -2305,7 +2314,7 @@ bool FrameBuffer::Impl::closeColorBufferLocked(HandleType p_colorbuffer, bool fo if (m_noDelayCloseColorBufferEnabled) forced = true; - ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer)); + auto c = m_colorbuffers.find(p_colorbuffer); if (c == m_colorbuffers.end()) { // This is harmless: it is normal for guest system to issue // closeColorBuffer command when the color buffer is already @@ -2340,7 +2349,7 @@ bool FrameBuffer::Impl::closeColorBufferLocked(HandleType p_colorbuffer, bool fo void FrameBuffer::Impl::decColorBufferRefCountNoDestroy(HandleType p_colorbuffer) { AutoLock colorBufferMapLock(m_colorBufferMapLock); - ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer)); + auto c = m_colorbuffers.find(p_colorbuffer); if (c == m_colorbuffers.end()) { return; } @@ -2545,7 +2554,7 @@ std::vector FrameBuffer::Impl::cleanupProcGLObjects_locked(uint64_t return colorBuffersToCleanup; } -void FrameBuffer::Impl::markOpened(ColorBufferRef* cbRef) { +void FrameBuffer::Impl::markOpened(ReferenceCountedColorBuffer* cbRef) { cbRef->opened = true; eraseDelayedCloseColorBufferLocked(cbRef->cb->getHndl(), cbRef->closedTs); cbRef->closedTs = 0; @@ -2713,7 +2722,7 @@ AsyncResult FrameBuffer::Impl::postImpl(HandleType p_colorbuffer, Post::Completi ColorBufferPtr colorBuffer = nullptr; { AutoLock colorBufferMapLock(m_colorBufferMapLock); - ColorBufferMap::iterator c = m_colorbuffers.find(p_colorbuffer); + auto c = m_colorbuffers.find(p_colorbuffer); if (c != m_colorbuffers.end()) { colorBuffer = c->second.cb; c->second.refcount++; @@ -3331,13 +3340,14 @@ bool FrameBuffer::Impl::onSave(Stream* stream, const ITextureSaverPtr& textureSa { AutoLock colorBufferMapLock(m_colorBufferMapLock); stream->putByte(m_guestManagedColorBufferLifetime); - saveCollection(stream, m_colorbuffers, - [now](Stream* s, const ColorBufferMap::value_type& pair) { - pair.second.cb->onSave(s); - s->putBe32(pair.second.refcount); - s->putByte(pair.second.opened); - s->putBe32(std::max(0, now - pair.second.closedTs)); - }); + saveCollection(stream, m_colorbuffers, [now](Stream* s, const auto& pair) { + auto cb = pair.second.cb; + assert(cb); + cb->onSave(s); + s->putBe32(pair.second.refcount); + s->putByte(pair.second.opened); + s->putBe32(std::max(0, now - pair.second.closedTs)); + }); } stream->putBe32(m_lastPostedColorBuffer); #if GFXSTREAM_ENABLE_HOST_GLES @@ -3562,7 +3572,8 @@ bool FrameBuffer::Impl::onLoad(Stream* stream, const ITextureLoaderPtr& textureL AutoLock colorBufferMapLock(m_colorBufferMapLock); m_guestManagedColorBufferLifetime = stream->getByte(); loadCollection( - stream, &m_colorbuffers, [this, now](Stream* stream) -> ColorBufferMap::value_type { + stream, &m_colorbuffers, + [this, now](Stream* stream) -> std::pair { ColorBufferPtr cb = ColorBuffer::onLoad(m_emulationGl.get(), m_emulationVk.get(), stream); if (!cb) { @@ -3575,7 +3586,8 @@ bool FrameBuffer::Impl::onLoad(Stream* stream, const ITextureLoaderPtr& textureL if (refCount == 0) { m_colorBufferDelayedCloseList.push_back({closedTs, handle}); } - return {handle, ColorBufferRef{std::move(cb), refCount, opened, closedTs}}; + return {handle, + ReferenceCountedColorBuffer{std::move(cb), refCount, opened, closedTs}}; }); } m_lastPostedColorBuffer = static_cast(stream->getBe32()); @@ -3587,8 +3599,14 @@ bool FrameBuffer::Impl::onLoad(Stream* stream, const ITextureLoaderPtr& textureL loadCollection( stream, &m_windows, [this](Stream* stream) -> EmulatedEglWindowSurfaceMap::value_type { ENSURE_GL_EMULATION_FATAL(); - auto window = - m_emulationGl->loadEmulatedEglWindowSurface(stream, m_colorbuffers, m_contexts); + auto window = m_emulationGl->loadEmulatedEglWindowSurface( + stream, + [this](uint32_t handle) -> IColorBufferRef { + auto it = m_colorbuffers.find(handle); + if (it == m_colorbuffers.end()) return nullptr; + return it->second.cb; + }, + m_contexts); HandleType handle = window->getHndl(); HandleType colorBufferHandle = stream->getBe32(); @@ -3676,11 +3694,11 @@ void FrameBuffer::Impl::unlock() { m_lock.unlock(); } ColorBufferPtr FrameBuffer::Impl::findColorBuffer(HandleType p_colorbuffer) { AutoLock colorBufferMapLock(m_colorBufferMapLock); - ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer)); + auto c = m_colorbuffers.find(p_colorbuffer); if (c == m_colorbuffers.end()) { return nullptr; } else { - return c->second.cb; + return std::dynamic_pointer_cast(c->second.cb); } } @@ -4156,7 +4174,7 @@ bool FrameBuffer::Impl::setEmulatedEglWindowSurfaceColorBuffer(HandleType p_surf { AutoLock colorBufferMapLock(m_colorBufferMapLock); - ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer)); + auto c = m_colorbuffers.find(p_colorbuffer); if (c == m_colorbuffers.end()) { GFXSTREAM_ERROR("bad color buffer handle %d", p_colorbuffer); // bad colorbuffer handle @@ -4234,7 +4252,8 @@ HandleType FrameBuffer::Impl::createEmulatedEglContext(int config, HandleType sh ENSURE_GL_EMULATION_VALUE(0); AutoLock mutex(m_lock); gfxstream::base::AutoWriteLock contextLock(m_contextStructureLock); - // Hold the ColorBuffer map lock so that the new handle won't collide with a ColorBuffer handle. + // Hold the ColorBuffer map lock so that the new handle won't collide with a + // ColorBuffer handle. AutoLock colorBufferMapLock(m_colorBufferMapLock); EmulatedEglContextPtr shareContext = nullptr; @@ -4304,7 +4323,8 @@ HandleType FrameBuffer::Impl::createEmulatedEglWindowSurface(int p_config, int p int p_height) { ENSURE_GL_EMULATION_VALUE(0); AutoLock mutex(m_lock); - // Hold the ColorBuffer map lock so that the new handle won't collide with a ColorBuffer handle. + // Hold the ColorBuffer map lock so that the new handle won't collide with a + // ColorBuffer handle. AutoLock colorBufferMapLock(m_colorBufferMapLock); HandleType handle = genHandle_locked(); diff --git a/host/frame_buffer.h b/host/frame_buffer.h index 71e8bc7de..9f233459e 100644 --- a/host/frame_buffer.h +++ b/host/frame_buffer.h @@ -32,21 +32,21 @@ #include "buffer.h" #include "color_buffer.h" #include "framework_formats.h" -#include "handle.h" -#include "post_commands.h" -#include "vsync_thread.h" #include "gfxstream/AsyncResult.h" #include "gfxstream/EventNotificationSupport.h" -#include "gfxstream/host/process_resources.h" #include "gfxstream/host/borrowed_image.h" #include "gfxstream/host/external_object_manager.h" -#include "gfxstream/host/gl_enums.h" #include "gfxstream/host/gfxstream_format.h" +#include "gfxstream/host/gl_enums.h" +#include "gfxstream/host/process_resources.h" #include "gfxstream/host/vk_enums.h" +#include "handle.h" +#include "post_commands.h" #include "render-utils/Renderer.h" #include "render-utils/render_api.h" #include "render-utils/stream.h" #include "render-utils/virtio_gpu_ops.h" +#include "vsync_thread.h" // values for 'param' argument of rcGetFBParam #define FB_WIDTH 1 diff --git a/host/frame_buffer_unittest.cpp b/host/frame_buffer_unittest.cpp index 775f84e51..5507c5b35 100644 --- a/host/frame_buffer_unittest.cpp +++ b/host/frame_buffer_unittest.cpp @@ -516,7 +516,8 @@ TEST_F(FrameBufferTest, SnapshotSingleColorBuffer) { // bug: 111360779 // Tests that the ColorBuffer is successfully updated even if a reformat happens // on restore; the reformat may mess up the texture restore logic. -// In ColorBuffer::subUpdate, this test is known to fail if touch() is moved after the reformat. +// In ColorBuffer::subUpdate, this test is known to fail if touch() is moved after the +// reformat. TEST_F(FrameBufferTest, SnapshotColorBufferSubUpdateRestore) { HandleType handle = mFb->createColorBuffer(mWidth, mHeight, GfxstreamFormat::R8G8B8A8_UNORM); @@ -741,7 +742,8 @@ TEST_F(FrameBufferTest, CreateColorBufferBGRA) { } // Test ColorBuffer with GL_RGBA, but read back as GL_BGRA, so that R/B are switched. -// TODO: This doesn't work on NVIDIA EGL, it issues GL_INVALID_OPERATION if the format doesn't match. +// TODO: This doesn't work on NVIDIA EGL, it issues GL_INVALID_OPERATION if the format doesn't +// match. TEST_F(FrameBufferTest, DISABLED_ReadColorBufferSwitchRedBlue) { HandleType handle = mFb->createColorBuffer(mWidth, mHeight, GfxstreamFormat::R8G8B8A8_UNORM); diff --git a/host/gl/display_gl.cpp b/host/gl/display_gl.cpp index 39d4746d6..fe046282e 100644 --- a/host/gl/display_gl.cpp +++ b/host/gl/display_gl.cpp @@ -14,12 +14,13 @@ #include "display_gl.h" -#include "display_surface_gl.h" #include "OpenGLESDispatch/DispatchTables.h" #include "OpenGLESDispatch/EGLDispatch.h" -#include "texture_draw.h" +#include "color_buffer_gl.h" +#include "display_surface_gl.h" #include "gfxstream/common/logging.h" #include "gfxstream/host/display_operations.h" +#include "texture_draw.h" namespace gfxstream { namespace host { @@ -48,23 +49,25 @@ std::shared_future DisplayGl::post(const Post& post) { bool hasDrawLayer = false; for (const PostLayer& layer : post.layers) { + if (!layer.colorBuffer) continue; + auto cbGl = layer.colorBuffer->getColorBufferGl(); + if (!cbGl) continue; + if (layer.layerOptions) { if (!hasDrawLayer) { mTextureDraw->prepareForDrawLayer(); hasDrawLayer = true; } - layer.colorBuffer->glOpPostLayer(*layer.layerOptions, post.frameWidth, - post.frameHeight, post.colorTransform); + cbGl->postLayer(*layer.layerOptions, post.frameWidth, post.frameHeight, + post.colorTransform); } else if (layer.overlayOptions) { if (hasDrawLayer) { GFXSTREAM_ERROR("Cannot mix colorBuffer.postLayer with postWithOverlay!"); } - layer.colorBuffer->glOpPostViewportScaledWithOverlay( - layer.overlayOptions->rotation, - layer.overlayOptions->dx, layer.overlayOptions->dy, - layer.overlayOptions->scaleX, layer.overlayOptions->scaleY, - layer.colorTransform); + cbGl->postViewportScaledWithOverlay( + layer.overlayOptions->rotation, layer.overlayOptions->dx, layer.overlayOptions->dy, + layer.overlayOptions->scaleX, layer.overlayOptions->scaleY, layer.colorTransform); } } if (hasDrawLayer) { diff --git a/host/gl/display_gl.h b/host/gl/display_gl.h index e363fea8c..739dfb4b4 100644 --- a/host/gl/display_gl.h +++ b/host/gl/display_gl.h @@ -22,10 +22,10 @@ #include #include -#include "color_buffer.h" +#include "gfxstream/host/color_buffer_interface.h" +#include "gfxstream/host/display.h" #include "hwc2.h" #include "texture_draw.h" -#include "gfxstream/host/display.h" namespace gfxstream { namespace host { @@ -37,20 +37,20 @@ class DisplayGl : public Display { ~DisplayGl() {} struct PostLayer { - ColorBuffer* colorBuffer = nullptr; - - std::optional layerOptions; - - // TODO: This should probably be removed and TextureDraw should - // only use drawLayer() but this is currently needed to support - // existing draw paths without depending on FrameBuffer directly. - struct OverlayOptions { - float rotation = 0.0f; - float dx = 0.0f; - float dy = 0.0f; - float scaleX = 1.0f; - float scaleY = 1.0f; - }; + IColorBuffer* colorBuffer = nullptr; + + std::optional layerOptions; + + // TODO: This should probably be removed and TextureDraw should + // only use drawLayer() but this is currently needed to support + // existing draw paths without depending on FrameBuffer directly. + struct OverlayOptions { + float rotation = 0.0f; + float dx = 0.0f; + float dy = 0.0f; + float scaleX = 1.0f; + float scaleY = 1.0f; + }; std::optional overlayOptions; const std::optional> colorTransform; diff --git a/host/gl/emulated_egl_window_surface.cpp b/host/gl/emulated_egl_window_surface.cpp index 3759e25dd..34ed7cfc3 100644 --- a/host/gl/emulated_egl_window_surface.cpp +++ b/host/gl/emulated_egl_window_surface.cpp @@ -61,7 +61,7 @@ std::unique_ptr EmulatedEglWindowSurface::create( return surface; } -void EmulatedEglWindowSurface::setColorBuffer(ColorBufferPtr p_colorBuffer) { +void EmulatedEglWindowSurface::setColorBuffer(IColorBufferRef p_colorBuffer) { mAttachedColorBuffer = p_colorBuffer; if (!p_colorBuffer) return; @@ -131,7 +131,11 @@ bool EmulatedEglWindowSurface::flushColorBuffer() { } } - mAttachedColorBuffer->glOpBlitFromCurrentReadBuffer(); + mAttachedColorBuffer->touch(); + auto cbGl = mAttachedColorBuffer->getColorBufferGl(); + if (cbGl) { + cbGl->blitFromCurrentReadBuffer(); + } if (needToSet) { // restore current context/surface @@ -224,10 +228,9 @@ void EmulatedEglWindowSurface::onSave(gfxstream::Stream* stream) const { } std::unique_ptr EmulatedEglWindowSurface::onLoad( - gfxstream::Stream* stream, - EGLDisplay display, - const ColorBufferMap& colorBuffers, - const EmulatedEglContextMap& contexts) { + gfxstream::Stream* stream, EGLDisplay display, + const std::function& colorBufferLookup, + const EmulatedEglContextMap& contexts) { HandleType hndl = stream->getBe32(); HandleType colorBufferHndl = stream->getBe32(); HandleType readCtx = stream->getBe32(); @@ -244,9 +247,8 @@ std::unique_ptr EmulatedEglWindowSurface::onLoad( assert(surface); // fb is already locked by its caller if (colorBufferHndl) { - const auto* colorBufferRef = gfxstream::base::find(colorBuffers, colorBufferHndl); - assert(colorBufferRef); - surface->mAttachedColorBuffer = colorBufferRef->cb; + surface->mAttachedColorBuffer = colorBufferLookup(colorBufferHndl); + assert(surface->mAttachedColorBuffer); } surface->mReadContext = gfxstream::base::findOrDefault(contexts, readCtx); surface->mDrawContext = gfxstream::base::findOrDefault(contexts, drawCtx); diff --git a/host/gl/emulated_egl_window_surface.h b/host/gl/emulated_egl_window_surface.h index bdab48470..197bde013 100644 --- a/host/gl/emulated_egl_window_surface.h +++ b/host/gl/emulated_egl_window_surface.h @@ -19,14 +19,15 @@ #include #include +#include #include #include #include -#include "color_buffer.h" -#include "handle.h" +#include "gfxstream/host/color_buffer_interface.h" #include "gl/color_buffer_gl.h" #include "gl/emulated_egl_context.h" +#include "handle.h" namespace gfxstream { namespace host { @@ -60,12 +61,10 @@ class EmulatedEglWindowSurface { // // IMPORTANT: This automatically resizes the Pbuffer's to the ColorBuffer's // dimensions. Potentially losing pixel values in the process. - void setColorBuffer(ColorBufferPtr p_colorBuffer); + void setColorBuffer(IColorBufferRef p_colorBuffer); // Retrieves a pointer to the attached color buffer. - ColorBuffer* getAttachedColorBuffer() const { - return mAttachedColorBuffer.get(); - } + IColorBuffer* getAttachedColorBuffer() const { return mAttachedColorBuffer.get(); } // Copy the Pbuffer's pixels to the attached color buffer. // Returns true on success, or false on error (e.g. if there is no @@ -99,10 +98,9 @@ class EmulatedEglWindowSurface { void onSave(gfxstream::Stream* stream) const; static std::unique_ptr onLoad( - gfxstream::Stream* stream, - EGLDisplay display, - const ColorBufferMap& colorBuffers, - const EmulatedEglContextMap& contexts); + gfxstream::Stream* stream, EGLDisplay display, + const std::function& colorBufferLookup, + const EmulatedEglContextMap& contexts); HandleType getHndl() const; @@ -114,7 +112,7 @@ class EmulatedEglWindowSurface { bool resize(unsigned int p_width, unsigned int p_height); EGLSurface mSurface = EGL_NO_SURFACE; - ColorBufferPtr mAttachedColorBuffer; + IColorBufferRef mAttachedColorBuffer; EmulatedEglContextPtr mReadContext; EmulatedEglContextPtr mDrawContext; GLuint mWidth = 0; diff --git a/host/gl/emulation_gl.cpp b/host/gl/emulation_gl.cpp index b25ee0293..ef96d9570 100644 --- a/host/gl/emulation_gl.cpp +++ b/host/gl/emulation_gl.cpp @@ -849,10 +849,9 @@ std::unique_ptr EmulationGl::createEmulatedEglWindowSu } std::unique_ptr EmulationGl::loadEmulatedEglWindowSurface( - gfxstream::Stream* stream, - const ColorBufferMap& colorBuffers, - const EmulatedEglContextMap& contexts) { - return EmulatedEglWindowSurface::onLoad(stream, mEglDisplay, colorBuffers, contexts); + gfxstream::Stream* stream, const std::function& colorBufferLookup, + const EmulatedEglContextMap& contexts) { + return EmulatedEglWindowSurface::onLoad(stream, mEglDisplay, colorBufferLookup, contexts); } } // namespace gl diff --git a/host/gl/emulation_gl.h b/host/gl/emulation_gl.h index 62f5fd159..27af2c61b 100644 --- a/host/gl/emulation_gl.h +++ b/host/gl/emulation_gl.h @@ -20,11 +20,14 @@ #include #include +#include #include #include #include #include +#include "OpenGLESDispatch/EGLDispatch.h" +#include "OpenGLESDispatch/GLESv2Dispatch.h" #include "buffer_gl.h" #include "color_buffer_gl.h" #include "compositor.h" @@ -36,17 +39,15 @@ #include "emulated_egl_fence_sync.h" #include "emulated_egl_image.h" #include "emulated_egl_window_surface.h" -#include "OpenGLESDispatch/EGLDispatch.h" -#include "OpenGLESDispatch/GLESv2Dispatch.h" -#include "pixel_read_formats.h" -#include "readback_worker_gl.h" -#include "texture_draw.h" -#include "gfxstream/host/features.h" #include "gfxstream/host/display.h" #include "gfxstream/host/display_surface.h" +#include "gfxstream/host/features.h" #include "gfxstream/host/gfxstream_format.h" #include "gfxstream/host/gl_enums.h" +#include "pixel_read_formats.h" +#include "readback_worker_gl.h" #include "render-utils/stream.h" +#include "texture_draw.h" #define EGL_NO_CONFIG ((EGLConfig)0) @@ -148,8 +149,7 @@ class EmulationGl { HandleType handle); std::unique_ptr loadEmulatedEglWindowSurface( - Stream* stream, - const ColorBufferMap& colorBuffers, + Stream* stream, const std::function& colorBufferLookup, const EmulatedEglContextMap& contexts); std::unique_ptr createFakeWindowSurface(); diff --git a/host/gl/readback_worker_gl.cpp b/host/gl/readback_worker_gl.cpp index 073691f94..ead29fbd9 100644 --- a/host/gl/readback_worker_gl.cpp +++ b/host/gl/readback_worker_gl.cpp @@ -17,11 +17,11 @@ #include -#include "color_buffer.h" -#include "context_helper.h" #include "OpenGLESDispatch/DispatchTables.h" #include "OpenGLESDispatch/EGLDispatch.h" #include "OpenGLESDispatch/GLESv2Dispatch.h" +#include "color_buffer.h" +#include "context_helper.h" #include "gfxstream/common/logging.h" #include "gl/color_buffer_gl.h" @@ -87,12 +87,10 @@ void ReadbackWorkerGl::deinitReadbackForDisplay(uint32_t displayId) { mTrackedDisplays.erase(it); } -ReadbackWorkerGl::DoNextReadbackResult -ReadbackWorkerGl::doNextReadback(uint32_t displayId, - ColorBuffer* cb, - void* fbImage, - bool repaint, - bool readbackBgra) { +ReadbackWorkerGl::DoNextReadbackResult ReadbackWorkerGl::doNextReadback(uint32_t displayId, + IColorBuffer* cb, + void* fbImage, bool repaint, + bool readbackBgra) { // if |repaint|, make sure that the current frame is immediately sent down // the pipeline and made available to the consumer by priming async // readback; doing 4 consecutive reads in a row, which should be enough to @@ -161,7 +159,11 @@ ReadbackWorkerGl::doNextReadback(uint32_t displayId, r.m_readbackCount++; r.mPrevReadPixelsIndex = readAt; - cb->glOpReadbackAsync(r.mBuffers[readAt], readbackBgra); + cb->touch(); + auto cbGl = cb->getColorBufferGl(); + if (cbGl) { + cbGl->readbackAsync(r.mBuffers[readAt], readbackBgra); + } // It's possible to post callback before any of the async readbacks // have written any data yet, which results in a black frame. Safer diff --git a/host/gl/readback_worker_gl.h b/host/gl/readback_worker_gl.h index 0e8794711..46a139f5c 100644 --- a/host/gl/readback_worker_gl.h +++ b/host/gl/readback_worker_gl.h @@ -28,7 +28,9 @@ #include "readback_worker.h" namespace gfxstream { -class ColorBuffer; +namespace host { +class IColorBuffer; +} // namespace host } // namespace gfxstream namespace gfxstream { @@ -59,11 +61,8 @@ class ReadbackWorkerGl : public ReadbackWorker { // |readbackBgra|: Whether to force the readback format as GL_BGRA_EXT, // so that we get (depending on driver quality, heh) a gpu conversion of the // readback image that is suitable for webrtc, which expects formats like that. - DoNextReadbackResult doNextReadback(uint32_t displayId, - ColorBuffer* cb, - void* fbImage, - bool repaint, - bool readbackBgra) override; + DoNextReadbackResult doNextReadback(uint32_t displayId, IColorBuffer* cb, void* fbImage, + bool repaint, bool readbackBgra) override; // getPixels(): Run this on a separate GL thread. This retrieves the // latest framebuffer that has been posted and read with doNextReadback. diff --git a/host/post_commands.h b/host/post_commands.h index 05b8c6b06..206880b89 100644 --- a/host/post_commands.h +++ b/host/post_commands.h @@ -29,6 +29,7 @@ namespace gfxstream { namespace host { +class IColorBuffer; class ColorBuffer; // Posting diff --git a/host/post_worker.cpp b/host/post_worker.cpp index 53041dcd3..bad7d15c1 100644 --- a/host/post_worker.cpp +++ b/host/post_worker.cpp @@ -21,10 +21,10 @@ #include "color_buffer.h" #include "frame_buffer.h" -#include "render_thread_info.h" #include "gfxstream/Tracing.h" #include "gfxstream/common/logging.h" #include "gfxstream/host/window_operations.h" +#include "render_thread_info.h" #include "vulkan/vk_common_operations.h" namespace gfxstream { @@ -92,8 +92,8 @@ void PostWorker::block(std::promise scheduledSignal, std::future con PostWorker::~PostWorker() {} -void PostWorker::post(ColorBuffer* cb, std::unique_ptr postCallback, - const std::optional>& colorTransform) { +void PostWorker::post(IColorBuffer* cb, std::unique_ptr postCallback, + const std::optional>& colorTransform) { auto packagedPostCallback = std::shared_ptr(std::move(postCallback)); runTask( std::packaged_task([cb, packagedPostCallback, this, colorTransform] { diff --git a/host/post_worker.h b/host/post_worker.h index a8c2cdb17..0f4c53fb7 100644 --- a/host/post_worker.h +++ b/host/post_worker.h @@ -30,6 +30,7 @@ namespace gfxstream { namespace host { +class IColorBuffer; class ColorBuffer; class FrameBuffer; struct RenderThreadInfo; @@ -41,7 +42,7 @@ class PostWorker { // post: posts the next color buffer. // Assumes framebuffer lock is held. - void post(ColorBuffer* cb, std::unique_ptr postCallback, + void post(IColorBuffer* cb, std::unique_ptr postCallback, const std::optional>& colorTransform); // viewport: (re)initializes viewport dimensions. @@ -75,8 +76,8 @@ class PostWorker { protected: void runTask(std::packaged_task); // Impl versions of the above, so we can run it from separate threads - virtual std::shared_future postImpl(ColorBuffer* cb, - const std::optional>& colorTransform) = 0; + virtual std::shared_future postImpl( + IColorBuffer* cb, const std::optional>& colorTransform) = 0; virtual void viewportImpl(int width, int height) = 0; virtual void clearImpl() = 0; virtual void exitImpl() = 0; diff --git a/host/post_worker_gl.cpp b/host/post_worker_gl.cpp index 6d133350e..9e29582da 100644 --- a/host/post_worker_gl.cpp +++ b/host/post_worker_gl.cpp @@ -54,7 +54,7 @@ PostWorkerGl::PostWorkerGl(bool mainThreadPostingOnly, FrameBuffer* fb, Composit } std::shared_future PostWorkerGl::postImpl( - ColorBuffer* cb, const std::optional>& colorTransform) { + IColorBuffer* cb, const std::optional>& colorTransform) { if (!mContextBound || m_mainThreadPostingOnly) { // This might happen on headless mode // Also if posting on main thread, the context binding can get polluted easily, which @@ -130,7 +130,7 @@ std::shared_future PostWorkerGl::postImpl( continue; } - ColorBuffer* currentCb = + IColorBuffer* currentCb = currentDisplayId == 0 ? cb : mFb->findColorBuffer(currentDisplayColorBufferHandle).get(); @@ -204,7 +204,7 @@ std::shared_future PostWorkerGl::postImpl( } DisplayGl::PostLayer PostWorkerGl::postWithOverlay( - ColorBuffer* cb, const std::optional>& colorTransform) { + IColorBuffer* cb, const std::optional>& colorTransform) { float dpr = mFb->getDpr(); int windowWidth = mFb->windowWidth(); int windowHeight = mFb->windowHeight(); diff --git a/host/post_worker_gl.h b/host/post_worker_gl.h index 12f7db9f3..39d2d8f01 100644 --- a/host/post_worker_gl.h +++ b/host/post_worker_gl.h @@ -38,7 +38,7 @@ class PostWorkerGl : public PostWorker, public DisplaySurfaceUser { protected: std::shared_future postImpl( - ColorBuffer* cb, const std::optional>& colorTransform) override; + IColorBuffer* cb, const std::optional>& colorTransform) override; void viewportImpl(int width, int height) override; void clearImpl() override; void exitImpl() override; @@ -51,7 +51,7 @@ class PostWorkerGl : public PostWorker, public DisplaySurfaceUser { private: void setupContext(); gl::DisplayGl::PostLayer postWithOverlay( - ColorBuffer* cb, const std::optional>& colorTransform); + IColorBuffer* cb, const std::optional>& colorTransform); private: // TODO(b/233939967): conslidate DisplayGl and DisplayVk into diff --git a/host/readback_worker.h b/host/readback_worker.h index b5a638d44..05c37eb99 100644 --- a/host/readback_worker.h +++ b/host/readback_worker.h @@ -20,7 +20,7 @@ namespace gfxstream { namespace host { -class ColorBuffer; +class IColorBuffer; // This class implements async readback of ColorBuffers on both the FrameBuffer // posting thread and a separate worker thread. @@ -52,11 +52,8 @@ class ReadbackWorker { // |readbackBgra|: Whether to force the readback format as GL_BGRA_EXT, // so that we get (depending on driver quality, heh) a gpu conversion of the // readback image that is suitable for webrtc, which expects formats like that. - virtual DoNextReadbackResult doNextReadback(uint32_t displayId, - ColorBuffer* cb, - void* fbImage, - bool repaint, - bool readbackBgra) = 0; + virtual DoNextReadbackResult doNextReadback(uint32_t displayId, IColorBuffer* cb, void* fbImage, + bool repaint, bool readbackBgra) = 0; // Retrieves the latest framebuffer that has been posted and read with // doNextReadback. This is meant for apps like video encoding to use as diff --git a/host/vulkan/post_worker_vk.cpp b/host/vulkan/post_worker_vk.cpp index 907409568..11e76a4d9 100644 --- a/host/vulkan/post_worker_vk.cpp +++ b/host/vulkan/post_worker_vk.cpp @@ -45,8 +45,8 @@ hwc_transform_t getTransformFromRotation(int rotation) { PostWorkerVk::PostWorkerVk(FrameBuffer* fb, Compositor* compositor, vk::DisplayVk* displayVk) : PostWorker(false, fb, compositor), m_displayVk(displayVk) {} -std::shared_future PostWorkerVk::postImpl(ColorBuffer* cb, - const std::optional>& colorTransform) { +std::shared_future PostWorkerVk::postImpl( + IColorBuffer* cb, const std::optional>& colorTransform) { std::shared_future completedFuture = std::async(std::launch::deferred, [] {}).share(); completedFuture.wait(); @@ -57,7 +57,7 @@ std::shared_future PostWorkerVk::postImpl(ColorBuffer* cb, std::vector> borrowedImages; DisplayVk::Post postCmd; - auto addPostImage = [&](ColorBuffer* colorBuffer, int32_t x, int32_t y, int32_t w, int32_t h, + auto addPostImage = [&](IColorBuffer* colorBuffer, int32_t x, int32_t y, int32_t w, int32_t h, float rotation, const std::optional>& transform = std::nullopt) { auto info = mFb->borrowColorBufferForDisplay(colorBuffer->getHndl()); @@ -154,7 +154,7 @@ std::shared_future PostWorkerVk::postImpl(ColorBuffer* cb, continue; } - ColorBuffer* currentCb = + IColorBuffer* currentCb = currentDisplayId == 0 ? cb : mFb->findColorBuffer(currentDisplayColorBufferHandle).get(); diff --git a/host/vulkan/post_worker_vk.h b/host/vulkan/post_worker_vk.h index 9ca13318c..4dafa714e 100644 --- a/host/vulkan/post_worker_vk.h +++ b/host/vulkan/post_worker_vk.h @@ -34,7 +34,7 @@ class PostWorkerVk : public PostWorker { protected: std::shared_future postImpl( - ColorBuffer* cb, const std::optional>& colorTransform) override; + IColorBuffer* cb, const std::optional>& colorTransform) override; void viewportImpl(int width, int height) override; void clearImpl() override; void exitImpl() override; From 199fe22a4db22ad7dd60d52f3897ddb026ce2b53 Mon Sep 17 00:00:00 2001 From: Jason Macnak Date: Fri, 24 Jul 2026 08:58:24 -0700 Subject: [PATCH 12/33] Replace BorrowedImage with ColorBuffer interface BorrowedImage was an earlier attempt to decouple ColorBuffer from the underlying backends. It allowed components in the GL and VK backends to use parts of ColorBuffer without having to have full dependencies on the other backend. However, this required lots of copying of information and extra callbacks in order to call methods. The new IColorBuffer interface replaces this by providing an interface to access global info (width, height, etc) and to access the underlying backend objects (ColorBufferGl, ColorBufferVk) without having to have a full dependency. Bug: b/537737772 Test: bazel test //host/... Low-Coverage-Reason: REFACTOR_ONLY Change-Id: I1e12791bf8f97cb419cee363c27c2a3d1cace9e4 --- host/color_buffer.cpp | 65 ++-------- host/color_buffer.h | 15 +-- .../include/gfxstream/host/borrowed_image.h | 34 ----- .../gfxstream/host/color_buffer_interface.h | 16 +++ host/compositor.h | 6 +- host/frame_buffer.cpp | 77 ++--------- host/frame_buffer.h | 8 +- host/frame_buffer_unittest.cpp | 40 ++---- host/gl/BUILD.bazel | 1 - host/gl/borrowed_image_gl.h | 40 ------ host/gl/color_buffer_gl.cpp | 11 -- host/gl/color_buffer_gl.h | 4 +- host/gl/compositor_gl.cpp | 54 ++++---- host/gl/readback_worker_gl.cpp | 2 +- host/post_worker.cpp | 6 +- host/virtio_gpu_resource.cpp | 4 +- host/vulkan/Android.bp | 1 - host/vulkan/BUILD.bazel | 2 - host/vulkan/CMakeLists.txt | 1 - host/vulkan/borrowed_image_vk.cpp | 121 ------------------ host/vulkan/borrowed_image_vk.h | 71 ---------- host/vulkan/color_buffer_vk.cpp | 9 +- host/vulkan/color_buffer_vk.h | 23 +++- host/vulkan/compositor_vk.cpp | 95 ++++++++++---- host/vulkan/compositor_vk.h | 23 +++- host/vulkan/compositor_vk_unittest.cpp | 108 ++++++++-------- host/vulkan/display_vk.cpp | 16 ++- host/vulkan/display_vk.h | 5 +- host/vulkan/display_vk_unittest.cpp | 26 ++-- host/vulkan/meson.build | 1 - host/vulkan/post_worker_vk.cpp | 11 +- host/vulkan/vk_common_operations.cpp | 20 ++- host/vulkan/vk_common_operations.h | 19 +-- host/vulkan/vk_utils.cpp | 100 +++++++++++++++ host/vulkan/vk_utils.h | 10 ++ 35 files changed, 434 insertions(+), 611 deletions(-) delete mode 100644 host/common/include/gfxstream/host/borrowed_image.h delete mode 100644 host/gl/borrowed_image_gl.h delete mode 100644 host/vulkan/borrowed_image_vk.cpp delete mode 100644 host/vulkan/borrowed_image_vk.h diff --git a/host/color_buffer.cpp b/host/color_buffer.cpp index 455fa5802..0729035a9 100644 --- a/host/color_buffer.cpp +++ b/host/color_buffer.cpp @@ -72,14 +72,13 @@ class ColorBuffer::Impl : public LazySnapshotObj { const void* pixels, void* metadata = nullptr); bool updateGlFromBytes(const void* bytes, std::size_t bytesSize); - std::unique_ptr borrowForComposition(UsedApi api, bool isTarget); - std::unique_ptr borrowForDisplay(UsedApi api); - bool flushFromGl(); bool flushFromVk(); bool flushFromVkBytes(const void* bytes, size_t bytesSize); bool invalidateForGl(); bool invalidateForVk(); + bool invalidateForBackend(Backend backend); + bool importHandle(void* handle, bool preserveContent); std::optional exportBlob(); @@ -348,51 +347,17 @@ bool ColorBuffer::Impl::updateGlFromBytes(const void* bytes, std::size_t bytesSi return true; } -std::unique_ptr ColorBuffer::Impl::borrowForComposition(UsedApi api, - bool isTarget) { - switch (api) { - case UsedApi::kGl: { -#if GFXSTREAM_ENABLE_HOST_GLES - if (!mColorBufferGl) { - GFXSTREAM_ERROR("%s: ColorBufferGl not available", __func__); - return nullptr; - } - return mColorBufferGl->getBorrowedImageInfo(); -#endif - } - case UsedApi::kVk: { - if (!mColorBufferVk) { - GFXSTREAM_ERROR("%s: ColorBufferVk not available", __func__); - return nullptr; - } - return mColorBufferVk->borrowForComposition(isTarget); - } - } - GFXSTREAM_ERROR("%s: Unimplemented", __func__); - return nullptr; +bool ColorBuffer::Impl::invalidateForBackend(Backend backend) { + return backend == Backend::VK ? invalidateForVk() : invalidateForGl(); } -std::unique_ptr ColorBuffer::Impl::borrowForDisplay(UsedApi api) { - switch (api) { - case UsedApi::kGl: { +bool ColorBuffer::Impl::importHandle(void* handle, bool preserveContent) { #if GFXSTREAM_ENABLE_HOST_GLES - if (!mColorBufferGl) { - GFXSTREAM_ERROR("%s: ColorBufferGl not available", __func__); - return nullptr; - } - return mColorBufferGl->getBorrowedImageInfo(); -#endif - } - case UsedApi::kVk: { - if (!mColorBufferVk) { - GFXSTREAM_ERROR("%s: ColorBufferVk not available", __func__); - return nullptr; - } - return mColorBufferVk->borrowForDisplay(); - } + if (mColorBufferGl) { + return mColorBufferGl->importEglNativePixmap(handle, preserveContent); } - GFXSTREAM_ERROR("%s: Unimplemented", __func__); - return nullptr; +#endif + return false; } bool ColorBuffer::Impl::flushFromGl() { @@ -714,12 +679,12 @@ bool ColorBuffer::updateGlFromBytes(const void* bytes, std::size_t bytesSize) { return mImpl->updateGlFromBytes(bytes, bytesSize); } -std::unique_ptr ColorBuffer::borrowForComposition(UsedApi api, bool isTarget) { - return mImpl->borrowForComposition(api, isTarget); +bool ColorBuffer::invalidateForBackend(Backend backend) { + return mImpl->invalidateForBackend(backend); } -std::unique_ptr ColorBuffer::borrowForDisplay(UsedApi api) { - return mImpl->borrowForDisplay(api); +bool ColorBuffer::importHandle(void* handle, bool preserveContent) { + return mImpl->importHandle(handle, preserveContent); } bool ColorBuffer::flushFromGl() { return mImpl->flushFromGl(); } @@ -730,10 +695,6 @@ bool ColorBuffer::flushFromVkBytes(const void* bytes, size_t bytesSize) { return mImpl->flushFromVkBytes(bytes, bytesSize); } -bool ColorBuffer::invalidateForGl() { return mImpl->invalidateForGl(); } - -bool ColorBuffer::invalidateForVk() { return mImpl->invalidateForVk(); } - std::optional ColorBuffer::exportBlob() { return mImpl->exportBlob(); } #if GFXSTREAM_ENABLE_HOST_GLES diff --git a/host/color_buffer.h b/host/color_buffer.h index 4fdc712a1..54f700fa7 100644 --- a/host/color_buffer.h +++ b/host/color_buffer.h @@ -23,7 +23,6 @@ #include #include "framework_formats.h" -#include "gfxstream/host/borrowed_image.h" #include "gfxstream/host/color_buffer_interface.h" #include "gfxstream/host/external_object_manager.h" #include "gfxstream/host/gfxstream_format.h" @@ -74,10 +73,10 @@ class ColorBuffer : public IColorBuffer, public LazySnapshotObj { GfxstreamFormat getFormat() const; void readToBytes(int x, int y, int width, int height, GfxstreamFormat pixelsFormat, - void* outPixels, uint64_t outPixelsSize); + void* outPixels, uint64_t outPixelsSize) override; void readToBytesScaled(int pixelsWidth, int pixelsHeight, int pixelsRotation, const Rect& rect, GfxstreamFormat pixelsFormat, void* outPixels, - const std::optional>& colorTransform); + const std::optional>& colorTransform) override; void readYuvToBytes(int x, int y, int width, int height, void* outPixels, uint32_t outPixelsSize); @@ -85,18 +84,12 @@ class ColorBuffer : public IColorBuffer, public LazySnapshotObj { const void* pixels, void* metadata = nullptr); bool updateGlFromBytes(const void* bytes, std::size_t bytesSize); - enum class UsedApi { - kGl, - kVk, - }; - std::unique_ptr borrowForComposition(UsedApi api, bool isTarget); - std::unique_ptr borrowForDisplay(UsedApi api); + bool invalidateForBackend(Backend backend) override; + bool importHandle(void* handle, bool preserveContent) override; bool flushFromGl(); bool flushFromVk(); bool flushFromVkBytes(const void* bytes, size_t bytesSize); - bool invalidateForGl(); - bool invalidateForVk(); std::optional exportBlob(); diff --git a/host/common/include/gfxstream/host/borrowed_image.h b/host/common/include/gfxstream/host/borrowed_image.h deleted file mode 100644 index 68000ab53..000000000 --- a/host/common/include/gfxstream/host/borrowed_image.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2022 The Android Open Source Project -// -// 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 expresso or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include - -namespace gfxstream { -namespace host { - -// Common base struct representing images (Gl/Vk) that are borrowed -// by server components (e.g. CompositorGl, CompositorVk, DisplayVk) -// from the underlying server image owner (GlEmulation/VkEmulation). -struct BorrowedImageInfo { - virtual ~BorrowedImageInfo() {} - - uint32_t id = 0; - uint32_t width = 0; - uint32_t height = 0; -}; - -} // namespace host -} // namespace gfxstream diff --git a/host/common/include/gfxstream/host/color_buffer_interface.h b/host/common/include/gfxstream/host/color_buffer_interface.h index 5b8246dff..a2361d0ea 100644 --- a/host/common/include/gfxstream/host/color_buffer_interface.h +++ b/host/common/include/gfxstream/host/color_buffer_interface.h @@ -14,8 +14,13 @@ #pragma once +#include #include #include +#include + +#include "gfxstream/host/gfxstream_format.h" +#include "render-utils/Renderer.h" namespace gfxstream { namespace host { @@ -28,6 +33,8 @@ namespace vk { class ColorBufferVk; } // namespace vk +enum class Backend { GL, VK }; + // A (mostly) generic interface to a `ColorBuffer` so that the various backends // interact with `ColorBuffer`s without needing to depend on all of the various // underlying `ColorBuffer` implementations. @@ -43,6 +50,15 @@ class IColorBuffer { virtual gl::ColorBufferGl* getColorBufferGl() = 0; virtual vk::ColorBufferVk* getColorBufferVk() = 0; + + virtual bool invalidateForBackend(Backend backend) = 0; + virtual bool importHandle(void* handle, bool preserveContent) = 0; + + virtual void readToBytes(int x, int y, int width, int height, GfxstreamFormat pixelsFormat, + void* outPixels, uint64_t outPixelsSize) = 0; + virtual void readToBytesScaled(int pixelsWidth, int pixelsHeight, int pixelsRotation, + const Rect& rect, GfxstreamFormat pixelsFormat, void* outPixels, + const std::optional>& colorTransform) = 0; }; // A (mostly) generic shared owning reference to a `ColorBuffer` so that the diff --git a/host/compositor.h b/host/compositor.h index e42ee7068..e79bf9aa2 100644 --- a/host/compositor.h +++ b/host/compositor.h @@ -18,7 +18,7 @@ #include #include -#include "gfxstream/host/borrowed_image.h" +#include "gfxstream/host/color_buffer_interface.h" #include "hwc2.h" #include "render-utils/Renderer.h" @@ -31,12 +31,12 @@ class Compositor { virtual ~Compositor() {} struct CompositionRequestLayer { - std::unique_ptr source; + IColorBufferRef source; ComposeLayer props; }; struct CompositionRequest { - std::unique_ptr target; + IColorBufferRef target; std::vector layers; }; diff --git a/host/frame_buffer.cpp b/host/frame_buffer.cpp index 65f88873e..e35ce3176 100644 --- a/host/frame_buffer.cpp +++ b/host/frame_buffer.cpp @@ -38,25 +38,26 @@ #include "gl/glestranslator/egl/egl_global_info.h" #endif -#include "host/gl/context_helper.h" -#include "hwc2.h" -#include "native_sub_window.h" -#include "render_thread_info.h" -#include "sync_thread.h" -#include "gfxstream/shared_library.h" +#include "color_buffer.h" #include "gfxstream/Tracing.h" #include "gfxstream/common/logging.h" #include "gfxstream/containers/Lookup.h" -#include "gfxstream/host/tracing.h" #include "gfxstream/host/display_operations.h" #include "gfxstream/host/guest_operations.h" #include "gfxstream/host/renderer_operations.h" #include "gfxstream/host/stream_utils.h" +#include "gfxstream/host/tracing.h" #include "gfxstream/host/vm_operations.h" #include "gfxstream/host/window_operations.h" +#include "gfxstream/shared_library.h" #include "gfxstream/synchronization/Lock.h" #include "gfxstream/system/System.h" +#include "host/gl/context_helper.h" +#include "hwc2.h" +#include "native_sub_window.h" #include "render-utils/MediaNative.h" +#include "render_thread_info.h" +#include "sync_thread.h" #include "vulkan/display_vk.h" #include "vulkan/post_worker_vk.h" #include "vulkan/vk_common_operations.h" @@ -581,10 +582,6 @@ class FrameBuffer::Impl : public gfxstream::base::EventNotificationSupport borrowColorBufferForComposition(uint32_t colorBufferHandle, - bool colorBufferIsTarget); - std::unique_ptr borrowColorBufferForDisplay(uint32_t colorBufferHandle); void logVulkanDeviceLost(); void setVsyncHz(int vsyncHz); @@ -3833,48 +3830,6 @@ void FrameBuffer::Impl::setGuestManagedColorBufferLifetime(bool guestManaged) { m_guestManagedColorBufferLifetime = guestManaged; } -std::unique_ptr FrameBuffer::Impl::borrowColorBufferForComposition( - uint32_t colorBufferHandle, bool colorBufferIsTarget) { - ColorBufferPtr colorBufferPtr = findColorBuffer(colorBufferHandle); - if (!colorBufferPtr) { - GFXSTREAM_ERROR("Failed to get borrowed image info for ColorBuffer:%d", colorBufferHandle); - return nullptr; - } - - if (m_useVulkanComposition) { - invalidateColorBufferForVk(colorBufferHandle); - } else { -#if GFXSTREAM_ENABLE_HOST_GLES - invalidateColorBufferForGl(colorBufferHandle); -#endif - } - - const auto api = m_useVulkanComposition ? ColorBuffer::UsedApi::kVk : ColorBuffer::UsedApi::kGl; - return colorBufferPtr->borrowForComposition(api, colorBufferIsTarget); -} - -std::unique_ptr FrameBuffer::Impl::borrowColorBufferForDisplay( - uint32_t colorBufferHandle) { - ColorBufferPtr colorBufferPtr = findColorBuffer(colorBufferHandle); - if (!colorBufferPtr) { - GFXSTREAM_ERROR("Failed to get borrowed image info for ColorBuffer:%d", colorBufferHandle); - return nullptr; - } - - if (m_useVulkanComposition) { - invalidateColorBufferForVk(colorBufferHandle); - } else { -#if GFXSTREAM_ENABLE_HOST_GLES - invalidateColorBufferForGl(colorBufferHandle); -#else - GFXSTREAM_ERROR("Failed to invalidate ColorBuffer:%d", colorBufferHandle); -#endif - } - - const auto api = m_useVulkanComposition ? ColorBuffer::UsedApi::kVk : ColorBuffer::UsedApi::kGl; - return colorBufferPtr->borrowForDisplay(api); -} - void FrameBuffer::Impl::logVulkanDeviceLost() { if (!m_emulationVk) { GFXSTREAM_FATAL("Device lost without VkEmulation?"); @@ -3991,7 +3946,7 @@ bool FrameBuffer::Impl::invalidateColorBufferForVk(HandleType colorBufferHandle) GFXSTREAM_ERROR("Failed to find ColorBuffer: %d", colorBufferHandle); return false; } - return colorBuffer->invalidateForVk(); + return colorBuffer->invalidateForBackend(Backend::VK); } std::optional FrameBuffer::Impl::exportColorBuffer( @@ -4751,7 +4706,7 @@ bool FrameBuffer::Impl::invalidateColorBufferForGl(HandleType colorBufferHandle) GFXSTREAM_ERROR("Failed to find ColorBuffer: %d", colorBufferHandle); return false; } - return colorBuffer->invalidateForGl(); + return colorBuffer->invalidateForBackend(Backend::GL); } ContextHelper* FrameBuffer::Impl::getPbufferSurfaceContextHelper() const { @@ -5384,7 +5339,7 @@ int FrameBuffer::getColorBufferScreenshot( void FrameBuffer::onLastColorBufferRef(uint32_t handle) { mImpl->onLastColorBufferRef(handle); } -ColorBufferPtr FrameBuffer::findColorBuffer(HandleType p_colorbuffer) { +IColorBufferRef FrameBuffer::findColorBuffer(HandleType p_colorbuffer) { return mImpl->findColorBuffer(p_colorbuffer); } @@ -5454,16 +5409,6 @@ void FrameBuffer::setGuestManagedColorBufferLifetime(bool guestManaged) { mImpl->setGuestManagedColorBufferLifetime(guestManaged); } -std::unique_ptr FrameBuffer::borrowColorBufferForComposition( - uint32_t colorBufferHandle, bool colorBufferIsTarget) { - return mImpl->borrowColorBufferForComposition(colorBufferHandle, colorBufferIsTarget); -} - -std::unique_ptr FrameBuffer::borrowColorBufferForDisplay( - uint32_t colorBufferHandle) { - return mImpl->borrowColorBufferForDisplay(colorBufferHandle); -} - void FrameBuffer::setVsyncHz(int vsyncHz) { mImpl->setVsyncHz(vsyncHz); } void FrameBuffer::scheduleVsyncTask(VsyncThread::VsyncTask task) { mImpl->scheduleVsyncTask(task); } diff --git a/host/frame_buffer.h b/host/frame_buffer.h index 9f233459e..e8424761b 100644 --- a/host/frame_buffer.h +++ b/host/frame_buffer.h @@ -34,7 +34,7 @@ #include "framework_formats.h" #include "gfxstream/AsyncResult.h" #include "gfxstream/EventNotificationSupport.h" -#include "gfxstream/host/borrowed_image.h" +#include "gfxstream/host/color_buffer_interface.h" #include "gfxstream/host/external_object_manager.h" #include "gfxstream/host/gfxstream_format.h" #include "gfxstream/host/gl_enums.h" @@ -368,7 +368,7 @@ class FrameBuffer : public gfxstream::base::EventNotificationSupport>& colorTransform); void onLastColorBufferRef(uint32_t handle); - ColorBufferPtr findColorBuffer(HandleType p_colorbuffer); + IColorBufferRef findColorBuffer(HandleType p_colorbuffer); BufferPtr findBuffer(HandleType p_buffer); void registerProcessCleanupCallback(void* key, uint64_t contextId, @@ -412,10 +412,6 @@ class FrameBuffer : public gfxstream::base::EventNotificationSupport borrowColorBufferForComposition(uint32_t colorBufferHandle, - bool colorBufferIsTarget); - std::unique_ptr borrowColorBufferForDisplay(uint32_t colorBufferHandle); - void logVulkanDeviceLost(); void setVsyncHz(int vsyncHz); diff --git a/host/frame_buffer_unittest.cpp b/host/frame_buffer_unittest.cpp index 5507c5b35..ca4b44a6e 100644 --- a/host/frame_buffer_unittest.cpp +++ b/host/frame_buffer_unittest.cpp @@ -12,32 +12,33 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "frame_buffer.h" - -#include - #include #include -#include + +#include "frame_buffer.h" + #include #include -#include "render_channel_impl.h" +#include +#include -#include "render_thread_info.h" #include "gfxstream/common/testing/graphics_test_environment.h" #include "gfxstream/files/PathUtils.h" +#include "gfxstream/host/color_buffer_interface.h" #include "gfxstream/host/display_operations.h" #include "gfxstream/host/features.h" #include "gfxstream/host/file_stream.h" #include "gfxstream/host/gfxstream_format.h" #include "gfxstream/host/mem_stream.h" -#include "gfxstream/host/window_operations.h" -#include "gfxstream/system/System.h" #include "gfxstream/host/testing/GLSnapshotTesting.h" #include "gfxstream/host/testing/GLTestUtils.h" #include "gfxstream/host/testing/OSWindow.h" #include "gfxstream/host/testing/SampleApplication.h" #include "gfxstream/host/testing/ShaderUtils.h" +#include "gfxstream/host/window_operations.h" +#include "gfxstream/system/System.h" +#include "render_channel_impl.h" +#include "render_thread_info.h" #ifdef _MSC_VER #include "gfxstream/msvc.h" @@ -538,27 +539,6 @@ TEST_F(FrameBufferTest, SnapshotColorBufferSubUpdateRestore) { mFb->closeColorBuffer(handle); } -// bug: 111558407 -// Tests that ColorBuffer's blit path is retained on save/restore. -TEST_F(FrameBufferTest, SnapshotFastBlitRestore) { - HandleType handle = mFb->createColorBuffer(mWidth, mHeight, GfxstreamFormat::R8G8B8A8_UNORM); - - EXPECT_TRUE(mFb->isFastBlitSupported()); - - mFb->lock(); - EXPECT_EQ(mFb->isFastBlitSupported(), mFb->findColorBuffer(handle)->glOpIsFastBlitSupported()); - mFb->unlock(); - - saveSnapshot(); - loadSnapshot(); - - mFb->lock(); - EXPECT_EQ(mFb->isFastBlitSupported(), mFb->findColorBuffer(handle)->glOpIsFastBlitSupported()); - mFb->unlock(); - - mFb->closeColorBuffer(handle); -} - // Tests rate of draw calls with no guest/host communication, but with translator. static constexpr uint32_t kDrawCallLimit = 50000; diff --git a/host/gl/BUILD.bazel b/host/gl/BUILD.bazel index eefff508d..d2e7d5be0 100644 --- a/host/gl/BUILD.bazel +++ b/host/gl/BUILD.bazel @@ -30,7 +30,6 @@ cc_library( "yuv_converter.cpp", ], hdrs = [ - "borrowed_image_gl.h", "buffer_gl.h", "color_buffer_gl.h", "compositor_gl.h", diff --git a/host/gl/borrowed_image_gl.h b/host/gl/borrowed_image_gl.h deleted file mode 100644 index 12dd8423c..000000000 --- a/host/gl/borrowed_image_gl.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2022 The Android Open Source Project -// -// 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 expresso or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include -#include -#include -#include - -#include - -#include "gfxstream/host/borrowed_image.h" - -namespace gfxstream { -namespace host { -namespace gl { - -struct BorrowedImageInfoGl : public BorrowedImageInfo { - GLuint texture = 0; - - // Functor called once commands using this Image have been - // issued (useful for setting a GL sync). - std::function onCommandsIssued; -}; - -} // namespace gl -} // namespace host -} // namespace gfxstream diff --git a/host/gl/color_buffer_gl.cpp b/host/gl/color_buffer_gl.cpp index f56fbd7e8..2f872f392 100644 --- a/host/gl/color_buffer_gl.cpp +++ b/host/gl/color_buffer_gl.cpp @@ -24,7 +24,6 @@ #include "OpenGLESDispatch/DispatchTables.h" #include "OpenGLESDispatch/EGLDispatch.h" -#include "borrowed_image_gl.h" #include "common/gl_utils.h" #include "debug_gl.h" #include "gfxstream/host/renderer_operations.h" @@ -1354,16 +1353,6 @@ bool ColorBufferGl::importEglNativePixmap(void* pixmap, bool preserveContent) { return true; } -std::unique_ptr ColorBufferGl::getBorrowedImageInfo() { - auto info = std::make_unique(); - info->id = mHndl; - info->width = m_width; - info->height = m_height; - info->texture = m_tex; - info->onCommandsIssued = [this]() { setSync(); }; - return info; -} - } // namespace gl } // namespace host } // namespace gfxstream diff --git a/host/gl/color_buffer_gl.h b/host/gl/color_buffer_gl.h index 7c8012e4a..802215864 100644 --- a/host/gl/color_buffer_gl.h +++ b/host/gl/color_buffer_gl.h @@ -29,7 +29,6 @@ #include "context_helper.h" #include "gfxstream/ManagedDescriptor.h" -#include "gfxstream/host/borrowed_image.h" #include "gfxstream/host/features.h" #include "gfxstream/host/gfxstream_format.h" #include "handle.h" @@ -197,13 +196,12 @@ class ColorBufferGl { PixelReadFormats& pixelReadFormats); HandleType getHndl() const; + GLuint getTexture() const { return m_tex; } bool isFastBlitSupported() const { return m_fastBlitSupported; } void postLayer(const ComposeLayer& l, int frameWidth, int frameHeight, const std::optional>& colorTransform); - std::unique_ptr getBorrowedImageInfo(); - // ColorBufferGl backing change methods // // Change to opaque fd or opaque win32 handle-backed VkDeviceMemory diff --git a/host/gl/compositor_gl.cpp b/host/gl/compositor_gl.cpp index 4b0ee9c2e..4a7172fff 100644 --- a/host/gl/compositor_gl.cpp +++ b/host/gl/compositor_gl.cpp @@ -14,28 +14,18 @@ #include "compositor_gl.h" -#include "borrowed_image_gl.h" +#include "OpenGLESDispatch/DispatchTables.h" #include "debug_gl.h" #include "display_surface_gl.h" -#include "OpenGLESDispatch/DispatchTables.h" -#include "texture_draw.h" #include "gfxstream/common/logging.h" +#include "gl/color_buffer_gl.h" +#include "texture_draw.h" namespace gfxstream { namespace host { namespace gl { namespace { -const BorrowedImageInfoGl* getInfoOrAbort(const std::unique_ptr& info) { - auto imageGl = static_cast(info.get()); - if (imageGl != nullptr) { - return imageGl; - } - - GFXSTREAM_FATAL("CompositorGl did not find BorrowedImageInfoGl"); - return nullptr; -} - std::shared_future getCompletedFuture() { std::shared_future completedFuture = std::async(std::launch::deferred, [] {}).share(); completedFuture.wait(); @@ -54,10 +44,21 @@ CompositorGl::~CompositorGl() {} Compositor::CompositionFinishedWaitable CompositorGl::compose( const CompositionRequest& composeRequest) { - const auto* targetImage = getInfoOrAbort(composeRequest.target); - const uint32_t targetWidth = targetImage->width; - const uint32_t targetHeight = targetImage->height; - const GLuint targetTexture = targetImage->texture; + auto targetCb = composeRequest.target; + if (!targetCb) { + GFXSTREAM_ERROR("CompositorGl::compose: target is null"); + return getCompletedFuture(); + } + targetCb->invalidateForBackend(Backend::GL); + auto targetCbGl = targetCb->getColorBufferGl(); + if (!targetCbGl) { + GFXSTREAM_ERROR("CompositorGl::compose: target is not GL ColorBuffer"); + return getCompletedFuture(); + } + + const uint32_t targetWidth = targetCbGl->getWidth(); + const uint32_t targetHeight = targetCbGl->getHeight(); + const GLuint targetTexture = targetCbGl->getTexture(); GL_SCOPED_DEBUG_GROUP("CompositorGl::compose() into texture:%d", targetTexture); GLint restoredViewport[4] = {0, 0, 0, 0}; @@ -76,11 +77,20 @@ Compositor::CompositionFinishedWaitable CompositorGl::compose( for (const CompositionRequestLayer& layer : composeRequest.layers) { if (layer.props.composeMode == HWC2_COMPOSITION_DEVICE) { - const BorrowedImageInfoGl* layerImage = getInfoOrAbort(layer.source); - const GLuint layerTexture = layerImage->texture; + auto layerCb = layer.source; + if (!layerCb) { + continue; + } + layerCb->invalidateForBackend(Backend::GL); + auto layerCbGl = layerCb->getColorBufferGl(); + if (!layerCbGl) { + continue; + } + + const GLuint layerTexture = layerCbGl->getTexture(); GL_SCOPED_DEBUG_GROUP("CompositorGl::compose() from layer texture:%d", layerTexture); - m_textureDraw->drawLayer(layer.props, targetWidth, targetHeight, layerImage->width, - layerImage->height, layerTexture); + m_textureDraw->drawLayer(layer.props, targetWidth, targetHeight, layerCbGl->getWidth(), + layerCbGl->getHeight(), layerTexture); } else { m_textureDraw->drawLayer(layer.props, targetWidth, targetHeight, 1, 1, 0); } @@ -92,7 +102,7 @@ Compositor::CompositionFinishedWaitable CompositorGl::compose( m_textureDraw->cleanupForDrawLayer(); - targetImage->onCommandsIssued(); + targetCbGl->setSync(); // Note: This should be returning a future when all work, both CPU and GPU, is // complete but is currently only returning a future when all CPU work is completed. diff --git a/host/gl/readback_worker_gl.cpp b/host/gl/readback_worker_gl.cpp index ead29fbd9..3711d4dd2 100644 --- a/host/gl/readback_worker_gl.cpp +++ b/host/gl/readback_worker_gl.cpp @@ -20,9 +20,9 @@ #include "OpenGLESDispatch/DispatchTables.h" #include "OpenGLESDispatch/EGLDispatch.h" #include "OpenGLESDispatch/GLESv2Dispatch.h" -#include "color_buffer.h" #include "context_helper.h" #include "gfxstream/common/logging.h" +#include "gfxstream/host/color_buffer_interface.h" #include "gl/color_buffer_gl.h" namespace gfxstream { diff --git a/host/post_worker.cpp b/host/post_worker.cpp index bad7d15c1..d5da84ef0 100644 --- a/host/post_worker.cpp +++ b/host/post_worker.cpp @@ -45,8 +45,7 @@ std::shared_future PostWorker::composeImpl(const FlatComposeRequest& compo } Compositor::CompositionRequest compositorRequest = {}; - compositorRequest.target = mFb->borrowColorBufferForComposition(composeRequest.targetHandle, - /*colorBufferIsTarget=*/true); + compositorRequest.target = mFb->findColorBuffer(composeRequest.targetHandle); if (!compositorRequest.target) { GFXSTREAM_ERROR("Compose target is null (cb=0x%x).", composeRequest.targetHandle); return completedFuture; @@ -58,8 +57,7 @@ std::shared_future PostWorker::composeImpl(const FlatComposeRequest& compo auto& compositorLayer = compositorRequest.layers.emplace_back(); compositorLayer.props = guestLayer; } else { - auto source = mFb->borrowColorBufferForComposition(guestLayer.cbHandle, - /*colorBufferIsTarget=*/false); + auto source = mFb->findColorBuffer(guestLayer.cbHandle); if (!source) { continue; } diff --git a/host/virtio_gpu_resource.cpp b/host/virtio_gpu_resource.cpp index 6a146442b..66d929c91 100644 --- a/host/virtio_gpu_resource.cpp +++ b/host/virtio_gpu_resource.cpp @@ -323,8 +323,8 @@ int VirtioGpuResource::ImportHandle(const struct stream_renderer_handle* handle, switch (handle->handle_type) { #if GFXSTREAM_ENABLE_HOST_GLES case STREAM_HANDLE_TYPE_PLATFORM_EGL_NATIVE_PIXMAP: - importSuccess = colorBufferPtr->glOpImportEglNativePixmap( - reinterpret_cast(handle->os_handle), preserveContent); + importSuccess = colorBufferPtr->importHandle(reinterpret_cast(handle->os_handle), + preserveContent); break; #endif default: diff --git a/host/vulkan/Android.bp b/host/vulkan/Android.bp index e8e98b4fd..854ccd5b6 100644 --- a/host/vulkan/Android.bp +++ b/host/vulkan/Android.bp @@ -67,7 +67,6 @@ cc_library_static { "-Wno-unreachable-code-loop-increment", ], srcs: [ - "borrowed_image_vk.cpp", "buffer_vk.cpp", "color_buffer_vk.cpp", "compositor_vk.cpp", diff --git a/host/vulkan/BUILD.bazel b/host/vulkan/BUILD.bazel index b48c2a8a7..06bb7acd4 100644 --- a/host/vulkan/BUILD.bazel +++ b/host/vulkan/BUILD.bazel @@ -59,7 +59,6 @@ cc_library( cc_library( name = "gfxstream_vulkan_server", srcs = [ - "borrowed_image_vk.cpp", "buffer_vk.cpp", "color_buffer_vk.cpp", "compositor_vk.cpp", @@ -91,7 +90,6 @@ cc_library( "vulkan_stream.cpp", ], hdrs = [ - "borrowed_image_vk.h", "buffer_vk.h", "color_buffer_vk.h", "compositor_fragment_shader.h", diff --git a/host/vulkan/CMakeLists.txt b/host/vulkan/CMakeLists.txt index 68e9fa13d..c041ab66a 100644 --- a/host/vulkan/CMakeLists.txt +++ b/host/vulkan/CMakeLists.txt @@ -21,7 +21,6 @@ if(CONFIG_AEMU) endif() add_library(gfxstream-vulkan-server - borrowed_image_vk.cpp buffer_vk.cpp color_buffer_vk.cpp compositor_vk.cpp diff --git a/host/vulkan/borrowed_image_vk.cpp b/host/vulkan/borrowed_image_vk.cpp deleted file mode 100644 index 04f19a1a3..000000000 --- a/host/vulkan/borrowed_image_vk.cpp +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2022 The Android Open Source Project -// -// 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 expresso or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "borrowed_image_vk.h" - -namespace gfxstream { -namespace host { -namespace vk { - -void addNeededBarriersToUseBorrowedImage( - const BorrowedImageInfoVk& borrowedImageInfo, uint32_t usedQueueFamilyIndex, - VkImageLayout usedInitialImageLayout, VkImageLayout usedFinalImageLayout, - VkAccessFlags usedAccessMask, std::vector* preUseQueueTransferBarriers, - std::vector* preUseLayoutTransitionBarriers, - std::vector* postUseLayoutTransitionBarriers, - std::vector* postUseQueueTransferBarriers) { - if (borrowedImageInfo.preBorrowQueueFamilyIndex != usedQueueFamilyIndex) { - const VkImageMemoryBarrier queueTransferBarrier = { - .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - .pNext = nullptr, - .srcAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, - .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, - .oldLayout = borrowedImageInfo.preBorrowLayout, - .newLayout = borrowedImageInfo.preBorrowLayout, - .srcQueueFamilyIndex = borrowedImageInfo.preBorrowQueueFamilyIndex, - .dstQueueFamilyIndex = usedQueueFamilyIndex, - .image = borrowedImageInfo.image, - .subresourceRange = - { - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .baseMipLevel = 0, - .levelCount = 1, - .baseArrayLayer = 0, - .layerCount = 1, - }, - }; - preUseQueueTransferBarriers->emplace_back(queueTransferBarrier); - } - if (borrowedImageInfo.preBorrowLayout != usedInitialImageLayout && - usedInitialImageLayout != VK_IMAGE_LAYOUT_UNDEFINED) { - const VkImageMemoryBarrier layoutTransitionBarrier = { - .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - .pNext = nullptr, - .srcAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, - .dstAccessMask = usedAccessMask, - .oldLayout = borrowedImageInfo.preBorrowLayout, - .newLayout = usedInitialImageLayout, - .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .image = borrowedImageInfo.image, - .subresourceRange = - { - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .baseMipLevel = 0, - .levelCount = 1, - .baseArrayLayer = 0, - .layerCount = 1, - }, - }; - preUseLayoutTransitionBarriers->emplace_back(layoutTransitionBarrier); - } - if (borrowedImageInfo.postBorrowLayout != usedFinalImageLayout) { - const VkImageMemoryBarrier layoutTransitionBarrier = { - .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - .pNext = nullptr, - .srcAccessMask = usedAccessMask, - .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, - .oldLayout = usedFinalImageLayout, - .newLayout = borrowedImageInfo.postBorrowLayout, - .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .image = borrowedImageInfo.image, - .subresourceRange = - { - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .baseMipLevel = 0, - .levelCount = 1, - .baseArrayLayer = 0, - .layerCount = 1, - }, - }; - postUseLayoutTransitionBarriers->emplace_back(layoutTransitionBarrier); - } - if (borrowedImageInfo.postBorrowQueueFamilyIndex != usedQueueFamilyIndex) { - const VkImageMemoryBarrier queueTransferBarrier = { - .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - .pNext = nullptr, - .srcAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, - .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, - .oldLayout = borrowedImageInfo.postBorrowLayout, - .newLayout = borrowedImageInfo.postBorrowLayout, - .srcQueueFamilyIndex = usedQueueFamilyIndex, - .dstQueueFamilyIndex = borrowedImageInfo.postBorrowQueueFamilyIndex, - .image = borrowedImageInfo.image, - .subresourceRange = - { - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .baseMipLevel = 0, - .levelCount = 1, - .baseArrayLayer = 0, - .layerCount = 1, - }, - }; - postUseQueueTransferBarriers->emplace_back(queueTransferBarrier); - } -} - -} // namespace vk -} // namespace host -} // namespace gfxstream diff --git a/host/vulkan/borrowed_image_vk.h b/host/vulkan/borrowed_image_vk.h deleted file mode 100644 index 25d1ebec2..000000000 --- a/host/vulkan/borrowed_image_vk.h +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2022 The Android Open Source Project -// -// 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 expresso or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include - -#include -#include - -#include "gfxstream/host/borrowed_image.h" -#include "gfxstream/host/gfxstream_format.h" - -namespace gfxstream { -namespace host { -namespace vk { - -struct BorrowedImageInfoVk : public BorrowedImageInfo { - VkImage image = VK_NULL_HANDLE; - VkImageView imageView = VK_NULL_HANDLE; - VkImageCreateInfo imageCreateInfo = {}; - GfxstreamFormat imageFormat = GfxstreamFormat::UNKNOWN; - - // The image layout that `image` is in before composition. - // - // This is currently ignored for composition target images as - // composition targets are expected to be cleared during - // composition. - VkImageLayout preBorrowLayout = VK_IMAGE_LAYOUT_UNDEFINED; - - // The queue family index that owns `image` before composition. - uint32_t preBorrowQueueFamilyIndex = 0; - - // The image layout that `image` should be transitioned to - // after composition. - // - // This is currently ignored for composition target images as - // composition targets are expected to be transitioned to - // VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL after composition for - // blitting to display images. - VkImageLayout postBorrowLayout = VK_IMAGE_LAYOUT_UNDEFINED; - - // The queue family index that `image` should be transitioned to - // after composition. - uint32_t postBorrowQueueFamilyIndex = 0; -}; - -// The caller should always record the queue transfer barriers with stages that supoort -// VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT. -void addNeededBarriersToUseBorrowedImage( - const BorrowedImageInfoVk& borrowedImageInfo, uint32_t usedQueueFamilyIndex, - VkImageLayout usedInitialImageLayout, VkImageLayout usedFinalImageLayout, - VkAccessFlags usedAccessMask, std::vector* preUseQueueTransferBarriers, - std::vector* preUseLayoutTransitionBarriers, - std::vector* postUseLayoutTransitionBarriers, - std::vector* postUseQueueTransferBarriers); - -} // namespace vk -} // namespace host -} // namespace gfxstream diff --git a/host/vulkan/color_buffer_vk.cpp b/host/vulkan/color_buffer_vk.cpp index e29cf175b..a24aaf3b2 100644 --- a/host/vulkan/color_buffer_vk.cpp +++ b/host/vulkan/color_buffer_vk.cpp @@ -107,12 +107,13 @@ bool ColorBufferVk::updateFromBytes(uint32_t x, uint32_t y, uint32_t w, uint32_t return mVkEmulation.updateColorBufferFromBytes(mHandle, x, y, w, h, bytes); } -std::unique_ptr ColorBufferVk::borrowForComposition(bool colorBufferIsTarget) { - return mVkEmulation.borrowColorBufferForComposition(mHandle, colorBufferIsTarget); +std::unique_ptr ColorBufferVk::prepareForComposition( + bool colorBufferIsTarget) { + return mVkEmulation.prepareColorBufferForComposition(mHandle, colorBufferIsTarget); } -std::unique_ptr ColorBufferVk::borrowForDisplay() { - return mVkEmulation.borrowColorBufferForDisplay(mHandle); +std::unique_ptr ColorBufferVk::prepareForDisplay() { + return mVkEmulation.prepareColorBufferForDisplay(mHandle); } std::optional ColorBufferVk::exportBlob() { diff --git a/host/vulkan/color_buffer_vk.h b/host/vulkan/color_buffer_vk.h index abb7d99af..a4b3c3527 100644 --- a/host/vulkan/color_buffer_vk.h +++ b/host/vulkan/color_buffer_vk.h @@ -12,12 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include +#pragma once + +#include #include #include -#include "gfxstream/host/borrowed_image.h" #include "gfxstream/host/external_object_manager.h" #include "gfxstream/host/gfxstream_format.h" #include "render-utils/Renderer.h" @@ -39,6 +40,20 @@ enum class LoadImageBehavior { class VkEmulation; +struct ColorBufferVkImageInfo { + uint32_t id = 0; + uint32_t width = 0; + uint32_t height = 0; + VkImage image = VK_NULL_HANDLE; + VkImageView imageView = VK_NULL_HANDLE; + VkImageCreateInfo imageCreateInfo = {}; + GfxstreamFormat imageFormat = GfxstreamFormat::UNKNOWN; + VkImageLayout preBorrowLayout = VK_IMAGE_LAYOUT_UNDEFINED; + uint32_t preBorrowQueueFamilyIndex = 0; + VkImageLayout postBorrowLayout = VK_IMAGE_LAYOUT_UNDEFINED; + uint32_t postBorrowQueueFamilyIndex = 0; +}; + class ColorBufferVk { public: static std::unique_ptr create(VkEmulation& emulationVk, uint32_t handle, @@ -58,8 +73,8 @@ class ColorBufferVk { bool updateFromBytes(const std::vector& bytes); bool updateFromBytes(uint32_t x, uint32_t y, uint32_t w, uint32_t h, const void* bytes); - std::unique_ptr borrowForComposition(bool colorBufferIsTarget); - std::unique_ptr borrowForDisplay(); + std::unique_ptr prepareForComposition(bool colorBufferIsTarget); + std::unique_ptr prepareForDisplay(); void onLoad(gfxstream::Stream* stream, LoadImageBehavior behavior); void onSave(gfxstream::Stream* stream, SaveImageBehavior behavior); diff --git a/host/vulkan/compositor_vk.cpp b/host/vulkan/compositor_vk.cpp index fc2dc9c50..54a3fd741 100644 --- a/host/vulkan/compositor_vk.cpp +++ b/host/vulkan/compositor_vk.cpp @@ -22,6 +22,7 @@ #include "gfxstream/common/logging.h" #include "gfxstream/host/tracing.h" +#include "vulkan/color_buffer_vk.h" #include "vulkan/compositor_fragment_shader.h" #include "vulkan/compositor_vertex_shader.h" #include "vulkan/vk_enum_string_helper.h" @@ -46,16 +47,6 @@ static const GfxstreamFormat kRenderTargetFormats[2] = { GfxstreamFormat::B8G8R8A8_UNORM, }; -const BorrowedImageInfoVk* getInfoOrAbort(const std::unique_ptr& info) { - auto imageVk = static_cast(info.get()); - if (imageVk != nullptr) { - return imageVk; - } - - GFXSTREAM_FATAL("CompositorVk did not find BorrowedImageInfoVk"); - return nullptr; -} - struct Vertex { alignas(8) glm::vec2 pos; alignas(8) glm::vec2 tex; @@ -1159,7 +1150,7 @@ VkFormatFeatureFlags CompositorVk::getFormatFeatures(VkFormat format, VkImageTil } CompositorVk::RenderTarget* CompositorVk::getOrCreateRenderTargetInfo( - const BorrowedImageInfoVk& imageInfo) { + const ColorBufferVkImageInfo& imageInfo) { std::lock_guard lock(m_renderTargetCacheMutex); auto* renderTargetPtr = m_renderTargetCache.get(imageInfo.id); if (renderTargetPtr != nullptr) { @@ -1196,13 +1187,13 @@ bool CompositorVk::canCompositeFrom(const VkImageCreateInfo& imageCi) { return true; } -void CompositorVk::buildCompositionVk(const CompositionRequest& compositionRequest, +void CompositorVk::buildCompositionVk(const CompositionRequestVk& compositionRequest, CompositionVk* compositionVk) { - if (compositionRequest.target.get() == nullptr) { + if (compositionRequest.target == nullptr) { GFXSTREAM_ERROR("invalid target!"); return; } - const BorrowedImageInfoVk* targetImage = getInfoOrAbort(compositionRequest.target); + const ColorBufferVkImageInfo* targetImage = compositionRequest.target; auto renderPassIt = m_vkRenderPasses.find(targetImage->imageFormat); if (renderPassIt == m_vkRenderPasses.end()) { @@ -1220,16 +1211,16 @@ void CompositorVk::buildCompositionVk(const CompositionRequest& compositionReque compositionVk->targetRenderPass = renderPassIt->second; compositionVk->targetFramebuffer = targetImageRenderTarget->m_vkFramebuffer; - for (const CompositionRequestLayer& layer : compositionRequest.layers) { + for (const CompositionRequestLayerVk& layer : compositionRequest.layers) { uint32_t sourceImageWidth = 0; uint32_t sourceImageHeight = 0; - const BorrowedImageInfoVk* sourceImage = nullptr; + const ColorBufferVkImageInfo* sourceImage = nullptr; if (layer.props.composeMode == HWC2_COMPOSITION_SOLID_COLOR) { sourceImageWidth = targetWidth; sourceImageHeight = targetHeight; } else if (layer.source) { - sourceImage = getInfoOrAbort(layer.source); + sourceImage = layer.source; if (!canCompositeFrom(sourceImage->imageCreateInfo)) { continue; } @@ -1391,8 +1382,55 @@ void CompositorVk::buildCompositionVk(const CompositionRequest& compositionReque } } +static Compositor::CompositionFinishedWaitable getCompletedFuture() { + std::promise promise; + promise.set_value(); + return promise.get_future().share(); +} + CompositorVk::CompositionFinishedWaitable CompositorVk::compose( const CompositionRequest& compositionRequest) { + auto targetCb = compositionRequest.target; + if (!targetCb) { + GFXSTREAM_ERROR("invalid target!"); + return getCompletedFuture(); + } + targetCb->invalidateForBackend(Backend::VK); + auto targetCbVk = targetCb->getColorBufferVk(); + auto targetImageInfo = targetCbVk ? targetCbVk->prepareForComposition(true) : nullptr; + if (!targetImageInfo) { + GFXSTREAM_ERROR("failed to prepare target!"); + return getCompletedFuture(); + } + + CompositionRequestVk compositionRequestVk; + compositionRequestVk.target = targetImageInfo.get(); + + std::vector> keepAliveImages; + keepAliveImages.push_back(std::move(targetImageInfo)); + + for (const CompositionRequestLayer& layer : compositionRequest.layers) { + CompositionRequestLayerVk layerVk; + layerVk.props = layer.props; + + if (layer.props.composeMode == HWC2_COMPOSITION_DEVICE && layer.source) { + auto sourceCb = layer.source; + sourceCb->invalidateForBackend(Backend::VK); + auto sourceCbVk = sourceCb->getColorBufferVk(); + auto sourceImageInfo = sourceCbVk ? sourceCbVk->prepareForComposition(false) : nullptr; + if (sourceImageInfo) { + layerVk.source = sourceImageInfo.get(); + keepAliveImages.push_back(std::move(sourceImageInfo)); + } + } + compositionRequestVk.layers.push_back(layerVk); + } + + return compose(compositionRequestVk); +} + +CompositorVk::CompositionFinishedWaitable CompositorVk::compose( + const CompositionRequestVk& compositionRequest) { static uint32_t sCompositionNumber = 0; const uint32_t thisCompositionNumber = sCompositionNumber++; @@ -1418,14 +1456,21 @@ CompositorVk::CompositionFinishedWaitable CompositorVk::compose( std::vector preCompositionLayoutTransitionBarriers; std::vector postCompositionLayoutTransitionBarriers; std::vector postCompositionQueueTransferBarriers; - addNeededBarriersToUseBorrowedImage( - *compositionVk.targetImage, m_queueFamilyIndex, kTargetImageInitialLayoutUsed, - kTargetImageFinalLayoutUsed, VK_ACCESS_MEMORY_WRITE_BIT, - &preCompositionQueueTransferBarriers, &preCompositionLayoutTransitionBarriers, - &postCompositionLayoutTransitionBarriers, &postCompositionQueueTransferBarriers); - for (const BorrowedImageInfoVk* sourceImage : compositionVk.layersSourceImages) { - addNeededBarriersToUseBorrowedImage( - *sourceImage, m_queueFamilyIndex, kSourceImageInitialLayoutUsed, + { + const auto* targetImage = compositionVk.targetImage; + vk_util::addNeededBarriersToUseImage( + targetImage->image, targetImage->preBorrowQueueFamilyIndex, + targetImage->preBorrowLayout, targetImage->postBorrowQueueFamilyIndex, + targetImage->postBorrowLayout, m_queueFamilyIndex, kTargetImageInitialLayoutUsed, + kTargetImageFinalLayoutUsed, VK_ACCESS_MEMORY_WRITE_BIT, + &preCompositionQueueTransferBarriers, &preCompositionLayoutTransitionBarriers, + &postCompositionLayoutTransitionBarriers, &postCompositionQueueTransferBarriers); + } + for (const ColorBufferVkImageInfo* sourceImage : compositionVk.layersSourceImages) { + vk_util::addNeededBarriersToUseImage( + sourceImage->image, sourceImage->preBorrowQueueFamilyIndex, + sourceImage->preBorrowLayout, sourceImage->postBorrowQueueFamilyIndex, + sourceImage->postBorrowLayout, m_queueFamilyIndex, kSourceImageInitialLayoutUsed, kSourceImageFinalLayoutUsed, VK_ACCESS_SHADER_READ_BIT, &preCompositionQueueTransferBarriers, &preCompositionLayoutTransitionBarriers, &postCompositionLayoutTransitionBarriers, &postCompositionQueueTransferBarriers); diff --git a/host/vulkan/compositor_vk.h b/host/vulkan/compositor_vk.h index a9e85f21f..4b9e28959 100644 --- a/host/vulkan/compositor_vk.h +++ b/host/vulkan/compositor_vk.h @@ -26,11 +26,10 @@ #include #include -#include "borrowed_image_vk.h" +#include "color_buffer_vk.h" #include "compositor.h" #include "debug_utils_helper.h" #include "gfxstream/LruCache.h" -#include "gfxstream/host/borrowed_image.h" #include "gfxstream/host/gfxstream_format.h" #include "gfxstream/synchronization/Lock.h" #include "goldfish_vk_dispatch.h" @@ -267,6 +266,16 @@ struct CompositorVkBase : public vk_util::MultiCrtp layers; +}; + class CompositorVk : protected CompositorVkBase, public Compositor { public: static std::unique_ptr create( @@ -280,6 +289,8 @@ class CompositorVk : protected CompositorVkBase, public Compositor { CompositionFinishedWaitable compose(const CompositionRequest& compositionRequest) override; + CompositionFinishedWaitable compose(const CompositionRequestVk& compositionRequestVk); + void setScreenMask(int width, int height, const uint8_t* rgbaData) override; void setScreenBackground(int width, int height, const uint8_t* rgbaData) override; @@ -370,15 +381,15 @@ class CompositorVk : protected CompositorVkBase, public Compositor { // A consolidated view of a `Compositor::CompositionRequest` with only // the Vulkan components needed for command recording and submission. struct CompositionVk { - const BorrowedImageInfoVk* targetImage = nullptr; + const ColorBufferVkImageInfo* targetImage = nullptr; VkRenderPass targetRenderPass = VK_NULL_HANDLE; VkFramebuffer targetFramebuffer = VK_NULL_HANDLE; std::vector layersPipelines; std::vector layerSourceSamplerFormats; - std::vector layersSourceImages; + std::vector layersSourceImages; FrameDescriptorSetsContents layersDescriptorSets; }; - void buildCompositionVk(const CompositionRequest& compositionRequest, + void buildCompositionVk(const CompositionRequestVk& compositionRequest, CompositionVk* compositionVk); void updateDescriptorSetsIfChanged(const FrameDescriptorSetsContents& contents, @@ -406,7 +417,7 @@ class CompositorVk : protected CompositorVkBase, public Compositor { // Gets the RenderTarget used for composing into the given image if it already exists, // otherwise creates it. - RenderTarget* getOrCreateRenderTargetInfo(const BorrowedImageInfoVk& info); + RenderTarget* getOrCreateRenderTargetInfo(const ColorBufferVkImageInfo& info); // Cached format properties used for checking if composition is supported with a given // format. diff --git a/host/vulkan/compositor_vk_unittest.cpp b/host/vulkan/compositor_vk_unittest.cpp index f119a7d25..f5d01ceee 100644 --- a/host/vulkan/compositor_vk_unittest.cpp +++ b/host/vulkan/compositor_vk_unittest.cpp @@ -12,19 +12,19 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include +#include + #include "compositor_vk.h" #include #include #include +#include #include #include -#include -#include -#include - -#include "borrowed_image_vk.h" +#include "color_buffer_vk.h" #include "gfxstream/common/testing/graphics_test_environment.h" #include "gfxstream/host/testing/VkTestUtils.h" #include "gfxstream/image_utils.h" @@ -131,6 +131,7 @@ class CompositorVkTest : public ::testing::Test { } void TearDown() override { + m_allocatedImages.clear(); m_YcbcrSamplerPool.destroy(); k_vk->vkDestroyCommandPool(m_vkDevice, m_vkCommandPool, nullptr); k_vk->vkDestroyDevice(m_vkDevice, nullptr); @@ -283,10 +284,10 @@ class CompositorVkTest : public ::testing::Test { } template - std::unique_ptr createBorrowedImageInfo(const SourceOrTargetImage* image) { + const ColorBufferVkImageInfo* createImageTransitionInfo(const SourceOrTargetImage* image) { static int sImageId = 0; - auto ret = std::make_unique(); + auto ret = std::make_unique(); ret->id = sImageId++; ret->width = image->m_width; ret->height = image->m_height; @@ -298,7 +299,9 @@ class CompositorVkTest : public ::testing::Test { ret->preBorrowQueueFamilyIndex = m_compositorQueueFamilyIndex; ret->postBorrowLayout = SourceOrTargetImage::k_vkImageLayout; ret->postBorrowQueueFamilyIndex = m_compositorQueueFamilyIndex; - return ret; + const auto* ptr = ret.get(); + m_allocatedImages.push_back(std::move(ret)); + return ptr; } void checkImageFilledWith(const TargetImage* image, uint32_t expectedColor) { @@ -328,6 +331,9 @@ class CompositorVkTest : public ::testing::Test { std::shared_ptr m_compositorVkQueueLock; vk_util::YcbcrSamplerPool m_YcbcrSamplerPool; + protected: + std::vector> m_allocatedImages; + private: void createInstance() { const VkApplicationInfo appInfo = { @@ -448,8 +454,8 @@ TEST_F(CompositorVkTest, EmptyCompositionShouldDrawABlackFrame) { } for (uint32_t i = 0; i < kNumImages; i++) { - const Compositor::CompositionRequest compositionRequest = { - .target = createBorrowedImageInfo(targets[i].get()), + const CompositionRequestVk compositionRequest = { + .target = createImageTransitionInfo(targets[i].get()), .layers = {}, // Note: this is empty! }; @@ -474,11 +480,11 @@ TEST_F(CompositorVkTest, SimpleComposition) { ASSERT_NE(target, nullptr); fillImageWith(target.get(), kColorBlack); - Compositor::CompositionRequest compositionRequest = { - .target = createBorrowedImageInfo(target.get()), + CompositionRequestVk compositionRequest = { + .target = createImageTransitionInfo(target.get()), }; - compositionRequest.layers.emplace_back(Compositor::CompositionRequestLayer{ - .source = createBorrowedImageInfo(source.get()), + compositionRequest.layers.emplace_back(CompositionRequestLayerVk{ + .source = createImageTransitionInfo(source.get()), .props = { .composeMode = HWC2_COMPOSITION_DEVICE, @@ -530,11 +536,11 @@ TEST_F(CompositorVkTest, BlendPremultiplied) { ASSERT_NE(target, nullptr); fillImageWith(target.get(), kColorBlack); - Compositor::CompositionRequest compositionRequest = { - .target = createBorrowedImageInfo(target.get()), + CompositionRequestVk compositionRequest = { + .target = createImageTransitionInfo(target.get()), }; - compositionRequest.layers.emplace_back(Compositor::CompositionRequestLayer{ - .source = createBorrowedImageInfo(source.get()), + compositionRequest.layers.emplace_back(CompositionRequestLayerVk{ + .source = createImageTransitionInfo(source.get()), .props = { .composeMode = HWC2_COMPOSITION_DEVICE, @@ -585,11 +591,11 @@ TEST_F(CompositorVkTest, Crop) { ASSERT_NE(target, nullptr); fillImageWith(target.get(), kColorBlack); - Compositor::CompositionRequest compositionRequest = { - .target = createBorrowedImageInfo(target.get()), + CompositionRequestVk compositionRequest = { + .target = createImageTransitionInfo(target.get()), }; - compositionRequest.layers.emplace_back(Compositor::CompositionRequestLayer{ - .source = createBorrowedImageInfo(source.get()), + compositionRequest.layers.emplace_back(CompositionRequestLayerVk{ + .source = createImageTransitionInfo(source.get()), .props = { .composeMode = HWC2_COMPOSITION_DEVICE, @@ -636,10 +642,10 @@ TEST_F(CompositorVkTest, SolidColor) { ASSERT_NE(target, nullptr); fillImageWith(target.get(), kColorBlack); - Compositor::CompositionRequest compositionRequest = { - .target = createBorrowedImageInfo(target.get()), + CompositionRequestVk compositionRequest = { + .target = createImageTransitionInfo(target.get()), }; - compositionRequest.layers.emplace_back(Compositor::CompositionRequestLayer{ + compositionRequest.layers.emplace_back(CompositionRequestLayerVk{ .source = nullptr, .props = { @@ -682,10 +688,10 @@ TEST_F(CompositorVkTest, SolidColorBelow) { ASSERT_NE(target, nullptr); fillImageWith(target.get(), kColorBlack); - Compositor::CompositionRequest compositionRequest = { - .target = createBorrowedImageInfo(target.get()), + CompositionRequestVk compositionRequest = { + .target = createImageTransitionInfo(target.get()), }; - compositionRequest.layers.emplace_back(Compositor::CompositionRequestLayer{ + compositionRequest.layers.emplace_back(CompositionRequestLayerVk{ .source = nullptr, .props = { @@ -707,8 +713,8 @@ TEST_F(CompositorVkTest, SolidColorBelow) { }, }, }); - compositionRequest.layers.emplace_back(Compositor::CompositionRequestLayer{ - .source = createBorrowedImageInfo(source.get()), + compositionRequest.layers.emplace_back(CompositionRequestLayerVk{ + .source = createImageTransitionInfo(source.get()), .props = { .composeMode = HWC2_COMPOSITION_DEVICE, @@ -758,11 +764,11 @@ TEST_F(CompositorVkTest, SolidColorAbove) { ASSERT_NE(target, nullptr); fillImageWith(target.get(), kColorBlack); - Compositor::CompositionRequest compositionRequest = { - .target = createBorrowedImageInfo(target.get()), + CompositionRequestVk compositionRequest = { + .target = createImageTransitionInfo(target.get()), }; - compositionRequest.layers.emplace_back(Compositor::CompositionRequestLayer{ - .source = createBorrowedImageInfo(source.get()), + compositionRequest.layers.emplace_back(CompositionRequestLayerVk{ + .source = createImageTransitionInfo(source.get()), .props = { .composeMode = HWC2_COMPOSITION_DEVICE, @@ -792,7 +798,7 @@ TEST_F(CompositorVkTest, SolidColorAbove) { .transform = HWC_TRANSFORM_NONE, }, }); - compositionRequest.layers.emplace_back(Compositor::CompositionRequestLayer{ + compositionRequest.layers.emplace_back(CompositionRequestLayerVk{ .source = nullptr, .props = { @@ -829,8 +835,8 @@ TEST_F(CompositorVkTest, Transformations) { auto source = createSourceImageFromPng(GetTestDataPath("256x256_android.png")); ASSERT_NE(source, nullptr); - Compositor::CompositionRequest compositionRequest; - compositionRequest.layers.emplace_back(Compositor::CompositionRequestLayer{ + CompositionRequestVk compositionRequest; + compositionRequest.layers.emplace_back(CompositionRequestLayerVk{ .props = { .composeMode = HWC2_COMPOSITION_DEVICE, @@ -878,9 +884,9 @@ TEST_F(CompositorVkTest, Transformations) { ASSERT_NE(target, nullptr); fillImageWith(target.get(), kColorBlack); - compositionRequest.target = createBorrowedImageInfo(target.get()); + compositionRequest.target = createImageTransitionInfo(target.get()); compositionRequest.layers[0].props.transform = transform; - compositionRequest.layers[0].source = createBorrowedImageInfo(source.get()); + compositionRequest.layers[0].source = createImageTransitionInfo(source.get()); auto compositionCompleteWaitable = compositor->compose(compositionRequest); compositionCompleteWaitable.wait(); @@ -906,8 +912,8 @@ TEST_F(CompositorVkTest, MultipleTargetsComposition) { targets.emplace_back(std::move(target)); } - Compositor::CompositionRequest compositionRequest = {}; - compositionRequest.layers.emplace_back(Compositor::CompositionRequestLayer{ + CompositionRequestVk compositionRequest = {}; + compositionRequest.layers.emplace_back(CompositionRequestLayerVk{ .props = { .composeMode = HWC2_COMPOSITION_DEVICE, @@ -942,8 +948,8 @@ TEST_F(CompositorVkTest, MultipleTargetsComposition) { for (uint32_t i = 0; i < kNumCompostions; i++) { const auto& target = targets[i]; - compositionRequest.target = createBorrowedImageInfo(target.get()); - compositionRequest.layers[0].source = createBorrowedImageInfo(source.get()), + compositionRequest.target = createImageTransitionInfo(target.get()); + compositionRequest.layers[0].source = createImageTransitionInfo(source.get()), compositionRequest.layers[0].props.displayFrame.left = (i + 0) * displayFrameWidth; compositionRequest.layers[0].props.displayFrame.right = (i + 1) * displayFrameWidth; @@ -973,11 +979,11 @@ TEST_F(CompositorVkTest, MultipleLayers) { ASSERT_NE(target, nullptr); fillImageWith(target.get(), kColorBlack); - Compositor::CompositionRequest compositionRequest = { - .target = createBorrowedImageInfo(target.get()), + CompositionRequestVk compositionRequest = { + .target = createImageTransitionInfo(target.get()), }; - compositionRequest.layers.emplace_back(Compositor::CompositionRequestLayer{ - .source = createBorrowedImageInfo(source1.get()), + compositionRequest.layers.emplace_back(CompositionRequestLayerVk{ + .source = createImageTransitionInfo(source1.get()), .props = { .composeMode = HWC2_COMPOSITION_DEVICE, @@ -1007,8 +1013,8 @@ TEST_F(CompositorVkTest, MultipleLayers) { .transform = HWC_TRANSFORM_NONE, }, }); - compositionRequest.layers.emplace_back(Compositor::CompositionRequestLayer{ - .source = createBorrowedImageInfo(source2.get()), + compositionRequest.layers.emplace_back(CompositionRequestLayerVk{ + .source = createImageTransitionInfo(source2.get()), .props = { .composeMode = HWC2_COMPOSITION_DEVICE, @@ -1038,8 +1044,8 @@ TEST_F(CompositorVkTest, MultipleLayers) { .transform = HWC_TRANSFORM_ROT_90, }, }); - compositionRequest.layers.emplace_back(Compositor::CompositionRequestLayer{ - .source = createBorrowedImageInfo(source2.get()), + compositionRequest.layers.emplace_back(CompositionRequestLayerVk{ + .source = createImageTransitionInfo(source2.get()), .props = { .composeMode = HWC2_COMPOSITION_DEVICE, diff --git a/host/vulkan/display_vk.cpp b/host/vulkan/display_vk.cpp index 0489c71f4..a99eaf3b3 100644 --- a/host/vulkan/display_vk.cpp +++ b/host/vulkan/display_vk.cpp @@ -22,6 +22,7 @@ #include "gfxstream/common/logging.h" #include "gfxstream/host/display_operations.h" #include "gfxstream/system/System.h" +#include "vulkan/color_buffer_vk.h" #include "vulkan/vk_enum_string_helper.h" #include "vulkan/vk_format_utils.h" @@ -268,7 +269,7 @@ DisplayVk::PostResult DisplayVk::postImpl(const Post& postCmd) { struct ImageBorrower { ImageBorrower(const VulkanDispatch& vk, VkQueue queue, std::shared_ptr queueLock, - uint32_t usedQueueFamilyIndex, const BorrowedImageInfoVk& image, + uint32_t usedQueueFamilyIndex, const ColorBufferVkImageInfo& image, const ImageBorrowResource& acquireResource, const ImageBorrowResource& releaseResource, VkImageLayout layout) : m_vk(vk), @@ -284,8 +285,9 @@ DisplayVk::PostResult DisplayVk::postImpl(const Post& postCmd) { accessMask = VK_ACCESS_SHADER_READ_BIT; } - addNeededBarriersToUseBorrowedImage( - image, usedQueueFamilyIndex, + vk_util::addNeededBarriersToUseImage( + image.image, image.preBorrowQueueFamilyIndex, image.preBorrowLayout, + image.postBorrowQueueFamilyIndex, image.postBorrowLayout, usedQueueFamilyIndex, /*usedInitialImageLayout=*/layout, /*usedFinalImageLayout=*/layout, accessMask, &acquireQueueTransferBarriers, &acquireLayoutTransitionBarriers, &releaseLayoutTransitionBarriers, @@ -407,7 +409,7 @@ DisplayVk::PostResult DisplayVk::postImpl(const Post& postCmd) { const auto& layer = postCmd.layers[0]; if (layer.rotationDegrees == 0 && !layer.colorTransform.has_value() && hwc_rect_get_width(&layer.displayFrame) == 0 && !postCmd.colorTransform.has_value()) { - const auto* sourceImageInfoVk = static_cast(layer.info); + const auto* sourceImageInfoVk = layer.info; if (canPost(sourceImageInfoVk->imageCreateInfo)) { useBlit = true; } @@ -419,7 +421,7 @@ DisplayVk::PostResult DisplayVk::postImpl(const Post& postCmd) { for (size_t i = 0; i < postCmd.layers.size(); ++i) { const auto& layer = postCmd.layers[i]; - const auto* sourceImageInfoVk = static_cast(layer.info); + const auto* sourceImageInfoVk = layer.info; VkImageLayout layout = useBlit ? VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; @@ -560,7 +562,7 @@ DisplayVk::PostResult DisplayVk::postImpl(const Post& postCmd) { if (useBlit) { // Use vkCmdBlitImage to post the image (single image optimized path) const auto& layer = postCmd.layers[0]; - const auto* sourceImageInfoVk = static_cast(layer.info); + const auto* sourceImageInfoVk = layer.info; VkImageMemoryBarrier acquireSwapchainImageBarrier = { .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, .srcAccessMask = curSrcAccessMask, @@ -663,7 +665,7 @@ DisplayVk::PostResult DisplayVk::postImpl(const Post& postCmd) { for (size_t i = 0; i < postCmd.layers.size(); ++i) { const auto& layer = postCmd.layers[i]; - const auto* sourceImageInfoVk = static_cast(layer.info); + const auto* sourceImageInfoVk = layer.info; // Strictly disable skin/mask if multi-display mode is active, regardless of image count bool isMultiDisplay = postCmd.layers.size() > 1; bool disableMask = isMultiDisplay; diff --git a/host/vulkan/display_vk.h b/host/vulkan/display_vk.h index 0ec82eb0b..2988eaee8 100644 --- a/host/vulkan/display_vk.h +++ b/host/vulkan/display_vk.h @@ -27,7 +27,6 @@ #include "compositor_vk.h" #include "debug_utils_helper.h" #include "display_surface_vk.h" -#include "gfxstream/host/borrowed_image.h" #include "gfxstream/host/display.h" #include "gfxstream/synchronization/Lock.h" #include "goldfish_vk_dispatch.h" @@ -41,6 +40,8 @@ namespace gfxstream { namespace host { namespace vk { +struct ColorBufferVkImageInfo; + class DisplayVk : public Display { public: DisplayVk(const VulkanDispatch&, VkPhysicalDevice, VkDevice, CompositorVk* compositorVk, @@ -52,7 +53,7 @@ class DisplayVk : public Display { ~DisplayVk(); struct PostLayer { - const BorrowedImageInfo* info; + const ColorBufferVkImageInfo* info; float rotationDegrees; std::optional> colorTransform; hwc_rect_t displayFrame; diff --git a/host/vulkan/display_vk_unittest.cpp b/host/vulkan/display_vk_unittest.cpp index 6fc88ccb0..24797e7e3 100644 --- a/host/vulkan/display_vk_unittest.cpp +++ b/host/vulkan/display_vk_unittest.cpp @@ -18,11 +18,11 @@ #include "display_vk.h" -#include "borrowed_image_vk.h" -#include "gfxstream/synchronization/Lock.h" -#include "gfxstream/host/testing/SampleApplication.h" +#include "color_buffer_vk.h" #include "gfxstream/host/testing/OSWindow.h" +#include "gfxstream/host/testing/SampleApplication.h" #include "gfxstream/host/testing/VkTestUtils.h" +#include "gfxstream/synchronization/Lock.h" #include "vulkan/vulkan_dispatch.h" namespace gfxstream { @@ -82,11 +82,11 @@ class DisplayVkTest : public ::testing::Test { } } - std::unique_ptr createBorrowedImageInfo( + std::unique_ptr createImageTransitionInfo( const std::unique_ptr& texture) { static uint32_t sTextureId = 0; - auto info = std::make_unique(); + auto info = std::make_unique(); info->id = sTextureId++; info->width = texture->m_vkImageCreateInfo.extent.width; info->height = texture->m_vkImageCreateInfo.extent.height; @@ -238,7 +238,7 @@ TEST_F(DisplayVkTest, PostWithoutSurfaceShouldntCrash) { m_vkCommandPool, textureWidth, textureHeight); std::vector pixels(textureWidth * textureHeight, 0); ASSERT_TRUE(texture->write(pixels)); - const auto imageInfo = createBorrowedImageInfo(texture); + const auto imageInfo = createImageTransitionInfo(texture); DisplayVk::Post postCmd; DisplayVk::PostLayer layer; layer.info = imageInfo.get(); @@ -266,7 +266,7 @@ TEST_F(DisplayVkTest, SimplePost) { ASSERT_TRUE(texture->write(pixels)); std::vector> waitForGpuFutures; for (uint32_t i = 0; i < 10; i++) { - const auto imageInfo = createBorrowedImageInfo(texture); + const auto imageInfo = createImageTransitionInfo(texture); DisplayVk::Post postCmd; DisplayVk::PostLayer layer; layer.info = imageInfo.get(); @@ -299,8 +299,8 @@ TEST_F(DisplayVkTest, PostTwoColorBuffers) { ASSERT_TRUE(greenTexture->write(greenPixels)); std::vector> waitForGpuFutures; for (uint32_t i = 0; i < 10; i++) { - const auto redImageInfo = createBorrowedImageInfo(redTexture); - const auto greenImageInfo = createBorrowedImageInfo(greenTexture); + const auto redImageInfo = createImageTransitionInfo(redTexture); + const auto greenImageInfo = createImageTransitionInfo(greenTexture); DisplayVk::Post redPostCmd; DisplayVk::PostLayer redLayer; redLayer.info = redImageInfo.get(); @@ -344,7 +344,7 @@ TEST_F(DisplayVkTest, PostWithRotation) { ASSERT_TRUE(texture->write(pixels)); std::vector> waitForGpuFutures; for (uint32_t i = 0; i < 10; i++) { - const auto imageInfo = createBorrowedImageInfo(texture); + const auto imageInfo = createImageTransitionInfo(texture); DisplayVk::Post postCmd; DisplayVk::PostLayer layer; layer.info = imageInfo.get(); @@ -379,7 +379,7 @@ TEST_F(DisplayVkTest, PostWithColorTransform) { ASSERT_TRUE(texture->write(pixels)); std::vector> waitForGpuFutures; for (uint32_t i = 0; i < 10; i++) { - const auto imageInfo = createBorrowedImageInfo(texture); + const auto imageInfo = createImageTransitionInfo(texture); DisplayVk::Post postCmd; DisplayVk::PostLayer layer; layer.info = imageInfo.get(); @@ -414,8 +414,8 @@ TEST_F(DisplayVkTest, PostMultiDisplayComposition) { std::vector> waitForGpuFutures; for (uint32_t i = 0; i < 10; i++) { - const auto redImageInfo = createBorrowedImageInfo(redTexture); - const auto greenImageInfo = createBorrowedImageInfo(greenTexture); + const auto redImageInfo = createImageTransitionInfo(redTexture); + const auto greenImageInfo = createImageTransitionInfo(greenTexture); DisplayVk::Post postCmd; // Combined frame size (side-by-side) diff --git a/host/vulkan/meson.build b/host/vulkan/meson.build index 6bc04c3a6..c09233172 100644 --- a/host/vulkan/meson.build +++ b/host/vulkan/meson.build @@ -9,7 +9,6 @@ subdir('cereal') subdir('emulated_textures') files_lib_vulkan_server = files( - 'borrowed_image_vk.cpp', 'buffer_vk.cpp', 'color_buffer_vk.cpp', 'compositor_vk.cpp', diff --git a/host/vulkan/post_worker_vk.cpp b/host/vulkan/post_worker_vk.cpp index 11e76a4d9..1966dcb5b 100644 --- a/host/vulkan/post_worker_vk.cpp +++ b/host/vulkan/post_worker_vk.cpp @@ -15,11 +15,12 @@ */ #include "post_worker_vk.h" -#include "host/frame_buffer.h" +#include "gfxstream/common/logging.h" #include "gfxstream/host/display_operations.h" #include "gfxstream/host/renderer_operations.h" #include "gfxstream/host/window_operations.h" -#include "gfxstream/common/logging.h" +#include "host/frame_buffer.h" +#include "vulkan/color_buffer_vk.h" #include "vulkan/display_vk.h" namespace gfxstream { @@ -54,13 +55,15 @@ std::shared_future PostWorkerVk::postImpl( GFXSTREAM_FATAL("PostWorker missing DisplayVk."); } - std::vector> borrowedImages; + std::vector> borrowedImages; DisplayVk::Post postCmd; auto addPostImage = [&](IColorBuffer* colorBuffer, int32_t x, int32_t y, int32_t w, int32_t h, float rotation, const std::optional>& transform = std::nullopt) { - auto info = mFb->borrowColorBufferForDisplay(colorBuffer->getHndl()); + colorBuffer->invalidateForBackend(Backend::VK); + auto cbVk = colorBuffer->getColorBufferVk(); + auto info = cbVk ? cbVk->prepareForDisplay() : nullptr; if (!info) return; DisplayVk::PostLayer layer; diff --git a/host/vulkan/vk_common_operations.cpp b/host/vulkan/vk_common_operations.cpp index d33d3acbf..cab8ad785 100644 --- a/host/vulkan/vk_common_operations.cpp +++ b/host/vulkan/vk_common_operations.cpp @@ -5125,7 +5125,7 @@ void VkEmulation::releaseColorBufferForGuestUse(uint32_t colorBufferHandle) { VK_CHECK(vk->vkWaitForFences(mDevice, 1, &fence, VK_TRUE, ANB_MAX_WAIT_NS)); } -std::unique_ptr VkEmulation::borrowColorBufferForComposition( +std::unique_ptr VkEmulation::prepareColorBufferForComposition( uint32_t colorBufferHandle, bool colorBufferIsTarget) { std::lock_guard lock(mMutex); @@ -5135,7 +5135,7 @@ std::unique_ptr VkEmulation::borrowColorBufferForCompositio return nullptr; } - auto compositorInfo = std::make_unique(); + auto compositorInfo = std::make_unique(); compositorInfo->id = colorBufferInfo->handle; compositorInfo->width = colorBufferInfo->imageCreateInfoShallow.extent.width; compositorInfo->height = colorBufferInfo->imageCreateInfoShallow.extent.height; @@ -5167,7 +5167,7 @@ std::unique_ptr VkEmulation::borrowColorBufferForCompositio return compositorInfo; } -std::unique_ptr VkEmulation::borrowColorBufferForDisplay( +std::unique_ptr VkEmulation::prepareColorBufferForDisplay( uint32_t colorBufferHandle) { std::lock_guard lock(mMutex); @@ -5177,7 +5177,7 @@ std::unique_ptr VkEmulation::borrowColorBufferForDisplay( return nullptr; } - auto compositorInfo = std::make_unique(); + auto compositorInfo = std::make_unique(); compositorInfo->id = colorBufferInfo->handle; compositorInfo->width = colorBufferInfo->imageCreateInfoShallow.extent.width; compositorInfo->height = colorBufferInfo->imageCreateInfoShallow.extent.height; @@ -5199,6 +5199,18 @@ std::unique_ptr VkEmulation::borrowColorBufferForDisplay( return compositorInfo; } +void VkEmulation::updateColorBufferLayoutAndQueue(uint32_t colorBufferHandle, VkImageLayout layout, + uint32_t queueFamilyIndex) { + std::lock_guard lock(mMutex); + auto colorBufferInfo = gfxstream::base::find(mColorBuffers, colorBufferHandle); + if (!colorBufferInfo) { + GFXSTREAM_ERROR("Invalid ColorBuffer handle %d.", static_cast(colorBufferHandle)); + return; + } + colorBufferInfo->currentLayout = layout; + colorBufferInfo->currentQueueFamilyIndex = queueFamilyIndex; +} + std::optional VkEmulation::findRepresentativeColorBufferMemoryTypeIndexLocked() { constexpr const uint32_t kArbitraryWidth = 64; diff --git a/host/vulkan/vk_common_operations.h b/host/vulkan/vk_common_operations.h index 8ba6a0e1d..861ceb047 100644 --- a/host/vulkan/vk_common_operations.h +++ b/host/vulkan/vk_common_operations.h @@ -23,22 +23,22 @@ #include #include -#include "borrowed_image_vk.h" +#include "color_buffer_vk.h" #include "compositor_vk.h" #include "debug_utils_helper.h" #include "device_lost_helper.h" #include "display_vk.h" #include "external_memory.h" +#include "gfxstream/Optional.h" +#include "gfxstream/ThreadAnnotations.h" +#include "gfxstream/host/GfxApiLogger.h" +#include "gfxstream/host/RenderDoc.h" #include "gfxstream/host/backend_callbacks.h" #include "gfxstream/host/external_object_manager.h" #include "gfxstream/host/features.h" #include "gfxstream/host/gfxstream_format.h" -#include "gfxstream/host/GfxApiLogger.h" -#include "gfxstream/host/RenderDoc.h" #include "gfxstream/host/vk_enums.h" #include "gfxstream/memory/UdmabufCreator.h" -#include "gfxstream/Optional.h" -#include "gfxstream/ThreadAnnotations.h" #include "goldfish_vk_private_defs.h" #include "host/framework_formats.h" #include "render-utils/Renderer.h" @@ -451,9 +451,12 @@ class VkEmulation { void releaseColorBufferForGuestUse(uint32_t colorBufferHandle); - std::unique_ptr borrowColorBufferForComposition(uint32_t colorBufferHandle, - bool colorBufferIsTarget); - std::unique_ptr borrowColorBufferForDisplay(uint32_t colorBufferHandle); + std::unique_ptr prepareColorBufferForComposition( + uint32_t colorBufferHandle, bool colorBufferIsTarget); + std::unique_ptr prepareColorBufferForDisplay( + uint32_t colorBufferHandle); + void updateColorBufferLayoutAndQueue(uint32_t colorBufferHandle, VkImageLayout layout, + uint32_t queueFamilyIndex); void applyApiVersionLimits(uint32_t& apiVersion) const { if (apiVersion > mGuestVulkanMaxApiVersion) { diff --git a/host/vulkan/vk_utils.cpp b/host/vulkan/vk_utils.cpp index 77f44253e..18b5335a9 100644 --- a/host/vulkan/vk_utils.cpp +++ b/host/vulkan/vk_utils.cpp @@ -404,6 +404,106 @@ bool YcbcrSamplerPool::getOrCreateSamplerInfo(GfxstreamFormat format, YCbCrSampl return true; } +void addNeededBarriersToUseImage(VkImage image, uint32_t preQueueFamilyIndex, + VkImageLayout preLayout, uint32_t postQueueFamilyIndex, + VkImageLayout postLayout, uint32_t usedQueueFamilyIndex, + VkImageLayout usedInitialImageLayout, + VkImageLayout usedFinalImageLayout, VkAccessFlags usedAccessMask, + std::vector* preUseQueueTransferBarriers, + std::vector* preUseLayoutTransitionBarriers, + std::vector* postUseLayoutTransitionBarriers, + std::vector* postUseQueueTransferBarriers) { + if (preQueueFamilyIndex != usedQueueFamilyIndex) { + const VkImageMemoryBarrier queueTransferBarrier = { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, + .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, + .oldLayout = preLayout, + .newLayout = preLayout, + .srcQueueFamilyIndex = preQueueFamilyIndex, + .dstQueueFamilyIndex = usedQueueFamilyIndex, + .image = image, + .subresourceRange = + { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, + }; + preUseQueueTransferBarriers->emplace_back(queueTransferBarrier); + } + if (preLayout != usedInitialImageLayout && + usedInitialImageLayout != VK_IMAGE_LAYOUT_UNDEFINED) { + const VkImageMemoryBarrier layoutTransitionBarrier = { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, + .dstAccessMask = usedAccessMask, + .oldLayout = preLayout, + .newLayout = usedInitialImageLayout, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = image, + .subresourceRange = + { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, + }; + preUseLayoutTransitionBarriers->emplace_back(layoutTransitionBarrier); + } + if (postLayout != usedFinalImageLayout) { + const VkImageMemoryBarrier layoutTransitionBarrier = { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = usedAccessMask, + .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, + .oldLayout = usedFinalImageLayout, + .newLayout = postLayout, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = image, + .subresourceRange = + { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, + }; + postUseLayoutTransitionBarriers->emplace_back(layoutTransitionBarrier); + } + if (postQueueFamilyIndex != usedQueueFamilyIndex) { + const VkImageMemoryBarrier queueTransferBarrier = { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, + .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, + .oldLayout = postLayout, + .newLayout = postLayout, + .srcQueueFamilyIndex = usedQueueFamilyIndex, + .dstQueueFamilyIndex = postQueueFamilyIndex, + .image = image, + .subresourceRange = + { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, + }; + postUseQueueTransferBarriers->emplace_back(queueTransferBarrier); + } +} + } // namespace vk_util } // namespace vk } // namespace host diff --git a/host/vulkan/vk_utils.h b/host/vulkan/vk_utils.h index 4ea1d8ed8..67bb09ccf 100644 --- a/host/vulkan/vk_utils.h +++ b/host/vulkan/vk_utils.h @@ -407,6 +407,16 @@ class YcbcrSamplerPool { std::unordered_map m_ycbcrSamplers GUARDED_BY(mMutex); }; +void addNeededBarriersToUseImage(VkImage image, uint32_t preQueueFamilyIndex, + VkImageLayout preLayout, uint32_t postQueueFamilyIndex, + VkImageLayout postLayout, uint32_t usedQueueFamilyIndex, + VkImageLayout usedInitialImageLayout, + VkImageLayout usedFinalImageLayout, VkAccessFlags usedAccessMask, + std::vector* preUseQueueTransferBarriers, + std::vector* preUseLayoutTransitionBarriers, + std::vector* postUseLayoutTransitionBarriers, + std::vector* postUseQueueTransferBarriers); + } // namespace vk_util } // namespace vk } // namespace host From 51ffc07c690380deca2eb58f3600e53219b7749b Mon Sep 17 00:00:00 2001 From: Jason Macnak Date: Fri, 24 Jul 2026 10:16:32 -0700 Subject: [PATCH 13/33] Convert BackendCallbacks to a GlobalState interface Bug: b/537737772 Test: bazel test //host/... Low-Coverage-Reason: REFACTOR_ONLY Change-Id: I5d19bb6c012d5c4e7b9c1ef5281e8303671f5956 --- .../gfxstream/host/backend_callbacks.h | 54 ----------- .../include/gfxstream/host/global_state.h | 46 ++++++++++ host/frame_buffer.cpp | 92 +++++++++---------- .../vk_android_native_buffer_operations.cpp | 6 +- .../vk_android_native_buffer_operations.h | 1 - host/vulkan/vk_common_operations.cpp | 7 +- host/vulkan/vk_common_operations.h | 8 +- host/vulkan/vk_decoder_global_state.cpp | 16 ++-- 8 files changed, 109 insertions(+), 121 deletions(-) delete mode 100644 host/common/include/gfxstream/host/backend_callbacks.h create mode 100644 host/common/include/gfxstream/host/global_state.h diff --git a/host/common/include/gfxstream/host/backend_callbacks.h b/host/common/include/gfxstream/host/backend_callbacks.h deleted file mode 100644 index cd764f141..000000000 --- a/host/common/include/gfxstream/host/backend_callbacks.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2024 The Android Open Source Project -// -// 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 expresso or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include - -#include "gfxstream/CancelableFuture.h" - -namespace gfxstream { -namespace host { - -struct BackendCallbacks { - using RegisterProcessCleanupCallbackFunc = - std::function callback)>; - RegisterProcessCleanupCallbackFunc registerProcessCleanupCallback; - - using UnregisterProcessCleanupCallbackFunc = std::function; - UnregisterProcessCleanupCallbackFunc unregisterProcessCleanupCallback; - - using InvalidateColorBufferFunc = std::function; - InvalidateColorBufferFunc invalidateColorBuffer; - - using FlushColorBufferFunc = std::function; - FlushColorBufferFunc flushColorBuffer; - - using FlushColorBufferFromBytesFunc = - std::function; - FlushColorBufferFromBytesFunc flushColorBufferFromBytes; - - using ScheduleAsyncWorkFunc = - std::function work, std::string description)>; - ScheduleAsyncWorkFunc scheduleAsyncWork; - - using RegisterVulkanInstanceFunc = std::function; - RegisterVulkanInstanceFunc registerVulkanInstance; - - using UnregisterVulkanInstanceFunc = std::function; - UnregisterVulkanInstanceFunc unregisterVulkanInstance; -}; - -} // namespace host -} // namespace gfxstream diff --git a/host/common/include/gfxstream/host/global_state.h b/host/common/include/gfxstream/host/global_state.h new file mode 100644 index 000000000..55ebd05e2 --- /dev/null +++ b/host/common/include/gfxstream/host/global_state.h @@ -0,0 +1,46 @@ +// Copyright 2026 The Android Open Source Project +// +// 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 expresso or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +#include "gfxstream/CancelableFuture.h" + +namespace gfxstream { +namespace host { + +class GlobalState { + public: + virtual ~GlobalState() = default; + + virtual void registerProcessCleanupCallback(void* key, uint64_t contextId, + std::function callback) = 0; + virtual void unregisterProcessCleanupCallback(void* key) = 0; + + virtual void invalidateColorBuffer(uint32_t colorBufferHandle) = 0; + virtual void flushColorBuffer(uint32_t colorBufferHandle) = 0; + virtual void flushColorBufferFromBytes(uint32_t colorBufferHandle, const void* bytes, + size_t bytesSize) = 0; + + virtual CancelableFuture scheduleAsyncWork(std::function work, + std::string description) = 0; + + virtual void registerVulkanInstance(uint64_t id, const char* appName) const {} + virtual void unregisterVulkanInstance(uint64_t id) const {} +}; + +} // namespace host +} // namespace gfxstream diff --git a/host/frame_buffer.cpp b/host/frame_buffer.cpp index e35ce3176..ffe7c0627 100644 --- a/host/frame_buffer.cpp +++ b/host/frame_buffer.cpp @@ -22,6 +22,8 @@ #include +#include "gfxstream/host/global_state.h" + #if defined(__linux__) #include #endif @@ -361,7 +363,8 @@ typedef std::unordered_map ProcOwnedColorBuffers; typedef std::unordered_map> CallbackMap; typedef std::unordered_map ProcOwnedCleanupCallbacks; -class FrameBuffer::Impl : public gfxstream::base::EventNotificationSupport { +class FrameBuffer::Impl : public gfxstream::base::EventNotificationSupport, + public GlobalState { public: static std::unique_ptr Create(FrameBuffer* framebuffer, uint32_t width, uint32_t height, const FeatureSet& features, bool useSubWindow); @@ -518,8 +521,8 @@ class FrameBuffer::Impl : public gfxstream::base::EventNotificationSupport callback); - void unregisterProcessCleanupCallback(void* key); + std::function callback) override; + void unregisterProcessCleanupCallback(void* key) override; + + void invalidateColorBuffer(uint32_t colorBufferHandle) override; + void flushColorBuffer(uint32_t colorBufferHandle) override; + void flushColorBufferFromBytes(uint32_t colorBufferHandle, const void* bytes, + size_t bytesSize) override; + CancelableFuture scheduleAsyncWork(std::function work, + std::string description) override; const ProcessResources* getProcessResources(uint64_t puid); @@ -1244,48 +1254,7 @@ std::unique_ptr FrameBuffer::Impl::Create(FrameBuffer* frameb if (impl->m_features.Vulkan.enabled()) { vkDispatch = vk::vkDispatch(false /* not for testing */); - gfxstream::host::BackendCallbacks callbacks{ - .registerProcessCleanupCallback = - [impl = impl.get()](void* key, uint64_t contextId, std::function callback) { - impl->registerProcessCleanupCallback(key, contextId, callback); - }, - .unregisterProcessCleanupCallback = - [impl = impl.get()](void* key) { impl->unregisterProcessCleanupCallback(key); }, - .invalidateColorBuffer = - [impl = impl.get()](uint32_t colorBufferHandle) { - impl->invalidateColorBufferForVk(colorBufferHandle); - }, - .flushColorBuffer = - [impl = impl.get()](uint32_t colorBufferHandle) { - impl->flushColorBufferFromVk(colorBufferHandle); - }, - .flushColorBufferFromBytes = - [impl = impl.get()](uint32_t colorBufferHandle, const void* bytes, - size_t bytesSize) { - impl->flushColorBufferFromVkBytes(colorBufferHandle, bytes, bytesSize); - }, - .scheduleAsyncWork = - [impl = impl.get()](std::function work, std::string description) { - auto promise = std::make_shared(); - auto future = promise->GetFuture(); - SyncThread::get()->triggerGeneral( - [promise = std::move(promise), work = std::move(work)]() mutable { - work(); - promise->MarkComplete(); - }, - description); - return future; - }, -#ifdef CONFIG_AEMU - .registerVulkanInstance = - [impl = impl.get()](uint64_t id, const char* appName) { - impl->registerVulkanInstance(id, appName); - }, - .unregisterVulkanInstance = - [impl = impl.get()](uint64_t id) { impl->unregisterVulkanInstance(id); }, -#endif - }; - impl->m_emulationVk = vk::VkEmulation::create(vkDispatch, callbacks, impl->m_features); + impl->m_emulationVk = vk::VkEmulation::create(vkDispatch, impl.get(), impl->m_features); if (!impl->m_emulationVk) { GFXSTREAM_ERROR( "Failed to initialize global Vulkan emulation requested. Try updating your GPU " @@ -3734,6 +3703,32 @@ void FrameBuffer::Impl::unregisterProcessCleanupCallback(void* key) { } } +void FrameBuffer::Impl::invalidateColorBuffer(uint32_t colorBufferHandle) { + invalidateColorBufferForVk(colorBufferHandle); +} + +void FrameBuffer::Impl::flushColorBuffer(uint32_t colorBufferHandle) { + flushColorBufferFromVk(colorBufferHandle); +} + +void FrameBuffer::Impl::flushColorBufferFromBytes(uint32_t colorBufferHandle, const void* bytes, + size_t bytesSize) { + flushColorBufferFromVkBytes(colorBufferHandle, bytes, bytesSize); +} + +CancelableFuture FrameBuffer::Impl::scheduleAsyncWork(std::function work, + std::string description) { + auto promise = std::make_shared(); + auto future = promise->GetFuture(); + SyncThread::get()->triggerGeneral( + [promise = std::move(promise), work = std::move(work)]() mutable { + work(); + promise->MarkComplete(); + }, + description); + return future; +} + const ProcessResources* FrameBuffer::Impl::getProcessResources(uint64_t puid) { { AutoLock mutex(m_procOwnedResourcesLock); @@ -4072,6 +4067,9 @@ void FrameBuffer::Impl::registerVulkanInstance(uint64_t id, const char* appName) void FrameBuffer::Impl::unregisterVulkanInstance(uint64_t id) const { get_gfxstream_vm_operations().unregister_vulkan_instance(id); } +#else +void FrameBuffer::Impl::registerVulkanInstance(uint64_t id, const char* appName) const {} +void FrameBuffer::Impl::unregisterVulkanInstance(uint64_t id) const {} #endif void FrameBuffer::Impl::createTrivialContext(HandleType shared, HandleType* contextOut, diff --git a/host/vulkan/vk_android_native_buffer_operations.cpp b/host/vulkan/vk_android_native_buffer_operations.cpp index daf0040cf..968afcf29 100644 --- a/host/vulkan/vk_android_native_buffer_operations.cpp +++ b/host/vulkan/vk_android_native_buffer_operations.cpp @@ -19,7 +19,7 @@ #include "cereal/common/goldfish_vk_deepcopy.h" #include "cereal/common/goldfish_vk_extension_structs.h" #include "frame_buffer.h" -#include "gfxstream/host/backend_callbacks.h" +#include "gfxstream/host/global_state.h" #include "gfxstream/host/tracing.h" #include "goldfish_vk_private_defs.h" #include "gralloc_defs.h" @@ -855,7 +855,7 @@ VkResult AndroidNativeBufferInfo::on_vkQueueSignalReleaseImageANDROID( VK_ANB_DEBUG_OBJ(this, "using native image, so use sync thread to wait"); // Queue wait to sync thread with completion callback // Pass anbInfo by value to get a ref - auto waitable = emu->getCallbacks().scheduleAsyncWork( + auto waitable = emu->getGlobalState()->scheduleAsyncWork( [waitForQsriFenceTask = std::move(waitForQsriFenceTask), this]() mutable { waitForQsriFenceTask(); mQsriTimeline->signalNextPresentAndPoll(); @@ -880,7 +880,7 @@ VkResult AndroidNativeBufferInfo::on_vkQueueSignalReleaseImageANDROID( string_VkFormat(mVkFormat), mVkFormat); } else { const size_t bytesSize = bytesPerPixel * mExtent.width * mExtent.height; - emu->getCallbacks().flushColorBufferFromBytes(mColorBufferHandle, bytes, bytesSize); + emu->getGlobalState()->flushColorBufferFromBytes(mColorBufferHandle, bytes, bytesSize); } mQsriTimeline->signalNextPresentAndPoll(); diff --git a/host/vulkan/vk_android_native_buffer_operations.h b/host/vulkan/vk_android_native_buffer_operations.h index 889a386ef..7848f5591 100644 --- a/host/vulkan/vk_android_native_buffer_operations.h +++ b/host/vulkan/vk_android_native_buffer_operations.h @@ -26,7 +26,6 @@ #include "gfxstream/AsyncResult.h" #include "gfxstream/BumpPool.h" #include "gfxstream/ThreadAnnotations.h" -#include "gfxstream/host/backend_callbacks.h" #include "gfxstream/synchronization/ConditionVariable.h" #include "gfxstream/synchronization/Lock.h" #include "goldfish_vk_private_defs.h" diff --git a/host/vulkan/vk_common_operations.cpp b/host/vulkan/vk_common_operations.cpp index cab8ad785..fc7ce841f 100644 --- a/host/vulkan/vk_common_operations.cpp +++ b/host/vulkan/vk_common_operations.cpp @@ -769,9 +769,8 @@ int VkEmulation::getSelectedGpuIndex( return selectedGpuIndex; } -/*static*/ std::unique_ptr VkEmulation::create(VulkanDispatch* gvk, - gfxstream::host::BackendCallbacks callbacks, + gfxstream::host::GlobalState* globalState, const gfxstream::host::FeatureSet& features) { if (!vkDispatchValid(gvk)) { GFXSTREAM_ERROR("Dispatch is invalid."); @@ -782,7 +781,7 @@ std::unique_ptr VkEmulation::create(VulkanDispatch* gvk, std::lock_guard lock(emulation->mMutex); - emulation->mCallbacks = callbacks; + emulation->m_globalState = globalState; emulation->mGvk = gvk; emulation->setFeatures(features); @@ -1914,7 +1913,7 @@ void VkEmulation::setFeatures(const gfxstream::host::FeatureSet& features) { #endif } -const gfxstream::host::BackendCallbacks& VkEmulation::getCallbacks() const { return mCallbacks; } +gfxstream::host::GlobalState* VkEmulation::getGlobalState() const { return m_globalState; } AstcEmulationMode VkEmulation::getAstcLdrEmulationMode() const { return mAstcLdrEmulationMode; } diff --git a/host/vulkan/vk_common_operations.h b/host/vulkan/vk_common_operations.h index 861ceb047..193271857 100644 --- a/host/vulkan/vk_common_operations.h +++ b/host/vulkan/vk_common_operations.h @@ -33,10 +33,10 @@ #include "gfxstream/ThreadAnnotations.h" #include "gfxstream/host/GfxApiLogger.h" #include "gfxstream/host/RenderDoc.h" -#include "gfxstream/host/backend_callbacks.h" #include "gfxstream/host/external_object_manager.h" #include "gfxstream/host/features.h" #include "gfxstream/host/gfxstream_format.h" +#include "gfxstream/host/global_state.h" #include "gfxstream/host/vk_enums.h" #include "gfxstream/memory/UdmabufCreator.h" #include "goldfish_vk_private_defs.h" @@ -96,7 +96,7 @@ class VkEmulation { ~VkEmulation(); static std::unique_ptr create(VulkanDispatch* vk, - gfxstream::host::BackendCallbacks callbacks, + gfxstream::host::GlobalState* globalState, const gfxstream::host::FeatureSet& features); struct Features { @@ -171,7 +171,7 @@ class VkEmulation { const gfxstream::host::FeatureSet& getFeatures() const; - const gfxstream::host::BackendCallbacks& getCallbacks() const; + gfxstream::host::GlobalState* getGlobalState() const; AstcEmulationMode getAstcLdrEmulationMode() const; @@ -572,7 +572,7 @@ class VkEmulation { std::mutex mMutex; - gfxstream::host::BackendCallbacks mCallbacks; + gfxstream::host::GlobalState* m_globalState = nullptr; gfxstream::host::FeatureSet mFeatures; diff --git a/host/vulkan/vk_decoder_global_state.cpp b/host/vulkan/vk_decoder_global_state.cpp index ad7f23cdf..e4a1d9ab9 100644 --- a/host/vulkan/vk_decoder_global_state.cpp +++ b/host/vulkan/vk_decoder_global_state.cpp @@ -1217,8 +1217,8 @@ class VkDecoderGlobalState::Impl { info.applicationName.c_str(), info.engineName.c_str()); #ifdef CONFIG_AEMU - m_vkEmulation->getCallbacks().registerVulkanInstance((uint64_t)*pInstance, - info.applicationName.c_str()); + m_vkEmulation->getGlobalState()->registerVulkanInstance((uint64_t)*pInstance, + info.applicationName.c_str()); #endif // Box it up VkInstance boxed = new_boxed_VkInstance(*pInstance, nullptr); @@ -1241,7 +1241,7 @@ class VkDecoderGlobalState::Impl { *pInstance = (VkInstance)info.boxed; if (vkCleanupEnabled()) { - m_vkEmulation->getCallbacks().registerProcessCleanupCallback( + m_vkEmulation->getGlobalState()->registerProcessCleanupCallback( unbox_VkInstance(boxed), info.contextId, [this, boxed] { if (snapshotsEnabled()) { snapshot()->vkDestroyInstance(nullptr, kInvalidSnapshotApiCallHandle, nullptr, 0, boxed, nullptr); @@ -1300,7 +1300,7 @@ class VkDecoderGlobalState::Impl { } // The instance should not be used after vkDestroyInstanceImpl is called, // remove it from the cleanup callback mapping. - m_vkEmulation->getCallbacks().unregisterProcessCleanupCallback(instance); + m_vkEmulation->getGlobalState()->unregisterProcessCleanupCallback(instance); vkDestroyInstanceImpl(instance); } @@ -6315,7 +6315,7 @@ class VkDecoderGlobalState::Impl { shouldUseDedicatedAllocInfo &= colorBufferMemoryUsesDedicatedAlloc; if (!m_vkEmulation->getFeatures().GuestVulkanOnly.enabled()) { - m_vkEmulation->getCallbacks().invalidateColorBuffer( + m_vkEmulation->getGlobalState()->invalidateColorBuffer( importCbInfoPtr->colorBuffer); } @@ -7785,7 +7785,7 @@ class VkDecoderGlobalState::Impl { } for (HandleType cb : acquiredColorBuffers) { - m_vkEmulation->getCallbacks().invalidateColorBuffer(cb); + m_vkEmulation->getGlobalState()->invalidateColorBuffer(cb); } if (m_vkEmulation->getFeatures().VulkanDisableCoherentMemoryAndEmulate.enabled()) { @@ -7952,7 +7952,7 @@ class VkDecoderGlobalState::Impl { string_VkResult(result), result); } else { for (HandleType cb : releasedColorBuffers) { - m_vkEmulation->getCallbacks().flushColorBuffer(cb); + m_vkEmulation->getGlobalState()->flushColorBuffer(cb); } } } else { @@ -10802,7 +10802,7 @@ class VkDecoderGlobalState::Impl { instanceInfo.applicationName.c_str(), instanceInfo.engineName.c_str()); #ifdef CONFIG_AEMU - m_vkEmulation->getCallbacks().unregisterVulkanInstance((uint64_t)instance); + m_vkEmulation->getGlobalState()->unregisterVulkanInstance((uint64_t)instance); #endif delete_VkInstance(instanceInfo.boxed); LOG_CALLS_VERBOSE("destroyInstanceObjects: finished."); From 1172a15733d4b26b32c55508225bb6851f183010 Mon Sep 17 00:00:00 2001 From: Jason Macnak Date: Fri, 24 Jul 2026 10:45:24 -0700 Subject: [PATCH 14/33] Decouple `vk_android_native_buffer_operations.cpp` from `FrameBuffer` ... by adding lock and unlock calls to the GlobalState interface Bug: b/537737772 Test: bazel test //host/... Low-Coverage-Reason: REFACTOR_ONLY Change-Id: I26b35adc766e1f45344a0d73cc23a53d29e3fe7f --- .../include/gfxstream/host/global_state.h | 3 +++ host/frame_buffer.cpp | 21 ++++++++++++------- .../vk_android_native_buffer_operations.cpp | 6 ++---- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/host/common/include/gfxstream/host/global_state.h b/host/common/include/gfxstream/host/global_state.h index 55ebd05e2..1e317eab4 100644 --- a/host/common/include/gfxstream/host/global_state.h +++ b/host/common/include/gfxstream/host/global_state.h @@ -30,6 +30,9 @@ class GlobalState { std::function callback) = 0; virtual void unregisterProcessCleanupCallback(void* key) = 0; + virtual void lockGlobalState() = 0; + virtual void unlockGlobalState() = 0; + virtual void invalidateColorBuffer(uint32_t colorBufferHandle) = 0; virtual void flushColorBuffer(uint32_t colorBufferHandle) = 0; virtual void flushColorBufferFromBytes(uint32_t colorBufferHandle, const void* bytes, diff --git a/host/frame_buffer.cpp b/host/frame_buffer.cpp index ffe7c0627..fe8e1e959 100644 --- a/host/frame_buffer.cpp +++ b/host/frame_buffer.cpp @@ -564,6 +564,9 @@ class FrameBuffer::Impl : public gfxstream::base::EventNotificationSupport callback) override; void unregisterProcessCleanupCallback(void* key) override; + void lockGlobalState() override; + void unlockGlobalState() override; + void invalidateColorBuffer(uint32_t colorBufferHandle) override; void flushColorBuffer(uint32_t colorBufferHandle) override; void flushColorBufferFromBytes(uint32_t colorBufferHandle, const void* bytes, @@ -3658,24 +3661,26 @@ void FrameBuffer::Impl::lock() { m_lock.lock(); } void FrameBuffer::Impl::unlock() { m_lock.unlock(); } +void FrameBuffer::Impl::lockGlobalState() NO_THREAD_SAFETY_ANALYSIS { lock(); } + +void FrameBuffer::Impl::unlockGlobalState() NO_THREAD_SAFETY_ANALYSIS { unlock(); } + ColorBufferPtr FrameBuffer::Impl::findColorBuffer(HandleType p_colorbuffer) { AutoLock colorBufferMapLock(m_colorBufferMapLock); - auto c = m_colorbuffers.find(p_colorbuffer); - if (c == m_colorbuffers.end()) { + auto it = m_colorbuffers.find(p_colorbuffer); + if (it == m_colorbuffers.end()) { return nullptr; - } else { - return std::dynamic_pointer_cast(c->second.cb); } + return std::dynamic_pointer_cast(it->second.cb); } BufferPtr FrameBuffer::Impl::findBuffer(HandleType p_buffer) { AutoLock colorBufferMapLock(m_colorBufferMapLock); - BufferMap::iterator b(m_buffers.find(p_buffer)); - if (b == m_buffers.end()) { + auto it = m_buffers.find(p_buffer); + if (it == m_buffers.end()) { return nullptr; - } else { - return b->second.buffer; } + return it->second.buffer; } void FrameBuffer::Impl::registerProcessCleanupCallback(void* key, uint64_t contextId, diff --git a/host/vulkan/vk_android_native_buffer_operations.cpp b/host/vulkan/vk_android_native_buffer_operations.cpp index 968afcf29..faca8879b 100644 --- a/host/vulkan/vk_android_native_buffer_operations.cpp +++ b/host/vulkan/vk_android_native_buffer_operations.cpp @@ -18,7 +18,6 @@ #include "cereal/common/goldfish_vk_deepcopy.h" #include "cereal/common/goldfish_vk_extension_structs.h" -#include "frame_buffer.h" #include "gfxstream/host/global_state.h" #include "gfxstream/host/tracing.h" #include "goldfish_vk_private_defs.h" @@ -674,8 +673,7 @@ VkResult AndroidNativeBufferInfo::on_vkQueueSignalReleaseImageANDROID( GFXSTREAM_TRACE_EVENT(GFXSTREAM_TRACE_DEFAULT_CATEGORY, "vkQSRI syncImageToColorBuffer()", GFXSTREAM_TRACE_FLOW(traceId)); - auto fb = FrameBuffer::getFB(); - fb->lock(); + emu->getGlobalState()->lockGlobalState(); // Implicitly synchronized *pNativeFenceFd = -1; @@ -849,7 +847,7 @@ VkResult AndroidNativeBufferInfo::on_vkQueueSignalReleaseImageANDROID( VK_ANB_DEBUG_OBJ(this, "wait callback: wait for fence %p...(done)", qsriFence); mQsriWaitFencePool->returnFence(qsriFence); }; - fb->unlock(); + emu->getGlobalState()->unlockGlobalState(); if (mUseVulkanNativeImage) { VK_ANB_DEBUG_OBJ(this, "using native image, so use sync thread to wait"); From 1c7c27ac964abd16604067a12582fcfc7059da90 Mon Sep 17 00:00:00 2001 From: Jason Macnak Date: Fri, 24 Jul 2026 11:06:59 -0700 Subject: [PATCH 15/33] Decouple PostWorker from FrameBuffer ... to allow for removing the circular dependencies between the main host server and the GL and VK backends. Bug: b/537737772 Test: bazel test //host/... Low-Coverage-Reason: REFACTOR_ONLY Change-Id: I1e83a716c8e854a2ce4458586c3b09c3232c0822 --- host/color_buffer.h | 6 +- .../gfxstream/host/color_buffer_interface.h | 8 +++ .../include/gfxstream/host/global_state.h | 15 ++++ host/frame_buffer.cpp | 68 ++++++++++--------- host/post_commands.h | 5 +- host/post_worker.cpp | 23 ++++--- host/post_worker.h | 16 ++--- host/post_worker_gl.cpp | 37 +++++----- host/post_worker_gl.h | 6 +- host/vulkan/post_worker_vk.cpp | 34 +++++----- host/vulkan/post_worker_vk.h | 3 +- 11 files changed, 127 insertions(+), 94 deletions(-) diff --git a/host/color_buffer.h b/host/color_buffer.h index 54f700fa7..dd31b4078 100644 --- a/host/color_buffer.h +++ b/host/color_buffer.h @@ -78,10 +78,10 @@ class ColorBuffer : public IColorBuffer, public LazySnapshotObj { GfxstreamFormat pixelsFormat, void* outPixels, const std::optional>& colorTransform) override; void readYuvToBytes(int x, int y, int width, int height, void* outPixels, - uint32_t outPixelsSize); + uint32_t outPixelsSize) override; bool updateFromBytes(int x, int y, int width, int height, GfxstreamFormat pixelsFormat, - const void* pixels, void* metadata = nullptr); + const void* pixels, void* metadata = nullptr) override; bool updateGlFromBytes(const void* bytes, std::size_t bytesSize); bool invalidateForBackend(Backend backend) override; @@ -91,7 +91,7 @@ class ColorBuffer : public IColorBuffer, public LazySnapshotObj { bool flushFromVk(); bool flushFromVkBytes(const void* bytes, size_t bytesSize); - std::optional exportBlob(); + std::optional exportBlob() override; #if GFXSTREAM_ENABLE_HOST_GLES bool canUseGlOps(); diff --git a/host/common/include/gfxstream/host/color_buffer_interface.h b/host/common/include/gfxstream/host/color_buffer_interface.h index a2361d0ea..5f7da5e77 100644 --- a/host/common/include/gfxstream/host/color_buffer_interface.h +++ b/host/common/include/gfxstream/host/color_buffer_interface.h @@ -19,6 +19,7 @@ #include #include +#include "gfxstream/host/external_object_manager.h" #include "gfxstream/host/gfxstream_format.h" #include "render-utils/Renderer.h" @@ -59,6 +60,13 @@ class IColorBuffer { virtual void readToBytesScaled(int pixelsWidth, int pixelsHeight, int pixelsRotation, const Rect& rect, GfxstreamFormat pixelsFormat, void* outPixels, const std::optional>& colorTransform) = 0; + virtual void readYuvToBytes(int x, int y, int width, int height, void* outPixels, + uint32_t outPixelsSize) = 0; + + virtual bool updateFromBytes(int x, int y, int width, int height, GfxstreamFormat pixelsFormat, + const void* pixels, void* metadata = nullptr) = 0; + + virtual std::optional exportBlob() = 0; }; // A (mostly) generic shared owning reference to a `ColorBuffer` so that the diff --git a/host/common/include/gfxstream/host/global_state.h b/host/common/include/gfxstream/host/global_state.h index 1e317eab4..091ae1024 100644 --- a/host/common/include/gfxstream/host/global_state.h +++ b/host/common/include/gfxstream/host/global_state.h @@ -18,6 +18,7 @@ #include #include "gfxstream/CancelableFuture.h" +#include "gfxstream/host/color_buffer_interface.h" namespace gfxstream { namespace host { @@ -26,6 +27,8 @@ class GlobalState { public: virtual ~GlobalState() = default; + virtual IColorBufferRef findColorBuffer(uint32_t colorBufferHandle) = 0; + virtual void registerProcessCleanupCallback(void* key, uint64_t contextId, std::function callback) = 0; virtual void unregisterProcessCleanupCallback(void* key) = 0; @@ -33,6 +36,18 @@ class GlobalState { virtual void lockGlobalState() = 0; virtual void unlockGlobalState() = 0; + virtual int getColorBufferScreenshot( + IColorBuffer* cb, int targetWidth, int targetHeight, int skinRotation, + GfxstreamFormat pixelsFormat, void* outPixels, const Rect& rect, + const std::optional>& colorTransform) = 0; + + virtual float getDpr() const = 0; + virtual int windowWidth() const = 0; + virtual int windowHeight() const = 0; + virtual float getPx() const = 0; + virtual float getPy() const = 0; + virtual int getZrot() const = 0; + virtual void invalidateColorBuffer(uint32_t colorBufferHandle) = 0; virtual void flushColorBuffer(uint32_t colorBufferHandle) = 0; virtual void flushColorBufferFromBytes(uint32_t colorBufferHandle, const void* bytes, diff --git a/host/frame_buffer.cpp b/host/frame_buffer.cpp index fe8e1e959..0c92cebfb 100644 --- a/host/frame_buffer.cpp +++ b/host/frame_buffer.cpp @@ -509,12 +509,12 @@ class FrameBuffer::Impl : public gfxstream::base::EventNotificationSupport>& colorTransform); + int getColorBufferScreenshot( + IColorBuffer* cb, int targetWidth, int targetHeight, int skinRotation, + GfxstreamFormat pixelsFormat, void* outPixels, const Rect& rect, + const std::optional>& colorTransform) override; void onLastColorBufferRef(uint32_t handle); - ColorBufferPtr findColorBuffer(HandleType p_colorbuffer); + IColorBufferRef findColorBuffer(HandleType p_colorbuffer) override; BufferPtr findBuffer(HandleType p_buffer); void registerProcessCleanupCallback(void* key, uint64_t contextId, @@ -1486,13 +1486,13 @@ std::unique_ptr FrameBuffer::Impl::Create(FrameBuffer* frameb if (impl->m_useVulkanComposition) { impl->m_postWorker.reset( - new PostWorkerVk(framebuffer, impl->m_compositor, impl->m_displayVk)); + new PostWorkerVk(impl.get(), impl->m_compositor, impl->m_displayVk)); } else { const bool shouldPostOnlyOnMainThread = postOnlyOnMainThread(); #if GFXSTREAM_ENABLE_HOST_GLES PostWorkerGl* postWorkerGl = - new PostWorkerGl(shouldPostOnlyOnMainThread, framebuffer, impl->m_compositor, + new PostWorkerGl(shouldPostOnlyOnMainThread, impl.get(), impl->m_compositor, impl->m_displayGl, impl->m_emulationGl.get()); impl->m_postWorker.reset(postWorkerGl); impl->m_displaySurfaceUsers.push_back(postWorkerGl); @@ -2549,7 +2549,7 @@ void FrameBuffer::Impl::readColorBuffer(HandleType p_colorbuffer, int x, int y, AutoLock mutex(m_lock); - ColorBufferPtr colorBuffer = findColorBuffer(p_colorbuffer); + IColorBufferRef colorBuffer = findColorBuffer(p_colorbuffer); if (!colorBuffer) { // bad colorbuffer handle return; @@ -2577,7 +2577,7 @@ void FrameBuffer::Impl::readColorBufferYUV(HandleType p_colorbuffer, int x, int int height, void* outPixels, uint32_t outPixelsSize) { AutoLock mutex(m_lock); - ColorBufferPtr colorBuffer = findColorBuffer(p_colorbuffer); + auto colorBuffer = findColorBuffer(p_colorbuffer); if (!colorBuffer) { // bad colorbuffer handle return; @@ -2610,15 +2610,13 @@ bool FrameBuffer::Impl::updateColorBuffer(HandleType p_colorbuffer, int x, int y AutoLock mutex(m_lock); - ColorBufferPtr colorBuffer = findColorBuffer(p_colorbuffer); + auto colorBuffer = findColorBuffer(p_colorbuffer); if (!colorBuffer) { // bad colorbuffer handle return false; } - colorBuffer->updateFromBytes(x, y, width, height, pixelsFormat, pixels); - - return true; + return colorBuffer->updateFromBytes(x, y, width, height, pixelsFormat, pixels); } bool FrameBuffer::Impl::updateColorBufferDeprecated(HandleType colorbuffer, int x, int y, int width, @@ -2766,7 +2764,8 @@ AsyncResult FrameBuffer::Impl::postImpl(HandleType p_colorbuffer, Post::Completi continue; } - cb = findColorBuffer(displayColorBufferHandle); + cb = std::static_pointer_cast( + findColorBuffer(displayColorBufferHandle)); if (!cb) { GFXSTREAM_ERROR("Failed to find ColorBuffer %d, skip onPost", displayColorBufferHandle); @@ -2950,7 +2949,7 @@ int FrameBuffer::Impl::getScreenshot(unsigned int nChannels, unsigned int* width if (displayId == 0) { cb = m_lastPostedColorBuffer; } - ColorBufferPtr colorBuffer = findColorBuffer(cb); + IColorBufferRef colorBuffer = findColorBuffer(cb); if (!colorBuffer) { *width = 0; *height = 0; @@ -3063,7 +3062,7 @@ int FrameBuffer::Impl::getScreenshot(unsigned int nChannels, unsigned int* width } int FrameBuffer::Impl::getColorBufferScreenshot( - ColorBuffer* cb, int targetWidth, int targetHeight, int skinRotation, + IColorBuffer* cb, int targetWidth, int targetHeight, int skinRotation, GfxstreamFormat pixelsFormat, void* outPixels, const Rect& rect, const std::optional>& colorTransform) { uint8_t* outPixelsRGBA = reinterpret_cast(outPixels); @@ -3665,7 +3664,7 @@ void FrameBuffer::Impl::lockGlobalState() NO_THREAD_SAFETY_ANALYSIS { lock(); } void FrameBuffer::Impl::unlockGlobalState() NO_THREAD_SAFETY_ANALYSIS { unlock(); } -ColorBufferPtr FrameBuffer::Impl::findColorBuffer(HandleType p_colorbuffer) { +IColorBufferRef FrameBuffer::Impl::findColorBuffer(HandleType p_colorbuffer) { AutoLock colorBufferMapLock(m_colorBufferMapLock); auto it = m_colorbuffers.find(p_colorbuffer); if (it == m_colorbuffers.end()) { @@ -3914,7 +3913,8 @@ int FrameBuffer::Impl::getDisplayActiveConfig() { bool FrameBuffer::Impl::flushColorBufferFromVk(HandleType colorBufferHandle) { AutoLock mutex(m_lock); - auto colorBuffer = findColorBuffer(colorBufferHandle); + ColorBufferPtr colorBuffer = + std::static_pointer_cast(findColorBuffer(colorBufferHandle)); if (!colorBuffer) { GFXSTREAM_ERROR("%s: Failed to find ColorBuffer:%d", __func__, colorBufferHandle); return false; @@ -3926,7 +3926,8 @@ bool FrameBuffer::Impl::flushColorBufferFromVkBytes(HandleType colorBufferHandle size_t bytesSize) { AutoLock mutex(m_lock); - auto colorBuffer = findColorBuffer(colorBufferHandle); + ColorBufferPtr colorBuffer = + std::static_pointer_cast(findColorBuffer(colorBufferHandle)); if (!colorBuffer) { GFXSTREAM_ERROR("%s: Failed to find ColorBuffer:%d", __func__, colorBufferHandle); return false; @@ -3953,7 +3954,7 @@ std::optional FrameBuffer::Impl::exportColorBuffer( HandleType colorBufferHandle) { AutoLock mutex(m_lock); - ColorBufferPtr colorBuffer = findColorBuffer(colorBufferHandle); + auto colorBuffer = findColorBuffer(colorBufferHandle); if (!colorBuffer) { return std::nullopt; } @@ -4695,7 +4696,8 @@ bool FrameBuffer::Impl::platformDestroySharedEglContext(void* underlyingContext) } bool FrameBuffer::Impl::flushColorBufferFromGl(HandleType colorBufferHandle) { - auto colorBuffer = findColorBuffer(colorBufferHandle); + ColorBufferPtr colorBuffer = + std::static_pointer_cast(findColorBuffer(colorBufferHandle)); if (!colorBuffer) { GFXSTREAM_ERROR("%s: Failed to find ColorBuffer:%d", __func__, colorBufferHandle); return false; @@ -4726,7 +4728,8 @@ ContextHelper* FrameBuffer::Impl::getPbufferSurfaceContextHelper() const { bool FrameBuffer::Impl::bindColorBufferToTexture(HandleType p_colorbuffer) { AutoLock mutex(m_lock); - ColorBufferPtr colorBuffer = findColorBuffer(p_colorbuffer); + ColorBufferPtr colorBuffer = + std::static_pointer_cast(findColorBuffer(p_colorbuffer)); if (!colorBuffer) { // bad colorbuffer handle return false; @@ -4743,7 +4746,8 @@ bool FrameBuffer::Impl::bindColorBufferToTexture2(HandleType p_colorbuffer) { mutex = std::make_unique(m_lock); } - ColorBufferPtr colorBuffer = findColorBuffer(p_colorbuffer); + ColorBufferPtr colorBuffer = + std::static_pointer_cast(findColorBuffer(p_colorbuffer)); if (!colorBuffer) { // bad colorbuffer handle return false; @@ -4765,7 +4769,8 @@ bool FrameBuffer::Impl::bindColorBufferToTexture2(HandleType p_colorbuffer) { bool FrameBuffer::Impl::bindColorBufferToRenderbuffer(HandleType p_colorbuffer) { AutoLock mutex(m_lock); - ColorBufferPtr colorBuffer = findColorBuffer(p_colorbuffer); + ColorBufferPtr colorBuffer = + std::static_pointer_cast(findColorBuffer(p_colorbuffer)); if (!colorBuffer) { // bad colorbuffer handle return false; @@ -4966,7 +4971,8 @@ void FrameBuffer::Impl::swapTexturesAndUpdateColorBuffer(uint32_t p_colorbuffer, { AutoLock mutex(m_lock); - ColorBufferPtr colorBuffer = findColorBuffer(p_colorbuffer); + ColorBufferPtr colorBuffer = + std::static_pointer_cast(findColorBuffer(p_colorbuffer)); if (!colorBuffer) { // bad colorbuffer handle return; diff --git a/host/post_commands.h b/host/post_commands.h index 206880b89..505cbea72 100644 --- a/host/post_commands.h +++ b/host/post_commands.h @@ -30,7 +30,6 @@ namespace gfxstream { namespace host { class IColorBuffer; -class ColorBuffer; // Posting enum class PostCmd { @@ -62,13 +61,13 @@ struct Post { //TODO: remove union here and separate into message structures union { - ColorBuffer* cb; + IColorBuffer* cb; struct { int width; int height; } viewport; struct { - ColorBuffer* cb; + IColorBuffer* cb; int screenwidth; int screenheight; int rotation; diff --git a/host/post_worker.cpp b/host/post_worker.cpp index d5da84ef0..dce82e934 100644 --- a/host/post_worker.cpp +++ b/host/post_worker.cpp @@ -19,10 +19,10 @@ #include -#include "color_buffer.h" -#include "frame_buffer.h" #include "gfxstream/Tracing.h" #include "gfxstream/common/logging.h" +#include "gfxstream/host/color_buffer_interface.h" +#include "gfxstream/host/global_state.h" #include "gfxstream/host/window_operations.h" #include "render_thread_info.h" #include "vulkan/vk_common_operations.h" @@ -30,8 +30,9 @@ namespace gfxstream { namespace host { -PostWorker::PostWorker(bool mainThreadPostingOnly, FrameBuffer* fb, Compositor* compositor) - : mFb(fb), +PostWorker::PostWorker(bool mainThreadPostingOnly, gfxstream::host::GlobalState* globalState, + Compositor* compositor) + : m_globalState(globalState), m_compositor(compositor), m_mainThreadPostingOnly(mainThreadPostingOnly) {} @@ -45,7 +46,7 @@ std::shared_future PostWorker::composeImpl(const FlatComposeRequest& compo } Compositor::CompositionRequest compositorRequest = {}; - compositorRequest.target = mFb->findColorBuffer(composeRequest.targetHandle); + compositorRequest.target = m_globalState->findColorBuffer(composeRequest.targetHandle); if (!compositorRequest.target) { GFXSTREAM_ERROR("Compose target is null (cb=0x%x).", composeRequest.targetHandle); return completedFuture; @@ -57,7 +58,7 @@ std::shared_future PostWorker::composeImpl(const FlatComposeRequest& compo auto& compositorLayer = compositorRequest.layers.emplace_back(); compositorLayer.props = guestLayer; } else { - auto source = mFb->findColorBuffer(guestLayer.cbHandle); + auto source = m_globalState->findColorBuffer(guestLayer.cbHandle); if (!source) { continue; } @@ -129,16 +130,16 @@ void PostWorker::clear() { runTask(std::packaged_task([this] { clearImpl(); })); } -void PostWorker::screenshot(ColorBuffer* cb, int screenwidth, int screenheight, int skinRotation, +void PostWorker::screenshot(IColorBuffer* cb, int screenwidth, int screenheight, int skinRotation, GfxstreamFormat pixelsFormat, void* outPixels, const Rect& rect, const std::optional>& colorTransform) { // See b/292237104. - mFb->lock(); + m_globalState->lockGlobalState(); - mFb->getColorBufferScreenshot(cb, screenwidth, screenheight, skinRotation, pixelsFormat, - outPixels, rect, colorTransform); + m_globalState->getColorBufferScreenshot(cb, screenwidth, screenheight, skinRotation, + pixelsFormat, outPixels, rect, colorTransform); - mFb->unlock(); + m_globalState->unlockGlobalState(); } namespace { diff --git a/host/post_worker.h b/host/post_worker.h index 0f4c53fb7..1a343b0ec 100644 --- a/host/post_worker.h +++ b/host/post_worker.h @@ -22,22 +22,20 @@ #include #include "compositor.h" -#include "hwc2.h" -#include "post_commands.h" #include "gfxstream/Compiler.h" +#include "gfxstream/host/color_buffer_interface.h" #include "gfxstream/host/gfxstream_format.h" - +#include "gfxstream/host/global_state.h" +#include "hwc2.h" +#include "post_commands.h" namespace gfxstream { namespace host { -class IColorBuffer; -class ColorBuffer; -class FrameBuffer; struct RenderThreadInfo; class PostWorker { public: - PostWorker(bool mainThreadPostingOnly, FrameBuffer* fb, Compositor* compositor); + PostWorker(bool mainThreadPostingOnly, GlobalState* globalState, Compositor* compositor); virtual ~PostWorker(); // post: posts the next color buffer. @@ -62,7 +60,7 @@ class PostWorker { void clear(); // screenshot: readbacks emulator display image to a buffer - void screenshot(ColorBuffer* cb, int screenwidth, int screenheight, int skinRotation, + void screenshot(IColorBuffer* cb, int screenwidth, int screenheight, int skinRotation, GfxstreamFormat pixelsFormat, void* outPixels, const Rect& rect, const std::optional>& colorTransform); @@ -84,7 +82,7 @@ class PostWorker { virtual std::shared_future composeImpl(const FlatComposeRequest& composeRequest); protected: - FrameBuffer* mFb; + GlobalState* m_globalState; Compositor* m_compositor = nullptr; protected: diff --git a/host/post_worker_gl.cpp b/host/post_worker_gl.cpp index 9e29582da..f3c1e415e 100644 --- a/host/post_worker_gl.cpp +++ b/host/post_worker_gl.cpp @@ -15,9 +15,9 @@ */ #include "post_worker_gl.h" -#include "frame_buffer.h" -#include "gfxstream/host/display_operations.h" #include "gfxstream/common/logging.h" +#include "gfxstream/host/display_operations.h" +#include "gfxstream/host/global_state.h" #include "gfxstream/host/renderer_operations.h" #include "gfxstream/host/window_operations.h" #include "host/gl/display_gl.h" @@ -43,9 +43,10 @@ hwc_transform_t getTransformFromRotation(int rotation) { } // namespace -PostWorkerGl::PostWorkerGl(bool mainThreadPostingOnly, FrameBuffer* fb, Compositor* compositor, - DisplayGl* displayGl, gl::EmulationGl* emulationGl) - : PostWorker(mainThreadPostingOnly, fb, compositor), +PostWorkerGl::PostWorkerGl(bool mainThreadPostingOnly, gfxstream::host::GlobalState* globalState, + Compositor* compositor, DisplayGl* displayGl, + gl::EmulationGl* emulationGl) + : PostWorker(mainThreadPostingOnly, globalState, compositor), m_displayGl(displayGl), mEmulationGl(emulationGl) { if (!m_displayGl) { @@ -133,12 +134,12 @@ std::shared_future PostWorkerGl::postImpl( IColorBuffer* currentCb = currentDisplayId == 0 ? cb - : mFb->findColorBuffer(currentDisplayColorBufferHandle).get(); + : m_globalState->findColorBuffer(currentDisplayColorBufferHandle).get(); if (!currentCb) { continue; } - const auto transform = getTransformFromRotation(mFb->getZrot()); + const auto transform = getTransformFromRotation(m_globalState->getZrot()); postLayerOptions.transform = transform; if ( transform == HWC_TRANSFORM_ROT_90 || transform == HWC_TRANSFORM_ROT_270) { std::swap(currentDisplayW, currentDisplayH); @@ -163,7 +164,7 @@ std::shared_future PostWorkerGl::postImpl( } } } else if (get_gfxstream_window_operations().is_folded()) { - const float dpr = mFb->getDpr(); + const float dpr = m_globalState->getDpr(); post.frameWidth = m_viewportWidth / dpr; post.frameHeight = m_viewportHeight / dpr; @@ -179,8 +180,8 @@ std::shared_future PostWorkerGl::postImpl( postLayerOptions.displayFrame = { .left = 0, .top = 0, - .right = mFb->windowWidth(), - .bottom = mFb->windowHeight(), + .right = m_globalState->windowWidth(), + .bottom = m_globalState->windowHeight(), }; postLayerOptions.crop = { .left = static_cast(displayOffsetX), @@ -188,7 +189,7 @@ std::shared_future PostWorkerGl::postImpl( .right = static_cast(displayOffsetX + displayW), .bottom = static_cast(displayOffsetY), }; - postLayerOptions.transform = getTransformFromRotation(mFb->getZrot()); + postLayerOptions.transform = getTransformFromRotation(m_globalState->getZrot()); post.layers.push_back(DisplayGl::PostLayer{ .colorBuffer = cb, @@ -205,12 +206,12 @@ std::shared_future PostWorkerGl::postImpl( DisplayGl::PostLayer PostWorkerGl::postWithOverlay( IColorBuffer* cb, const std::optional>& colorTransform) { - float dpr = mFb->getDpr(); - int windowWidth = mFb->windowWidth(); - int windowHeight = mFb->windowHeight(); - float px = mFb->getPx(); - float py = mFb->getPy(); - int zRot = mFb->getZrot(); + float dpr = m_globalState->getDpr(); + int windowWidth = m_globalState->windowWidth(); + int windowHeight = m_globalState->windowHeight(); + float px = m_globalState->getPx(); + float py = m_globalState->getPy(); + int zRot = m_globalState->getZrot(); // Find the x and y values at the origin when "fully scrolled." // Multiply by 2 because the texture goes from -1 to 1, not 0 to 1. @@ -256,7 +257,7 @@ DisplayGl::PostLayer PostWorkerGl::postWithOverlay( // and resets the posting viewport. void PostWorkerGl::viewportImpl(int width, int height) { setupContext(); - const float dpr = mFb->getDpr(); + const float dpr = m_globalState->getDpr(); m_viewportWidth = width * dpr; m_viewportHeight = height * dpr; diff --git a/host/post_worker_gl.h b/host/post_worker_gl.h index 39d2d8f01..86a778c2f 100644 --- a/host/post_worker_gl.h +++ b/host/post_worker_gl.h @@ -18,7 +18,9 @@ #include #include +#include "gfxstream/host/color_buffer_interface.h" #include "gfxstream/host/display_surface_user.h" +#include "gfxstream/host/global_state.h" #include "post_worker.h" #include "host/gl/display_gl.h" #include "host/gl/emulation_gl.h" @@ -33,8 +35,8 @@ class RecursiveScopedContextBind; class PostWorkerGl : public PostWorker, public DisplaySurfaceUser { public: - PostWorkerGl(bool mainThreadPostingOnly, FrameBuffer* fb, Compositor* compositor, - gl::DisplayGl* displayGl, gl::EmulationGl* emulationGl); + PostWorkerGl(bool mainThreadPostingOnly, GlobalState* globalState, + Compositor* compositor, gl::DisplayGl* displayGl, gl::EmulationGl* emulationGl); protected: std::shared_future postImpl( diff --git a/host/vulkan/post_worker_vk.cpp b/host/vulkan/post_worker_vk.cpp index 1966dcb5b..50b37e6ba 100644 --- a/host/vulkan/post_worker_vk.cpp +++ b/host/vulkan/post_worker_vk.cpp @@ -17,9 +17,9 @@ #include "gfxstream/common/logging.h" #include "gfxstream/host/display_operations.h" +#include "gfxstream/host/global_state.h" #include "gfxstream/host/renderer_operations.h" #include "gfxstream/host/window_operations.h" -#include "host/frame_buffer.h" #include "vulkan/color_buffer_vk.h" #include "vulkan/display_vk.h" @@ -43,8 +43,9 @@ hwc_transform_t getTransformFromRotation(int rotation) { } // namespace -PostWorkerVk::PostWorkerVk(FrameBuffer* fb, Compositor* compositor, vk::DisplayVk* displayVk) - : PostWorker(false, fb, compositor), m_displayVk(displayVk) {} +PostWorkerVk::PostWorkerVk(gfxstream::host::GlobalState* globalState, Compositor* compositor, + vk::DisplayVk* displayVk) + : PostWorker(false, globalState, compositor), m_displayVk(displayVk) {} std::shared_future PostWorkerVk::postImpl( IColorBuffer* cb, const std::optional>& colorTransform) { @@ -86,12 +87,12 @@ std::shared_future PostWorkerVk::postImpl( if (pixel_fold) { #ifdef CONFIG_AEMU if (!get_gfxstream_should_skip_draw()) { - const float dpr = mFb->getDpr(); - const float px = mFb->getPx(); - const float py = mFb->getPy(); - const int windowWidth = mFb->windowWidth(); - const int windowHeight = mFb->windowHeight(); - const float zRot = static_cast(mFb->getZrot()); + const float dpr = m_globalState->getDpr(); + const float px = m_globalState->getPx(); + const float py = m_globalState->getPy(); + const int windowWidth = m_globalState->windowWidth(); + const int windowHeight = m_globalState->windowHeight(); + const float zRot = static_cast(m_globalState->getZrot()); // Calculate "excess" space (difference between viewport and content size) // m_viewportWidth/Height are updated in viewportImpl @@ -130,7 +131,8 @@ std::shared_future PostWorkerVk::postImpl( currentDisplayId, currentDisplayColorBufferHandle); } // Main window post - addPostImage(cb, 0, 0, 0, 0, static_cast(mFb->getZrot()), colorTransform); + addPostImage(cb, 0, 0, 0, 0, static_cast(m_globalState->getZrot()), + colorTransform); } else { uint32_t combinedDisplayW = 0; uint32_t combinedDisplayH = 0; @@ -160,13 +162,13 @@ std::shared_future PostWorkerVk::postImpl( IColorBuffer* currentCb = currentDisplayId == 0 ? cb - : mFb->findColorBuffer(currentDisplayColorBufferHandle).get(); + : m_globalState->findColorBuffer(currentDisplayColorBufferHandle).get(); if (!currentCb) { continue; } - float rotation = static_cast(mFb->getZrot()); - const auto transform = getTransformFromRotation(mFb->getZrot()); + float rotation = static_cast(m_globalState->getZrot()); + const auto transform = getTransformFromRotation(m_globalState->getZrot()); if (transform == HWC_TRANSFORM_ROT_90 || transform == HWC_TRANSFORM_ROT_270) { std::swap(currentDisplayW, currentDisplayH); } @@ -177,10 +179,10 @@ std::shared_future PostWorkerVk::postImpl( } else if (get_gfxstream_window_operations().is_folded()) { // TODO: Implement fold logic if needed (similar to GL) // For now simple post - addPostImage(cb, 0, 0, 0, 0, static_cast(mFb->getZrot()), colorTransform); + addPostImage(cb, 0, 0, 0, 0, static_cast(m_globalState->getZrot()), colorTransform); } else { // Simple case: single display, no special mode - addPostImage(cb, 0, 0, 0, 0, static_cast(mFb->getZrot()), colorTransform); + addPostImage(cb, 0, 0, 0, 0, static_cast(m_globalState->getZrot()), colorTransform); } constexpr const int kMaxPostRetries = 2; @@ -196,7 +198,7 @@ std::shared_future PostWorkerVk::postImpl( } void PostWorkerVk::viewportImpl(int width, int height) { - const float dpr = mFb->getDpr(); + const float dpr = m_globalState->getDpr(); m_viewportWidth = width * dpr; m_viewportHeight = height * dpr; } diff --git a/host/vulkan/post_worker_vk.h b/host/vulkan/post_worker_vk.h index 4dafa714e..e9ca11457 100644 --- a/host/vulkan/post_worker_vk.h +++ b/host/vulkan/post_worker_vk.h @@ -30,7 +30,8 @@ class DisplayVk; class PostWorkerVk : public PostWorker { public: - PostWorkerVk(FrameBuffer* fb, Compositor* compositor, vk::DisplayVk* displayGl); + PostWorkerVk(gfxstream::host::GlobalState* globalState, Compositor* compositor, + vk::DisplayVk* displayGl); protected: std::shared_future postImpl( From a6e1fec16b76b298ed882dc9e79bf768476e7590 Mon Sep 17 00:00:00 2001 From: Jason Macnak Date: Fri, 24 Jul 2026 12:12:07 -0700 Subject: [PATCH 16/33] Decouple RenderThreadInfoGl from FrameBuffer ... to allow for removing the circular dependencies between the main host server and the GL and VK backends. Bug: b/537737772 Test: bazel test //host/... Low-Coverage-Reason: REFACTOR_ONLY Change-Id: Ie731e9b17b0017598a005d0020ea43f7da3f165d --- .../include/gfxstream/host/global_state.h | 4 ++++ host/frame_buffer.cpp | 7 +++++-- host/frame_buffer.h | 4 ++++ host/frame_buffer_unittest.cpp | 2 +- host/gl/render_thread_info_gl.cpp | 19 +++++++++---------- host/gl/render_thread_info_gl.h | 5 ++++- host/render_thread.cpp | 2 +- host/render_thread_info.cpp | 6 +++--- host/render_thread_info.h | 3 ++- host/testlibs/support/SampleApplication.cpp | 2 +- 10 files changed, 34 insertions(+), 20 deletions(-) diff --git a/host/common/include/gfxstream/host/global_state.h b/host/common/include/gfxstream/host/global_state.h index 091ae1024..279566d76 100644 --- a/host/common/include/gfxstream/host/global_state.h +++ b/host/common/include/gfxstream/host/global_state.h @@ -48,6 +48,10 @@ class GlobalState { virtual float getPy() const = 0; virtual int getZrot() const = 0; + virtual void postLoadRenderThreadContextSurfacePtrs() = 0; + virtual bool bindContext(uint32_t p_context, uint32_t p_drawSurface, + uint32_t p_readSurface) = 0; + virtual void invalidateColorBuffer(uint32_t colorBufferHandle) = 0; virtual void flushColorBuffer(uint32_t colorBufferHandle) = 0; virtual void flushColorBufferFromBytes(uint32_t colorBufferHandle, const void* bytes, diff --git a/host/frame_buffer.cpp b/host/frame_buffer.cpp index 0c92cebfb..c06e31f65 100644 --- a/host/frame_buffer.cpp +++ b/host/frame_buffer.cpp @@ -684,7 +684,7 @@ class FrameBuffer::Impl : public gfxstream::base::EventNotificationSupporteglGetError()); mRenderThreadInfo = new RenderThreadInfo(); - mRenderThreadInfo->initGl(); + mRenderThreadInfo->initGl(mFb->getGlobalState()); } virtual void TearDown() override { diff --git a/host/gl/render_thread_info_gl.cpp b/host/gl/render_thread_info_gl.cpp index 7a2878b21..41b25a5f6 100644 --- a/host/gl/render_thread_info_gl.cpp +++ b/host/gl/render_thread_info_gl.cpp @@ -16,13 +16,13 @@ #include -#include "frame_buffer.h" #include "OpenGLESDispatch/EGLDispatch.h" #include "OpenGLESDispatch/GLESv1Dispatch.h" #include "OpenGLESDispatch/GLESv2Dispatch.h" -#include "gfxstream/synchronization/Lock.h" #include "gfxstream/containers/Lookup.h" +#include "gfxstream/host/global_state.h" #include "gfxstream/host/stream_utils.h" +#include "gfxstream/synchronization/Lock.h" namespace gfxstream { namespace host { @@ -34,7 +34,8 @@ using gfxstream::Stream; static thread_local RenderThreadInfoGl* tlThreadInfo = nullptr; -RenderThreadInfoGl::RenderThreadInfoGl() { +RenderThreadInfoGl::RenderThreadInfoGl(gfxstream::host::GlobalState* globalState) + : m_globalState(globalState) { m_glDec.initGL(gles1_dispatch_get_proc_func, nullptr); m_gl2Dec.initGL(gles2_dispatch_get_proc_func, nullptr); @@ -84,8 +85,7 @@ void RenderThreadInfoGl::onSave(Stream* stream) { } bool RenderThreadInfoGl::onLoad(Stream* stream) { - FrameBuffer* fb = FrameBuffer::getFB(); - assert(fb); + assert(m_globalState); HandleType ctxHndl = stream->getBe32(); HandleType drawSurf = stream->getBe32(); @@ -95,7 +95,7 @@ bool RenderThreadInfoGl::onLoad(Stream* stream) { currDrawSurfHandleFromLoad = drawSurf; currReadSurfHandleFromLoad = readSurf; - fb->postLoadRenderThreadContextSurfacePtrs(); + m_globalState->postLoadRenderThreadContextSurfacePtrs(); loadCollection(stream, &m_contextSet, [](Stream* stream) { return stream->getBe32(); @@ -113,15 +113,14 @@ bool RenderThreadInfoGl::onLoad(Stream* stream) { } void RenderThreadInfoGl::postLoadRefreshCurrentContextSurfacePtrs() { - FrameBuffer* fb = FrameBuffer::getFB(); - assert(fb); + assert(m_globalState); - fb->postLoadRenderThreadContextSurfacePtrs(); + m_globalState->postLoadRenderThreadContextSurfacePtrs(); const HandleType ctx = currContext ? currContext->getHndl() : 0; const HandleType draw = currDrawSurf ? currDrawSurf->getHndl() : 0; const HandleType read = currReadSurf ? currReadSurf->getHndl() : 0; - fb->bindContext(ctx, draw, read); + m_globalState->bindContext(ctx, draw, read); } } // namespace gl diff --git a/host/gl/render_thread_info_gl.h b/host/gl/render_thread_info_gl.h index 7fa866f3e..c23dfc5e4 100644 --- a/host/gl/render_thread_info_gl.h +++ b/host/gl/render_thread_info_gl.h @@ -27,13 +27,14 @@ namespace gfxstream { namespace host { +class GlobalState; namespace gl { struct RenderThreadInfoGl { // Create new instance. Only call this once per thread. // Future calls to get() will return this instance until // it is destroyed. - RenderThreadInfoGl(); + RenderThreadInfoGl(gfxstream::host::GlobalState* globalState); // Destructor. ~RenderThreadInfoGl(); @@ -73,6 +74,8 @@ struct RenderThreadInfoGl { // Decoder states. GLESv1Decoder m_glDec; GLESv2Decoder m_gl2Dec; + + gfxstream::host::GlobalState* m_globalState = nullptr; }; } // namespace gl diff --git a/host/render_thread.cpp b/host/render_thread.cpp index ce31969bf..a255d1303 100644 --- a/host/render_thread.cpp +++ b/host/render_thread.cpp @@ -285,7 +285,7 @@ intptr_t RenderThread::main() { // initialize decoders #if GFXSTREAM_ENABLE_HOST_GLES if (FrameBuffer::getFB()->hasEmulationGl()) { - tInfo->initGl(); + tInfo->initGl(FrameBuffer::getFB()->getGlobalState()); } initRenderControlContext(&(tInfo->m_rcDec)); diff --git a/host/render_thread_info.cpp b/host/render_thread_info.cpp index dc600209e..001db5b3d 100644 --- a/host/render_thread_info.cpp +++ b/host/render_thread_info.cpp @@ -63,8 +63,8 @@ void RenderThreadInfo::forAllRenderThreadInfos(std::functiongetBe32() == 1; if (loadGlInfo) { if (!m_glInfo) { - m_glInfo.emplace(); + m_glInfo.emplace(FrameBuffer::getFB()->getGlobalState()); } if (!m_glInfo->onLoad(stream)) { return false; diff --git a/host/render_thread_info.h b/host/render_thread_info.h index 838996b2f..ef7afb6fe 100644 --- a/host/render_thread_info.h +++ b/host/render_thread_info.h @@ -31,6 +31,7 @@ namespace gfxstream { namespace host { +class GlobalState; // A class used to model the state of each RenderThread related struct RenderThreadInfo { @@ -49,7 +50,7 @@ struct RenderThreadInfo { static void forAllRenderThreadInfos(std::function); #if GFXSTREAM_ENABLE_HOST_GLES - void initGl(); + void initGl(gfxstream::host::GlobalState* globalState); #endif // The unique id of owner guest process of this render thread diff --git a/host/testlibs/support/SampleApplication.cpp b/host/testlibs/support/SampleApplication.cpp index e51276413..7d4f991fe 100644 --- a/host/testlibs/support/SampleApplication.cpp +++ b/host/testlibs/support/SampleApplication.cpp @@ -265,7 +265,7 @@ SampleApplication::SampleApplication(int windowWidth, int windowHeight, int refr } mRenderThreadInfo.reset(new RenderThreadInfo()); - mRenderThreadInfo->initGl(); + mRenderThreadInfo->initGl(mFb->getGlobalState()); mColorBuffer = mFb->createColorBuffer(mWidth, mHeight, GfxstreamFormat::R8G8B8A8_UNORM); mContext = mFb->createEmulatedEglContext(0, 0, glVersion); From 4df6a7f1c00dba66ade2c69f2ff1622fa48f6d37 Mon Sep 17 00:00:00 2001 From: Jason Macnak Date: Fri, 24 Jul 2026 13:20:13 -0700 Subject: [PATCH 17/33] Separate native_sub_window* into new library ... in order to decouple and remove the circular dependency between the vk server and the main host server. Bug: b/537737772 Test: bazel test //host/... Low-Coverage-Reason: REFACTOR_ONLY Change-Id: I5b900511a0f33bb85c87ea0628abdd5ec4794609 --- host/Android.bp | 10 +- host/BUILD.bazel | 54 +------ host/CMakeLists.txt | 13 +- host/decoder_common/Android.bp | 3 + host/frame_buffer.cpp | 3 +- host/gles_compat.h | 40 ----- host/meson.build | 26 +--- host/native_sub_window_android.cpp | 54 ------- host/native_sub_window_win32.cpp | 105 ------------- host/native_sub_window_x11.cpp | 141 ------------------ host/native_window/Android.bp | 36 +++++ host/native_window/BUILD.bazel | 73 +++++++++ host/native_window/CMakeLists.txt | 36 +++++ .../gfxstream/host}/native_sub_window.h | 57 ++++--- host/native_window/meson.build | 30 ++++ .../native_sub_window_android.cpp | 42 ++++++ .../native_sub_window_cocoa.mm | 95 ++++++------ .../native_sub_window_qnx.cpp | 2 +- .../native_sub_window_stub.cpp | 5 +- .../native_window/native_sub_window_win32.cpp | 83 +++++++++++ host/native_window/native_sub_window_x11.cpp | 112 ++++++++++++++ host/vulkan/Android.bp | 1 + host/vulkan/BUILD.bazel | 1 + host/vulkan/CMakeLists.txt | 1 + host/vulkan/display_surface_vk.cpp | 2 +- host/vulkan/meson.build | 4 +- 26 files changed, 516 insertions(+), 513 deletions(-) delete mode 100644 host/gles_compat.h delete mode 100644 host/native_sub_window_android.cpp delete mode 100644 host/native_sub_window_win32.cpp delete mode 100644 host/native_sub_window_x11.cpp create mode 100644 host/native_window/Android.bp create mode 100644 host/native_window/BUILD.bazel create mode 100644 host/native_window/CMakeLists.txt rename host/{ => native_window/include/gfxstream/host}/native_sub_window.h (62%) create mode 100644 host/native_window/meson.build create mode 100644 host/native_window/native_sub_window_android.cpp rename host/{ => native_window}/native_sub_window_cocoa.mm (66%) rename host/{ => native_window}/native_sub_window_qnx.cpp (98%) rename host/{ => native_window}/native_sub_window_stub.cpp (95%) create mode 100644 host/native_window/native_sub_window_win32.cpp create mode 100644 host/native_window/native_sub_window_x11.cpp diff --git a/host/Android.bp b/host/Android.bp index a8a569587..c76e169bd 100644 --- a/host/Android.bp +++ b/host/Android.bp @@ -45,16 +45,17 @@ cc_library_host_static { gfxstream_backend_static_deps = [ "libgfxstream_common_base", + "libgfxstream_common_logging", "libgfxstream_common_utils", "libgfxstream_etc", "libgfxstream_glestranslator_egl", "libgfxstream_glestranslator_glescm", "libgfxstream_glestranslator_glesv2", "libgfxstream_host_address_space", - "libgfxstream_host_compressedtextures", - "libgfxstream_host_decoder_common", "libgfxstream_host_common", "libgfxstream_host_compressedtextures", + "libgfxstream_host_compressedtextures", + "libgfxstream_host_decoder_common", "libgfxstream_host_features", "libgfxstream_host_gl_server", "libgfxstream_host_gles1_dec", @@ -63,7 +64,7 @@ gfxstream_backend_static_deps = [ "libgfxstream_host_glsnapshot", "libgfxstream_host_iostream", "libgfxstream_host_library", - "libgfxstream_common_logging", + "libgfxstream_host_native_window", "libgfxstream_host_openglesdispatch", "libgfxstream_host_rendercontrol_dec", "libgfxstream_host_renderdoc", @@ -121,6 +122,7 @@ cc_defaults { "libgfxstream_host_glsnapshot", "libgfxstream_host_address_space", "libgfxstream_host_vulkan_cereal", + "libgfxstream_host_native_window", ], shared_libs: [ "liblog", // gfxstream_base uses this via perfetto-libperfettobase @@ -161,12 +163,10 @@ cc_defaults { ], target: { host: { - srcs: ["native_sub_window_x11.cpp"], static_libs: gfxstream_backend_snapshot_static_deps, whole_static_libs: gfxstream_backend_snapshot_static_deps, }, android: { - srcs: ["native_sub_window_android.cpp"], shared_libs: [ "libnativewindow", ], diff --git a/host/BUILD.bazel b/host/BUILD.bazel index 8ce64ed75..5ab37ba5a 100644 --- a/host/BUILD.bazel +++ b/host/BUILD.bazel @@ -1,6 +1,6 @@ load("@protobuf//bazel:cc_proto_library.bzl", "cc_proto_library") load("@protobuf//bazel:proto_library.bzl", "proto_library") -load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test", "objc_library") +load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test") load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") package( @@ -70,10 +70,8 @@ cc_library( "compositor.h", "frame_buffer.h", "framework_formats.h", - "gles_compat.h", "handle.h", "hwc2.h", - "native_sub_window.h", "post_commands.h", "post_worker.h", "readback_worker.h", @@ -98,34 +96,6 @@ cc_library( ], ) -objc_library( - name = "gfxstream_backend_static-darwin", - srcs = [ - "gles_compat.h", - "native_sub_window.h", - "native_sub_window_cocoa.mm", - ], - copts = GFXSTREAM_HOST_COPTS + [ - "-Wno-deprecated-declarations", - # These sources use manual reference counting, so disable ARC which - # objc_library enables by default. - "-fno-objc-arc", - ], - defines = GFXSTREAM_HOST_DEFINES, - sdk_frameworks = [ - "AppKit", - "QuartzCore", - "IOSurface", - ], - target_compatible_with = [ - "@platforms//os:macos", - ], - deps = [ - ":gfxstream_backend_headers", - "//third_party/opengl:gfxstream_egl_headers", - ], -) - cc_library( name = "gfxstream_backend_static", srcs = [ @@ -153,16 +123,7 @@ cc_library( "virtio_gpu_ring_blob.cpp", "virtio_gpu_timelines.cpp", "vsync_thread.cpp", - ] + select({ - "@platforms//os:macos": [], - "@platforms//os:windows": [ - "native_sub_window_win32.cpp", - ], - "@platforms//os:linux": [ - "native_sub_window_x11.cpp", - ], - "//conditions:default": [], - }), + ], hdrs = [ "buffer.h", "channel_stream.h", @@ -170,10 +131,8 @@ cc_library( "compositor.h", "frame_buffer.h", "framework_formats.h", - "gles_compat.h", "handle.h", "hwc2.h", - "native_sub_window.h", "post_commands.h", "post_worker.h", "post_worker_gl.h", @@ -233,6 +192,7 @@ cc_library( "//host/gl/glestranslator/gles_cm:gles_cm_translator_static", "//host/iostream:gfxstream_host_iostream", "//host/library:gfxstream_host_library", + "//host/native_window:gfxstream_host_native_window", "//host/renderControl_dec", "//host/renderdoc:gfxstream_host_renderdoc", "//host/snapshot:gfxstream_host_snapshot", @@ -246,12 +206,7 @@ cc_library( "//third_party/xcb", "@protobuf", "@protobuf//src/google/protobuf/io", - ] + select({ - "@platforms//os:macos": [ - ":gfxstream_backend_static-darwin", - ], - "//conditions:default": [], - }), + ], ) cc_library( @@ -319,6 +274,7 @@ cc_test( "//common/testenv:graphics_test_environment_support", "//host/common:gfxstream_host_common", "//host/features:gfxstream_host_features", + "//host/gl:gfxstream_opengl_server", "//host/testlibs/oswindow:gfxstream_oswindow_test_support", "//host/testlibs/support:gfxstream_host_testing_support", "@com_google_googletest//:gtest", diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index d18a2a73e..3f45b638f 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -52,6 +52,7 @@ add_subdirectory(tracing) add_subdirectory(decoder_common) add_subdirectory(compressed_textures) add_subdirectory(renderdoc) +add_subdirectory(native_window) add_library( gfxstream_backend.headers @@ -102,15 +103,7 @@ set(stream-server-core-sources virtio_gpu_ring_blob.cpp virtio_gpu_timelines.cpp vsync_thread.cpp) -if (APPLE) - set(stream-server-core-platform-sources native_sub_window_cocoa.mm) -elseif (WIN32) - set(stream-server-core-platform-sources native_sub_window_win32.cpp) -elseif (QNX) - set(stream-server-core-platform-sources native_sub_window_qnx.cpp) -else() - set(stream-server-core-platform-sources native_sub_window_x11.cpp) -endif() + @@ -120,7 +113,6 @@ add_library( gfxstream_backend_static STATIC ${stream-server-core-sources} - ${stream-server-core-platform-sources} ) target_link_libraries( gfxstream_backend_static @@ -146,6 +138,7 @@ target_link_libraries( gfxstream-vulkan-server GLES_CM_translator_static renderControl_dec + gfxstream_host_native_window ) if(NOT APPLE AND NOT WIN32) target_link_libraries(gfxstream_backend_static PUBLIC gfxstream_xcb_headers) diff --git a/host/decoder_common/Android.bp b/host/decoder_common/Android.bp index 3c914e240..09ac25589 100644 --- a/host/decoder_common/Android.bp +++ b/host/decoder_common/Android.bp @@ -33,6 +33,9 @@ cc_library_static { "libgfxstream_host_library", "libgfxstream_common_logging", ], + export_static_lib_headers: [ + "libgfxstream_common_base", + ], cflags: ["-fvisibility=hidden"], export_include_dirs: [ "include", diff --git a/host/frame_buffer.cpp b/host/frame_buffer.cpp index c06e31f65..8f441366e 100644 --- a/host/frame_buffer.cpp +++ b/host/frame_buffer.cpp @@ -40,12 +40,12 @@ #include "gl/glestranslator/egl/egl_global_info.h" #endif -#include "color_buffer.h" #include "gfxstream/Tracing.h" #include "gfxstream/common/logging.h" #include "gfxstream/containers/Lookup.h" #include "gfxstream/host/display_operations.h" #include "gfxstream/host/guest_operations.h" +#include "gfxstream/host/native_sub_window.h" #include "gfxstream/host/renderer_operations.h" #include "gfxstream/host/stream_utils.h" #include "gfxstream/host/tracing.h" @@ -56,7 +56,6 @@ #include "gfxstream/system/System.h" #include "host/gl/context_helper.h" #include "hwc2.h" -#include "native_sub_window.h" #include "render-utils/MediaNative.h" #include "render_thread_info.h" #include "sync_thread.h" diff --git a/host/gles_compat.h b/host/gles_compat.h deleted file mode 100644 index 6aef3b1ef..000000000 --- a/host/gles_compat.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2024 The Android Open Source Project -// -// 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. - -#ifndef GLES_COMPAT_H -#define GLES_COMPAT_H - -#include - -typedef unsigned int GLenum; -typedef int32_t EGLint; -// Must stay ABI-compatible with the real EGLNativeWindowType from -// , which is pointer-sized on 64-bit platforms -// (e.g. `void*` on Apple); a 32-bit integer here truncates pointers. -typedef void* EGLNativeWindowType; - -namespace gfxstream { -namespace gl { -class EmulationGl { - public: - EmulationGl() {} - ~EmulationGl() {} - - private: - uint32_t payload; -}; -} // namespace gl -} // namespace gfxstream - -#endif diff --git a/host/meson.build b/host/meson.build index 3937c075f..fb2fc960a 100644 --- a/host/meson.build +++ b/host/meson.build @@ -20,20 +20,22 @@ subdir('snapshot') subdir('decoder_common') subdir('address_space') subdir('common') +subdir('native_window') inc_gfxstream_backend = [ - inc_host_decoder_common, inc_common_base, + inc_common_logging, inc_common_utils, inc_drm_headers, inc_glm, inc_host_address_space, inc_host_common, + inc_host_decoder_common, inc_host_features, inc_host_include, inc_host_iostream, inc_host_library, - inc_common_logging, + inc_host_native_window, inc_host_renderdoc, inc_host_snapshot, inc_host_tracing, @@ -43,14 +45,15 @@ inc_gfxstream_backend = [ ] link_gfxstream_backend = [ - lib_host_decoder_common, lib_common_base, + lib_common_logging, lib_common_utils, lib_host_address_space, lib_host_common, + lib_host_decoder_common, lib_host_features, lib_host_library, - lib_common_logging, + lib_host_native_window, lib_host_tracing, ] @@ -129,21 +132,6 @@ if use_composer link_gfxstream_backend += lib_composer endif -if not use_gles - files_lib_gfxstream_backend += files('native_sub_window_stub.cpp') -elif host_machine.system() == 'darwin' - files_lib_gfxstream_backend += files('native_sub_window_cocoa.mm') -elif host_machine.system() == 'windows' - files_lib_gfxstream_backend += files('native_sub_window_win32.cpp') -elif host_machine.system() == 'linux' and use_gles - files_lib_gfxstream_backend += files('native_sub_window_x11.cpp') -elif host_machine.system() == 'qnx' - files_lib_gfxstream_backend += files( - 'platform_helper_qnx.cpp', - 'native_sub_window_qnx.cpp', - ) -endif - gfxstream_backend_cpp_args = [ '-Wno-unused-parameter', '-Wno-unused-variable', diff --git a/host/native_sub_window_android.cpp b/host/native_sub_window_android.cpp deleted file mode 100644 index 93edad0a4..000000000 --- a/host/native_sub_window_android.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* -* Copyright (C) 2011 The Android Open Source Project -* -* 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. -*/ -#include "native_sub_window.h" - -#include - -#include - -EGLNativeWindowType createSubWindow(FBNativeWindowType p_window, - int x, - int y, - int width, - int height, - float dpr, - SubWindowRepaintCallback repaint_callback, - void* repaint_callback_param, - int hideWindow) { - ANativeWindow_acquire(p_window); - ANativeWindow_setBuffersGeometry(p_window, width, height, AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM); - return p_window; -} - -void destroySubWindow(EGLNativeWindowType win) { - ANativeWindow_release(win); -} - -int moveSubWindow(FBNativeWindowType p_parent_window, - EGLNativeWindowType p_sub_window, - int x, - int y, - int width, - int height, - float dpr) { - // moving windows not supported in Android; we can't create an actual sub window - return true; -} - -void* getNativeDisplay() { - fprintf(stderr, "%s: Unimplemented\n", __func__); - return nullptr; -} diff --git a/host/native_sub_window_win32.cpp b/host/native_sub_window_win32.cpp deleted file mode 100644 index 4ba8fc154..000000000 --- a/host/native_sub_window_win32.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/* -* Copyright (C) 2011 The Android Open Source Project -* -* 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. -*/ -#include "native_sub_window.h" - -#include - -struct SubWindowUserData { - SubWindowRepaintCallback repaint_callback; - void* repaint_callback_param; -}; - -static LRESULT CALLBACK subWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { - if (uMsg == WM_PAINT) { - auto user_data = - (SubWindowUserData*)GetWindowLongPtr(hwnd, GWLP_USERDATA); - if (user_data && user_data->repaint_callback) { - user_data->repaint_callback(user_data->repaint_callback_param); - } - } else if (uMsg == WM_NCDESTROY) { - SubWindowUserData* user_data = - (SubWindowUserData*)GetWindowLongPtr(hwnd, GWLP_USERDATA); - delete user_data; - } - return DefWindowProcA(hwnd, uMsg, wParam, lParam); -} - -EGLNativeWindowType createSubWindow(FBNativeWindowType p_window, - int x, int y,int width, int height, float dpr, - SubWindowRepaintCallback repaint_callback, - void* repaint_callback_param, int hideWindow){ - static const char className[] = "subWin"; - - WNDCLASSA wc = {}; - if (!GetClassInfoA(GetModuleHandle(NULL), className, &wc)) { - wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;// redraw if size changes - wc.lpfnWndProc = &subWindowProc; // points to window procedure - wc.cbWndExtra = sizeof(void*) ; // save extra window memory - wc.lpszClassName = className; // name of window class - RegisterClassA(&wc); - } - - // We assume size/pos are passed in as logical size/coordinates. Convert it to pixel - // coordinates. - x *= dpr; - y *= dpr; - width *= dpr; - height *= dpr; - EGLNativeWindowType ret = CreateWindowExA( - WS_EX_NOPARENTNOTIFY, // do not bother our parent window - className, - "sub", - WS_CHILD|WS_DISABLED, - x,y,width,height, - p_window, - NULL, - NULL, - NULL); - - auto user_data = new SubWindowUserData(); - user_data->repaint_callback = repaint_callback; - user_data->repaint_callback_param = repaint_callback_param; - - SetWindowLongPtr(ret, GWLP_USERDATA, (LONG_PTR)user_data); - if (!hideWindow) - ShowWindow(ret, SW_SHOW); - return ret; -} - -void destroySubWindow(EGLNativeWindowType win){ - PostMessage(win, WM_CLOSE, 0, 0); -} - -int moveSubWindow(FBNativeWindowType p_parent_window, - EGLNativeWindowType p_sub_window, - int x, - int y, - int width, - int height, - float dpr) { - BOOL ret = MoveWindow(p_sub_window, - x * dpr, - y * dpr, - width * dpr, - height * dpr, - TRUE); - return ret; -} - -void* getNativeDisplay() { - fprintf(stderr, "%s: Unimplemented\n", __func__); - return nullptr; -} diff --git a/host/native_sub_window_x11.cpp b/host/native_sub_window_x11.cpp deleted file mode 100644 index 062ace8ec..000000000 --- a/host/native_sub_window_x11.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/* -* Copyright (C) 2011 The Android Open Source Project -* -* 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. -*/ -#include "native_sub_window.h" - -#include - -#include "gfxstream/host/X11Support.h" - -namespace { - -static Bool WaitForMapNotify(Display *d, XEvent *e, char *arg) { - if (e->type == MapNotify && e->xmap.window == (Window)arg) { - return 1; - } - return 0; -} - -static Bool WaitForConfigureNotify(Display *d, XEvent *e, char *arg) { - if (e->type == ConfigureNotify && e->xmap.window == (Window)arg) { - return 1; - } - return 0; -} - -static Display *s_display = NULL; - -} // namespace - -EGLNativeWindowType createSubWindow(FBNativeWindowType p_window, - int x, - int y, - int width, - int height, - float dpr, - SubWindowRepaintCallback repaint_callback, - void* repaint_callback_param, - int hideWindow) { - auto x11 = getX11Api(); - // The call to this function is protected by a lock - // in FrameBuffer so it is safe to check and initialize s_display here - if (!s_display) { - s_display = x11->XOpenDisplay(NULL); - } - - XSetWindowAttributes wa; - wa.event_mask = StructureNotifyMask; - wa.override_redirect = True; - Window win = x11->XCreateWindow(s_display, - p_window, - x * dpr, - y * dpr, - width * dpr, - height * dpr, - 0, - CopyFromParent, - CopyFromParent, - CopyFromParent, - CWEventMask, - &wa); - if (!hideWindow) { - x11->XMapWindow(s_display,win); - x11->XSetWindowBackground(s_display, win, 0); - XEvent e; - x11->XIfEvent(s_display, &e, WaitForMapNotify, (char *)win); - } - return win; -} - -void destroySubWindow(EGLNativeWindowType win) { - if (!s_display) { - return; - } - - getX11Api()->XDestroyWindow(s_display, win); -} - -int moveSubWindow(FBNativeWindowType p_parent_window, - EGLNativeWindowType p_sub_window, - int x, - int y, - int width, - int height, - float dpr) { - // This value is set during create, so if it is still null, simply - // return because the global state is corrupted - if (!s_display) { - return false; - } - - x *= dpr; - y *= dpr; - width *= dpr; - height *= dpr; - - auto x11 = getX11Api(); - - // Make sure something has changed, otherwise XIfEvent will block and - // freeze the emulator. - XWindowAttributes attrs; - if (!x11->XGetWindowAttributes(s_display, p_sub_window, &attrs)) { - return false; - } - if (x == attrs.x && y == attrs.y && - width == attrs.width && height == attrs.height) { - // Technically, resizing was a success because it was unneeded. - return true; - } - - // This prevents flicker on resize. - x11->XSetWindowBackgroundPixmap(s_display, p_sub_window, None); - - int ret = x11->XMoveResizeWindow( - s_display, - p_sub_window, - x, - y, - width, - height); - - XEvent e; - x11->XIfEvent(s_display, &e, WaitForConfigureNotify, (char *)p_sub_window); - - return ret; -} - -void* getNativeDisplay() { - return s_display; -} diff --git a/host/native_window/Android.bp b/host/native_window/Android.bp new file mode 100644 index 000000000..02e463fd6 --- /dev/null +++ b/host/native_window/Android.bp @@ -0,0 +1,36 @@ +package { + default_applicable_licenses: ["hardware_google_gfxstream_license"], +} + +cc_library_static { + name: "libgfxstream_host_native_window", + defaults: ["gfxstream_host_cc_defaults"], + srcs: [ + "native_sub_window_stub.cpp", + ], + target: { + host: { + srcs: ["native_sub_window_x11.cpp"], + static_libs: [ + "libgfxstream_host_decoder_common", + ], + }, + android: { + srcs: ["native_sub_window_android.cpp"], + shared_libs: [ + "libnativewindow", + ], + }, + darwin: { + srcs: ["native_sub_window_cocoa.mm"], + }, + windows: { + srcs: ["native_sub_window_win32.cpp"], + }, + }, + export_include_dirs: ["include"], + header_libs: [ + "libgfxstream_backend_headers", + "libgfxstream_thirdparty_opengl_headers", + ], +} diff --git a/host/native_window/BUILD.bazel b/host/native_window/BUILD.bazel new file mode 100644 index 000000000..08120e950 --- /dev/null +++ b/host/native_window/BUILD.bazel @@ -0,0 +1,73 @@ +load("@rules_cc//cc:defs.bzl", "cc_library", "objc_library") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") + +package( + default_applicable_licenses = ["//:gfxstream_license"], + default_visibility = ["//:gfxstream"], +) + +objc_library( + name = "gfxstream_host_native_window-darwin", + srcs = [ + "native_sub_window_cocoa.mm", + ], + hdrs = [ + "include/gfxstream/host/native_sub_window.h", + ], + copts = GFXSTREAM_HOST_COPTS + [ + "-Wno-deprecated-declarations", + "-std=c++20", + "-fno-objc-arc", + ], + defines = GFXSTREAM_HOST_DEFINES, + includes = ["include"], + sdk_frameworks = [ + "AppKit", + "QuartzCore", + "IOSurface", + ], + target_compatible_with = [ + "@platforms//os:macos", + ], + deps = [ + "//host:gfxstream_backend_headers", + "//third_party/opengl:gfxstream_egl_headers", + ], +) + +cc_library( + name = "gfxstream_host_native_window", + srcs = select({ + "@platforms//os:macos": [], + "@platforms//os:windows": [ + "native_sub_window_win32.cpp", + ], + "@platforms//os:linux": [ + "native_sub_window_x11.cpp", + ], + "//conditions:default": [ + "native_sub_window_stub.cpp", + ], + }), + hdrs = [ + "include/gfxstream/host/native_sub_window.h", + ], + copts = GFXSTREAM_HOST_COPTS, + defines = GFXSTREAM_HOST_DEFINES, + includes = ["include"], + deps = select({ + "@platforms//os:macos": [ + ":gfxstream_host_native_window-darwin", + ], + "//conditions:default": [], + }) + [ + "//common/base:gfxstream_common_base", + "//common/logging:gfxstream_common_logging", + "//host:gfxstream_backend_headers", + "//host/decoder_common:gfxstream_host_decoder_common", + "//third_party/opengl:gfxstream_egl_headers", + "//third_party/opengl:gfxstream_gles2_headers", + "//third_party/opengl:gfxstream_gles3_headers", + "//third_party/xcb", + ], +) diff --git a/host/native_window/CMakeLists.txt b/host/native_window/CMakeLists.txt new file mode 100644 index 000000000..3ddaa5e11 --- /dev/null +++ b/host/native_window/CMakeLists.txt @@ -0,0 +1,36 @@ + + +if (APPLE) + set(gfxstream_host_native_window_platform_sources + native_sub_window_cocoa.mm) +elseif (WIN32) + set(gfxstream_host_native_window_platform_sources + native_sub_window_win32.cpp) +elseif (QNX) + set(gfxstream_host_native_window_platform_sources + native_sub_window_qnx.cpp) +else() + set(gfxstream_host_native_window_platform_sources + native_sub_window_x11.cpp) +endif() + + +add_library( + gfxstream_host_native_window + STATIC + native_sub_window_stub.cpp + ${gfxstream_host_native_window_platform_sources}) + +target_include_directories( + gfxstream_host_native_window + PUBLIC + include + ) + +target_link_libraries( + gfxstream_host_native_window + PRIVATE + gfxstream_common_base + gfxstream_backend_headers + gfxstream_host_decoder_common + ) diff --git a/host/native_sub_window.h b/host/native_window/include/gfxstream/host/native_sub_window.h similarity index 62% rename from host/native_sub_window.h rename to host/native_window/include/gfxstream/host/native_sub_window.h index 3791a9e71..d7e4a37f9 100644 --- a/host/native_sub_window.h +++ b/host/native_window/include/gfxstream/host/native_sub_window.h @@ -1,27 +1,34 @@ /* -* Copyright (C) 2011 The Android Open Source Project -* -* 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. -*/ + * Copyright (C) 2011 The Android Open Source Project + * + * 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. + */ #ifndef NATIVE_SUB_WINDOW_H #define NATIVE_SUB_WINDOW_H +#include + #include "render-utils/render_api_platform_types.h" #if GFXSTREAM_ENABLE_HOST_GLES #include #else -#include "gles_compat.h" +typedef unsigned int GLenum; +typedef int32_t EGLint; +// Must stay ABI-compatible with the real EGLNativeWindowType from +// , which is pointer-sized on 64-bit platforms +// (e.g. `void*` on Apple); a 32-bit integer here truncates pointers. +typedef void* EGLNativeWindowType; #endif #ifdef __cplusplus @@ -44,15 +51,10 @@ typedef void (*SubWindowRepaintCallback)(void*); // repaint callback when/if it's invoked. // On success, return a new platform-specific window handle, cast as an // EGLNativeWindowType. Or 0/NULL in case of failure. -EGLNativeWindowType createSubWindow(FBNativeWindowType p_window, - int x, - int y, - int width, - int height, - float dpr, +EGLNativeWindowType createSubWindow(FBNativeWindowType p_window, int x, int y, int width, + int height, float dpr, SubWindowRepaintCallback repaint_callback, - void* repaint_callback_param, - int hideWindow); + void* repaint_callback_param, int hideWindow); // Destroy a sub-window previously created through createSubWindow() above. void destroySubWindow(EGLNativeWindowType win); @@ -62,13 +64,8 @@ void destroySubWindow(EGLNativeWindowType win); // |p_sub_window| is the platform-specific handle to the EGL subwindow. // |x|,|y|,|width|,|height| are the new location and dimensions of the // subwindow. -int moveSubWindow(FBNativeWindowType p_parent_window, - EGLNativeWindowType p_sub_window, - int x, - int y, - int width, - int height, - float dpr); +int moveSubWindow(FBNativeWindowType p_parent_window, EGLNativeWindowType p_sub_window, int x, + int y, int width, int height, float dpr); void* getNativeDisplay(); diff --git a/host/native_window/meson.build b/host/native_window/meson.build new file mode 100644 index 000000000..c5da6236a --- /dev/null +++ b/host/native_window/meson.build @@ -0,0 +1,30 @@ +# Copyright 2026 Android Open Source Project +# SPDX-License-Identifier: Apache-2.0 + +inc_host_native_window = include_directories('include') + +files_lib_host_native_window = files('native_sub_window_stub.cpp') + +if host_machine.system() == 'darwin' + files_lib_host_native_window += files('native_sub_window_cocoa.mm') +elif host_machine.system() == 'windows' + files_lib_host_native_window += files('native_sub_window_win32.cpp') +elif host_machine.system() == 'linux' and use_gles + files_lib_host_native_window += files('native_sub_window_x11.cpp') +elif host_machine.system() == 'qnx' + files_lib_host_native_window += files( + 'native_sub_window_qnx.cpp', + ) +endif + +lib_host_native_window = static_library( + 'host_native_window', + files_lib_host_native_window, + include_directories: [ + inc_common_base, + inc_host_common, + inc_host_decoder_common, + inc_host_include, + inc_host_native_window, + ], +) diff --git a/host/native_window/native_sub_window_android.cpp b/host/native_window/native_sub_window_android.cpp new file mode 100644 index 000000000..cafb1fe8d --- /dev/null +++ b/host/native_window/native_sub_window_android.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * 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. + */ +#include +#include + +#include "gfxstream/host/native_sub_window.h" + +EGLNativeWindowType createSubWindow(FBNativeWindowType p_window, int x, int y, int width, + int height, float dpr, + SubWindowRepaintCallback repaint_callback, + void* repaint_callback_param, int hideWindow) { + ANativeWindow_acquire(p_window); + ANativeWindow_setBuffersGeometry(p_window, width, height, + AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM); + return p_window; +} + +void destroySubWindow(EGLNativeWindowType win) { ANativeWindow_release(win); } + +int moveSubWindow(FBNativeWindowType p_parent_window, EGLNativeWindowType p_sub_window, int x, + int y, int width, int height, float dpr) { + // moving windows not supported in Android; we can't create an actual sub window + return true; +} + +void* getNativeDisplay() { + fprintf(stderr, "%s: Unimplemented\n", __func__); + return nullptr; +} diff --git a/host/native_sub_window_cocoa.mm b/host/native_window/native_sub_window_cocoa.mm similarity index 66% rename from host/native_sub_window_cocoa.mm rename to host/native_window/native_sub_window_cocoa.mm index 49790f079..583d060c5 100644 --- a/host/native_sub_window_cocoa.mm +++ b/host/native_window/native_sub_window_cocoa.mm @@ -1,24 +1,23 @@ /* -* Copyright (C) 2011 The Android Open Source Project -* -* 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. -*/ + * Copyright (C) 2011 The Android Open Source Project + * + * 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. + */ #import #import - -#include "native_sub_window.h" #include +#include "gfxstream/host/native_sub_window.h" /* * EmuGLView inherit from NSOpenGLView and override the isOpaque @@ -26,51 +25,46 @@ * when the view needs to be redrawn. */ @interface EmuGLView : NSOpenGLView { -} @end +} +@end @implementation EmuGLView - - (BOOL)isOpaque { - return YES; - } +- (BOOL)isOpaque { + return YES; +} @end @interface EmuGLViewWithMetal : NSOpenGLView -- (CAMetalLayer *)getMetalLayer; +- (CAMetalLayer*)getMetalLayer; @end - @implementation EmuGLViewWithMetal - - (BOOL)isOpaque { - return YES; - } +- (BOOL)isOpaque { + return YES; +} - - (CALayer *)makeBackingLayer { - CALayer * layer = [CAMetalLayer layer]; +- (CALayer*)makeBackingLayer { + CALayer* layer = [CAMetalLayer layer]; return layer; - } +} - - (CAMetalLayer *)getMetalLayer { - // The 'layer' property on NSView returns a CALayer. We can safely cast it - // to CAMetalLayer because we configured the view to use it. - return (CAMetalLayer *)self.layer; - } +- (CAMetalLayer*)getMetalLayer { + // The 'layer' property on NSView returns a CALayer. We can safely cast it + // to CAMetalLayer because we configured the view to use it. + return (CAMetalLayer*)self.layer; +} @end -EGLNativeWindowType createSubWindow(FBNativeWindowType p_window, - int x, - int y, - int width, - int height, - float dpr, +EGLNativeWindowType createSubWindow(FBNativeWindowType p_window, int x, int y, int width, + int height, float dpr, SubWindowRepaintCallback repaint_callback, - void* repaint_callback_param, - int hideWindow) { - NSWindow* win = (NSWindow *)p_window; + void* repaint_callback_param, int hideWindow) { + NSWindow* win = (NSWindow*)p_window; if (!win) { return NULL; } @@ -116,26 +110,21 @@ EGLNativeWindowType createSubWindow(FBNativeWindowType p_window, } void destroySubWindow(EGLNativeWindowType win) { - if(win){ - NSView *glView = (NSView *)win; + if (win) { + NSView* glView = (NSView*)win; [glView removeFromSuperview]; [glView release]; } } -int moveSubWindow(FBNativeWindowType p_parent_window, - EGLNativeWindowType p_sub_window, - int x, - int y, - int width, - int height, - float dpr) { - NSWindow *win = (NSWindow *)p_parent_window; +int moveSubWindow(FBNativeWindowType p_parent_window, EGLNativeWindowType p_sub_window, int x, + int y, int width, int height, float dpr) { + NSWindow* win = (NSWindow*)p_parent_window; if (!win) { return 0; } - NSView *glView = (NSView *)p_sub_window; + NSView* glView = (NSView*)p_sub_window; if (!glView) { return 0; } diff --git a/host/native_sub_window_qnx.cpp b/host/native_window/native_sub_window_qnx.cpp similarity index 98% rename from host/native_sub_window_qnx.cpp rename to host/native_window/native_sub_window_qnx.cpp index cf459e0d3..21b9cdbed 100644 --- a/host/native_sub_window_qnx.cpp +++ b/host/native_window/native_sub_window_qnx.cpp @@ -17,7 +17,7 @@ #include -#include "native_sub_window.h" +#include "gfxstream/host/native_sub_window.h" #include "platform_helper_qnx.h" EGLNativeWindowType createSubWindow(FBNativeWindowType p_window, int x, int y, int width, diff --git a/host/native_sub_window_stub.cpp b/host/native_window/native_sub_window_stub.cpp similarity index 95% rename from host/native_sub_window_stub.cpp rename to host/native_window/native_sub_window_stub.cpp index c4379bc19..6375fdd65 100644 --- a/host/native_sub_window_stub.cpp +++ b/host/native_window/native_sub_window_stub.cpp @@ -14,8 +14,9 @@ * limitations under the License. */ -#include "gles_compat.h" -#include "native_sub_window.h" +#include + +#include "gfxstream/host/native_sub_window.h" EGLNativeWindowType createSubWindow(FBNativeWindowType p_window, int x, int y, int width, int height, float dpr, diff --git a/host/native_window/native_sub_window_win32.cpp b/host/native_window/native_sub_window_win32.cpp new file mode 100644 index 000000000..7f9806958 --- /dev/null +++ b/host/native_window/native_sub_window_win32.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * 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. + */ +#include + +#include "gfxstream/host/native_sub_window.h" + +struct SubWindowUserData { + SubWindowRepaintCallback repaint_callback; + void* repaint_callback_param; +}; + +static LRESULT CALLBACK subWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { + if (uMsg == WM_PAINT) { + auto user_data = (SubWindowUserData*)GetWindowLongPtr(hwnd, GWLP_USERDATA); + if (user_data && user_data->repaint_callback) { + user_data->repaint_callback(user_data->repaint_callback_param); + } + } else if (uMsg == WM_NCDESTROY) { + SubWindowUserData* user_data = (SubWindowUserData*)GetWindowLongPtr(hwnd, GWLP_USERDATA); + delete user_data; + } + return DefWindowProcA(hwnd, uMsg, wParam, lParam); +} + +EGLNativeWindowType createSubWindow(FBNativeWindowType p_window, int x, int y, int width, + int height, float dpr, + SubWindowRepaintCallback repaint_callback, + void* repaint_callback_param, int hideWindow) { + static const char className[] = "subWin"; + + WNDCLASSA wc = {}; + if (!GetClassInfoA(GetModuleHandle(NULL), className, &wc)) { + wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; // redraw if size changes + wc.lpfnWndProc = &subWindowProc; // points to window procedure + wc.cbWndExtra = sizeof(void*); // save extra window memory + wc.lpszClassName = className; // name of window class + RegisterClassA(&wc); + } + + // We assume size/pos are passed in as logical size/coordinates. Convert it to pixel + // coordinates. + x *= dpr; + y *= dpr; + width *= dpr; + height *= dpr; + EGLNativeWindowType ret = CreateWindowExA( + WS_EX_NOPARENTNOTIFY, // do not bother our parent window + className, "sub", WS_CHILD | WS_DISABLED, x, y, width, height, p_window, NULL, NULL, NULL); + + auto user_data = new SubWindowUserData(); + user_data->repaint_callback = repaint_callback; + user_data->repaint_callback_param = repaint_callback_param; + + SetWindowLongPtr(ret, GWLP_USERDATA, (LONG_PTR)user_data); + if (!hideWindow) ShowWindow(ret, SW_SHOW); + return ret; +} + +void destroySubWindow(EGLNativeWindowType win) { PostMessage(win, WM_CLOSE, 0, 0); } + +int moveSubWindow(FBNativeWindowType p_parent_window, EGLNativeWindowType p_sub_window, int x, + int y, int width, int height, float dpr) { + BOOL ret = MoveWindow(p_sub_window, x * dpr, y * dpr, width * dpr, height * dpr, TRUE); + return ret; +} + +void* getNativeDisplay() { + fprintf(stderr, "%s: Unimplemented\n", __func__); + return nullptr; +} diff --git a/host/native_window/native_sub_window_x11.cpp b/host/native_window/native_sub_window_x11.cpp new file mode 100644 index 000000000..6f917661e --- /dev/null +++ b/host/native_window/native_sub_window_x11.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * 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. + */ +#include + +#include "gfxstream/host/X11Support.h" +#include "gfxstream/host/native_sub_window.h" + +namespace { + +static Bool WaitForMapNotify(Display* d, XEvent* e, char* arg) { + if (e->type == MapNotify && e->xmap.window == (Window)arg) { + return 1; + } + return 0; +} + +static Bool WaitForConfigureNotify(Display* d, XEvent* e, char* arg) { + if (e->type == ConfigureNotify && e->xmap.window == (Window)arg) { + return 1; + } + return 0; +} + +static Display* s_display = NULL; + +} // namespace + +EGLNativeWindowType createSubWindow(FBNativeWindowType p_window, int x, int y, int width, + int height, float dpr, + SubWindowRepaintCallback repaint_callback, + void* repaint_callback_param, int hideWindow) { + auto x11 = getX11Api(); + // The call to this function is protected by a lock + // in FrameBuffer so it is safe to check and initialize s_display here + if (!s_display) { + s_display = x11->XOpenDisplay(NULL); + } + + XSetWindowAttributes wa; + wa.event_mask = StructureNotifyMask; + wa.override_redirect = True; + Window win = + x11->XCreateWindow(s_display, p_window, x * dpr, y * dpr, width * dpr, height * dpr, 0, + CopyFromParent, CopyFromParent, CopyFromParent, CWEventMask, &wa); + if (!hideWindow) { + x11->XMapWindow(s_display, win); + x11->XSetWindowBackground(s_display, win, 0); + XEvent e; + x11->XIfEvent(s_display, &e, WaitForMapNotify, (char*)win); + } + return win; +} + +void destroySubWindow(EGLNativeWindowType win) { + if (!s_display) { + return; + } + + getX11Api()->XDestroyWindow(s_display, win); +} + +int moveSubWindow(FBNativeWindowType p_parent_window, EGLNativeWindowType p_sub_window, int x, + int y, int width, int height, float dpr) { + // This value is set during create, so if it is still null, simply + // return because the global state is corrupted + if (!s_display) { + return false; + } + + x *= dpr; + y *= dpr; + width *= dpr; + height *= dpr; + + auto x11 = getX11Api(); + + // Make sure something has changed, otherwise XIfEvent will block and + // freeze the emulator. + XWindowAttributes attrs; + if (!x11->XGetWindowAttributes(s_display, p_sub_window, &attrs)) { + return false; + } + if (x == attrs.x && y == attrs.y && width == attrs.width && height == attrs.height) { + // Technically, resizing was a success because it was unneeded. + return true; + } + + // This prevents flicker on resize. + x11->XSetWindowBackgroundPixmap(s_display, p_sub_window, None); + + int ret = x11->XMoveResizeWindow(s_display, p_sub_window, x, y, width, height); + + XEvent e; + x11->XIfEvent(s_display, &e, WaitForConfigureNotify, (char*)p_sub_window); + + return ret; +} + +void* getNativeDisplay() { return s_display; } diff --git a/host/vulkan/Android.bp b/host/vulkan/Android.bp index 854ccd5b6..592445041 100644 --- a/host/vulkan/Android.bp +++ b/host/vulkan/Android.bp @@ -50,6 +50,7 @@ cc_library_static { "libgfxstream_host_snapshot", "libgfxstream_host_vulkan_cereal", "libgfxstream_host_vulkan_emulatedtextures", + "libgfxstream_host_native_window", ], export_static_lib_headers: [ "libgfxstream_host_decoder_common", diff --git a/host/vulkan/BUILD.bazel b/host/vulkan/BUILD.bazel index 06bb7acd4..014b502bd 100644 --- a/host/vulkan/BUILD.bazel +++ b/host/vulkan/BUILD.bazel @@ -164,6 +164,7 @@ cc_library( "//host/gl/OpenGLESDispatch:gfxstream_host_openglesdispatch_headers", "//host/iostream:gfxstream_host_iostream", "//host/library:gfxstream_host_library", + "//host/native_window:gfxstream_host_native_window", "//host/renderdoc:gfxstream_host_renderdoc", "//host/tracing:gfxstream_host_tracing", "//host/vulkan/cereal:gfxstream_vulkan_cereal", diff --git a/host/vulkan/CMakeLists.txt b/host/vulkan/CMakeLists.txt index c041ab66a..884c8ef1c 100644 --- a/host/vulkan/CMakeLists.txt +++ b/host/vulkan/CMakeLists.txt @@ -72,6 +72,7 @@ target_link_libraries(gfxstream-vulkan-server PUBLIC gfxstream_vulkan_headers gfxstream_xcb_headers OpenglRender_vulkan_cereal + gfxstream_host_native_window PRIVATE gfxstream_opengl_headers ) diff --git a/host/vulkan/display_surface_vk.cpp b/host/vulkan/display_surface_vk.cpp index b8ca49ff5..d9da517d2 100644 --- a/host/vulkan/display_surface_vk.cpp +++ b/host/vulkan/display_surface_vk.cpp @@ -18,7 +18,7 @@ #if defined(VK_USE_PLATFORM_XCB_KHR) #include "gfxstream/host/X11Support.h" #endif -#include "native_sub_window.h" +#include "gfxstream/host/native_sub_window.h" #include "vk_utils.h" namespace gfxstream { diff --git a/host/vulkan/meson.build b/host/vulkan/meson.build index c09233172..7461480c5 100644 --- a/host/vulkan/meson.build +++ b/host/vulkan/meson.build @@ -73,6 +73,7 @@ lib_vulkan_server = static_library( inc_cereal_common, inc_cereal, inc_common_base, + inc_common_logging, inc_common_utils, inc_gl_openglesdispatch, inc_gl_server, @@ -84,7 +85,7 @@ lib_vulkan_server = static_library( inc_host_include, inc_host_iostream, inc_host_library, - inc_common_logging, + inc_host_native_window, inc_host_renderdoc, inc_host_snapshot, inc_host_tracing, @@ -104,6 +105,7 @@ lib_vulkan_server = static_library( lib_host_compressed_textures, lib_host_features, lib_host_library, + lib_host_native_window, lib_host_tracing, lib_vulkan_cereal, ], From 6d7cf2dc53a371a8390d668bd4871ba0975f8c1b Mon Sep 17 00:00:00 2001 From: Jason Macnak Date: Fri, 24 Jul 2026 13:33:12 -0700 Subject: [PATCH 18/33] Move some common headers to host/common ... to continue to decouple and break the circular dependencies between the main host server and the gl and vk backends. Bug: b/537737772 Test: bazel test //host/... Low-Coverage-Reason: REFACTOR_ONLY Change-Id: Ib167048865ce447777162acb3c0628dfa893d6a3 --- host/Android.bp | 1 - host/BUILD.bazel | 13 ------ host/CMakeLists.txt | 1 - host/buffer.h | 2 +- host/color_buffer.h | 6 +-- host/common/Android.bp | 1 + host/common/BUILD.bazel | 1 + host/common/CMakeLists.txt | 1 + host/{ => common}/hwc2.cpp | 8 ++-- .../include/gfxstream/host}/compositor.h | 6 +-- .../gfxstream/host}/framework_formats.h | 0 .../include/gfxstream/host}/handle.h | 0 .../include/gfxstream/host}/hwc2.h | 31 +++++++------- .../include/gfxstream/host}/readback_worker.h | 40 +++++++++---------- host/common/meson.build | 1 + host/frame_buffer.cpp | 2 +- host/frame_buffer.h | 4 +- host/gl/BUILD.bazel | 1 + host/gl/buffer_gl.h | 2 +- host/gl/color_buffer_gl.h | 4 +- host/gl/compositor_gl.h | 6 +-- host/gl/display_gl.h | 2 +- host/gl/emulated_egl_context.h | 2 +- host/gl/emulated_egl_image.h | 2 +- host/gl/emulated_egl_window_surface.h | 2 +- host/gl/emulation_gl.h | 2 +- host/gl/readback_worker_gl.h | 12 +++--- host/gl/render_thread_info_gl.h | 2 +- host/{ => gl}/stale_ptr_registry.h | 0 host/gl/texture_draw.h | 2 +- host/meson.build | 1 - host/post_commands.h | 2 +- host/post_worker.h | 4 +- .../host/testing/SampleApplication.h | 6 +-- host/virtio_gpu_frontend.cpp | 6 +-- host/vulkan/compositor_vk.h | 4 +- host/vulkan/display_vk.h | 2 +- host/vulkan/vk_common_operations.h | 2 +- host/vulkan/vk_decoder_internal_structs.h | 2 +- 39 files changed, 86 insertions(+), 100 deletions(-) rename host/{ => common}/hwc2.cpp (86%) rename host/{ => common/include/gfxstream/host}/compositor.h (96%) rename host/{ => common/include/gfxstream/host}/framework_formats.h (100%) rename host/{ => common/include/gfxstream/host}/handle.h (100%) rename host/{ => common/include/gfxstream/host}/hwc2.h (84%) rename host/{ => common/include/gfxstream/host}/readback_worker.h (74%) rename host/{ => gl}/stale_ptr_registry.h (100%) diff --git a/host/Android.bp b/host/Android.bp index c76e169bd..517a3872c 100644 --- a/host/Android.bp +++ b/host/Android.bp @@ -135,7 +135,6 @@ cc_defaults { "channel_stream.cpp", "color_buffer.cpp", "frame_buffer.cpp", - "hwc2.cpp", "post_worker.cpp", "post_worker_gl.cpp", "read_buffer.cpp", diff --git a/host/BUILD.bazel b/host/BUILD.bazel index 5ab37ba5a..b10342144 100644 --- a/host/BUILD.bazel +++ b/host/BUILD.bazel @@ -67,15 +67,9 @@ cc_library( hdrs = [ "buffer.h", "color_buffer.h", - "compositor.h", "frame_buffer.h", - "framework_formats.h", - "handle.h", - "hwc2.h", "post_commands.h", "post_worker.h", - "readback_worker.h", - "stale_ptr_registry.h", "vsync_thread.h", ], copts = GFXSTREAM_HOST_COPTS, @@ -103,7 +97,6 @@ cc_library( "channel_stream.cpp", "color_buffer.cpp", "frame_buffer.cpp", - "hwc2.cpp", "post_worker.cpp", "post_worker_gl.cpp", "read_buffer.cpp", @@ -128,16 +121,11 @@ cc_library( "buffer.h", "channel_stream.h", "color_buffer.h", - "compositor.h", "frame_buffer.h", - "framework_formats.h", - "handle.h", - "hwc2.h", "post_commands.h", "post_worker.h", "post_worker_gl.h", "read_buffer.h", - "readback_worker.h", "render_channel_impl.h", "render_control.h", "render_lib_impl.h", @@ -146,7 +134,6 @@ cc_library( "render_window.h", "renderer_impl.h", "ring_stream.h", - "stale_ptr_registry.h", "sync_thread.h", "virtgpu_gfxstream_protocol.h", "virtio_gpu.h", diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index 3f45b638f..a708e16d0 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -83,7 +83,6 @@ set(stream-server-core-sources channel_stream.cpp color_buffer.cpp frame_buffer.cpp - hwc2.cpp post_worker.cpp post_worker_gl.cpp read_buffer.cpp diff --git a/host/buffer.h b/host/buffer.h index 59cf6b2c4..8dd9d9cb4 100644 --- a/host/buffer.h +++ b/host/buffer.h @@ -17,7 +17,7 @@ #include #include "gfxstream/host/external_object_manager.h" -#include "handle.h" +#include "gfxstream/host/handle.h" #include "render-utils/stream.h" #include "snapshot/LazySnapshotObj.h" diff --git a/host/color_buffer.h b/host/color_buffer.h index dd31b4078..e82f3e12b 100644 --- a/host/color_buffer.h +++ b/host/color_buffer.h @@ -22,12 +22,12 @@ #include #include -#include "framework_formats.h" #include "gfxstream/host/color_buffer_interface.h" #include "gfxstream/host/external_object_manager.h" +#include "gfxstream/host/framework_formats.h" #include "gfxstream/host/gfxstream_format.h" -#include "handle.h" -#include "hwc2.h" +#include "gfxstream/host/hwc2.h" +#include "gfxstream/host/handle.h" #include "render-utils/Renderer.h" #include "render-utils/stream.h" #include "snapshot/LazySnapshotObj.h" diff --git a/host/common/Android.bp b/host/common/Android.bp index 8437ba380..3bd200e1a 100644 --- a/host/common/Android.bp +++ b/host/common/Android.bp @@ -29,6 +29,7 @@ cc_library_static { "file_stream.cpp", "graphics_driver_lock.cpp", "guest_operations.cpp", + "hwc2.cpp", "mem_stream.cpp", "renderer_operations.cpp", "stream_utils.cpp", diff --git a/host/common/BUILD.bazel b/host/common/BUILD.bazel index 394d98978..ce5cbf80b 100644 --- a/host/common/BUILD.bazel +++ b/host/common/BUILD.bazel @@ -18,6 +18,7 @@ cc_library( "file_stream.cpp", "graphics_driver_lock.cpp", "guest_operations.cpp", + "hwc2.cpp", "mem_stream.cpp", "renderer_operations.cpp", "stream_utils.cpp", diff --git a/host/common/CMakeLists.txt b/host/common/CMakeLists.txt index e04ad8d1e..a0d448868 100644 --- a/host/common/CMakeLists.txt +++ b/host/common/CMakeLists.txt @@ -36,6 +36,7 @@ if (NOT TARGET gfxstream_host_common) file_stream.cpp graphics_driver_lock.cpp guest_operations.cpp + hwc2.cpp mem_stream.cpp renderer_operations.cpp stream_utils.cpp diff --git a/host/hwc2.cpp b/host/common/hwc2.cpp similarity index 86% rename from host/hwc2.cpp rename to host/common/hwc2.cpp index 12358f31e..411256dc7 100644 --- a/host/hwc2.cpp +++ b/host/common/hwc2.cpp @@ -12,13 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "hwc2.h" +#include "gfxstream/host/hwc2.h" namespace gfxstream { namespace host { -std::unique_ptr ToFlatComposeRequest( - const ComposeDevice* composeRequest) { +std::unique_ptr ToFlatComposeRequest(const ComposeDevice* composeRequest) { auto flatComposeRequest = std::make_unique(); flatComposeRequest->displayId = 0; flatComposeRequest->targetHandle = composeRequest->targetHandle; @@ -28,8 +27,7 @@ std::unique_ptr ToFlatComposeRequest( return flatComposeRequest; } -std::unique_ptr ToFlatComposeRequest( - const ComposeDevice_v2* composeRequest) { +std::unique_ptr ToFlatComposeRequest(const ComposeDevice_v2* composeRequest) { auto flatComposeRequest = std::make_unique(); flatComposeRequest->displayId = composeRequest->displayId; flatComposeRequest->targetHandle = composeRequest->targetHandle; diff --git a/host/compositor.h b/host/common/include/gfxstream/host/compositor.h similarity index 96% rename from host/compositor.h rename to host/common/include/gfxstream/host/compositor.h index e79bf9aa2..56d71295c 100644 --- a/host/compositor.h +++ b/host/common/include/gfxstream/host/compositor.h @@ -19,7 +19,7 @@ #include #include "gfxstream/host/color_buffer_interface.h" -#include "hwc2.h" +#include "gfxstream/host/hwc2.h" #include "render-utils/Renderer.h" namespace gfxstream { @@ -54,9 +54,7 @@ class Compositor { int screenWidth; int screenHeight; }; - std::optional getDisplayLayout() const { - return m_displayLayout; - } + std::optional getDisplayLayout() const { return m_displayLayout; } void setDisplayLayout(int screenWidth, int screenHeight, const Rect& displayRect) { if (displayRect.size.w > 0 && displayRect.size.h > 0) { DisplayLayout layout; diff --git a/host/framework_formats.h b/host/common/include/gfxstream/host/framework_formats.h similarity index 100% rename from host/framework_formats.h rename to host/common/include/gfxstream/host/framework_formats.h diff --git a/host/handle.h b/host/common/include/gfxstream/host/handle.h similarity index 100% rename from host/handle.h rename to host/common/include/gfxstream/host/handle.h diff --git a/host/hwc2.h b/host/common/include/gfxstream/host/hwc2.h similarity index 84% rename from host/hwc2.h rename to host/common/include/gfxstream/host/hwc2.h index 936832487..9c48fa1c6 100644 --- a/host/hwc2.h +++ b/host/common/include/gfxstream/host/hwc2.h @@ -1,23 +1,24 @@ /* -* Copyright (C) 2011-2015 The Android Open Source Project -* -* 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. -*/ + * Copyright (C) 2011-2015 The Android Open Source Project + * + * 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. + */ #ifndef _LIBRENDER_HWC2_H #define _LIBRENDER_HWC2_H -#include #include + +#include #include namespace gfxstream { diff --git a/host/readback_worker.h b/host/common/include/gfxstream/host/readback_worker.h similarity index 74% rename from host/readback_worker.h rename to host/common/include/gfxstream/host/readback_worker.h index 05c37eb99..c31572049 100644 --- a/host/readback_worker.h +++ b/host/common/include/gfxstream/host/readback_worker.h @@ -1,18 +1,18 @@ /* -* Copyright (C) 2017 The Android Open Source Project -* -* 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. -*/ + * Copyright (C) 2017 The Android Open Source Project + * + * 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. + */ #pragma once #include @@ -25,7 +25,7 @@ class IColorBuffer; // This class implements async readback of ColorBuffers on both the FrameBuffer // posting thread and a separate worker thread. class ReadbackWorker { - public: + public: virtual ~ReadbackWorker() = default; virtual void init() = 0; @@ -37,9 +37,9 @@ class ReadbackWorker { virtual void deinitReadbackForDisplay(uint32_t displayId) = 0; enum class DoNextReadbackResult { - OK_NOT_READY_FOR_READ, + OK_NOT_READY_FOR_READ, - OK_READY_FOR_READ, + OK_READY_FOR_READ, }; // doNextReadback(): Call this from the emugl FrameBuffer::post thread @@ -66,11 +66,11 @@ class ReadbackWorker { // This is usually called when there was no doNextReadback activity // for a few ms, to guarantee that end users see the final frame. enum class FlushResult { - FAIL, + FAIL, - OK_NOT_READY_FOR_READ, + OK_NOT_READY_FOR_READ, - OK_READY_FOR_READ, + OK_READY_FOR_READ, }; virtual FlushResult flushPipeline(uint32_t displayId) = 0; diff --git a/host/common/meson.build b/host/common/meson.build index 44cff945c..7b995e692 100644 --- a/host/common/meson.build +++ b/host/common/meson.build @@ -13,6 +13,7 @@ files_lib_host_common = files( 'file_stream.cpp', 'graphics_driver_lock.cpp', 'guest_operations.cpp', + 'hwc2.cpp', 'mem_stream.cpp', 'renderer_operations.cpp', 'stream_utils.cpp', diff --git a/host/frame_buffer.cpp b/host/frame_buffer.cpp index 8f441366e..6347b9d3b 100644 --- a/host/frame_buffer.cpp +++ b/host/frame_buffer.cpp @@ -45,6 +45,7 @@ #include "gfxstream/containers/Lookup.h" #include "gfxstream/host/display_operations.h" #include "gfxstream/host/guest_operations.h" +#include "gfxstream/host/hwc2.h" #include "gfxstream/host/native_sub_window.h" #include "gfxstream/host/renderer_operations.h" #include "gfxstream/host/stream_utils.h" @@ -55,7 +56,6 @@ #include "gfxstream/synchronization/Lock.h" #include "gfxstream/system/System.h" #include "host/gl/context_helper.h" -#include "hwc2.h" #include "render-utils/MediaNative.h" #include "render_thread_info.h" #include "sync_thread.h" diff --git a/host/frame_buffer.h b/host/frame_buffer.h index 8f890983b..5ae35413d 100644 --- a/host/frame_buffer.h +++ b/host/frame_buffer.h @@ -31,16 +31,16 @@ #include "buffer.h" #include "color_buffer.h" -#include "framework_formats.h" #include "gfxstream/AsyncResult.h" #include "gfxstream/EventNotificationSupport.h" #include "gfxstream/host/color_buffer_interface.h" #include "gfxstream/host/external_object_manager.h" +#include "gfxstream/host/framework_formats.h" #include "gfxstream/host/gfxstream_format.h" #include "gfxstream/host/gl_enums.h" #include "gfxstream/host/process_resources.h" #include "gfxstream/host/vk_enums.h" -#include "handle.h" +#include "gfxstream/host/handle.h" #include "post_commands.h" #include "render-utils/Renderer.h" #include "render-utils/render_api.h" diff --git a/host/gl/BUILD.bazel b/host/gl/BUILD.bazel index d2e7d5be0..a1dfc7523 100644 --- a/host/gl/BUILD.bazel +++ b/host/gl/BUILD.bazel @@ -47,6 +47,7 @@ cc_library( "pixel_read_formats.h", "readback_worker_gl.h", "render_thread_info_gl.h", + "stale_ptr_registry.h", "texture_draw.h", "texture_resize.h", "yuv_converter.h", diff --git a/host/gl/buffer_gl.h b/host/gl/buffer_gl.h index a4c4ab9fc..4ae64c7d6 100644 --- a/host/gl/buffer_gl.h +++ b/host/gl/buffer_gl.h @@ -22,7 +22,7 @@ #include #include "context_helper.h" -#include "handle.h" +#include "gfxstream/host/handle.h" #include "render-utils/stream.h" namespace gfxstream { diff --git a/host/gl/color_buffer_gl.h b/host/gl/color_buffer_gl.h index 802215864..937434b63 100644 --- a/host/gl/color_buffer_gl.h +++ b/host/gl/color_buffer_gl.h @@ -31,8 +31,8 @@ #include "gfxstream/ManagedDescriptor.h" #include "gfxstream/host/features.h" #include "gfxstream/host/gfxstream_format.h" -#include "handle.h" -#include "hwc2.h" +#include "gfxstream/host/hwc2.h" +#include "gfxstream/host/handle.h" #include "pixel_read_formats.h" #include "render-utils/Renderer.h" #include "render-utils/stream.h" diff --git a/host/gl/compositor_gl.h b/host/gl/compositor_gl.h index 8561c23a7..6a3a1b2be 100644 --- a/host/gl/compositor_gl.h +++ b/host/gl/compositor_gl.h @@ -14,14 +14,14 @@ #pragma once -#include - #include #include #include #include -#include "compositor.h" +#include + +#include "gfxstream/host/compositor.h" #include "gfxstream/host/display_surface_user.h" #include "texture_draw.h" diff --git a/host/gl/display_gl.h b/host/gl/display_gl.h index 739dfb4b4..c0afd1f9a 100644 --- a/host/gl/display_gl.h +++ b/host/gl/display_gl.h @@ -24,7 +24,7 @@ #include "gfxstream/host/color_buffer_interface.h" #include "gfxstream/host/display.h" -#include "hwc2.h" +#include "gfxstream/host/hwc2.h" #include "texture_draw.h" namespace gfxstream { diff --git a/host/gl/emulated_egl_context.h b/host/gl/emulated_egl_context.h index 238aad011..b1e74db68 100644 --- a/host/gl/emulated_egl_context.h +++ b/host/gl/emulated_egl_context.h @@ -22,7 +22,7 @@ #include #include -#include "handle.h" +#include "gfxstream/host/handle.h" #include "gfxstream/host/GLDecoderContextData.h" #include "gfxstream/host/gl_enums.h" #include "render-utils/stream.h" diff --git a/host/gl/emulated_egl_image.h b/host/gl/emulated_egl_image.h index 7fbb15e78..9119019b1 100644 --- a/host/gl/emulated_egl_image.h +++ b/host/gl/emulated_egl_image.h @@ -23,7 +23,7 @@ #include #include -#include "handle.h" +#include "gfxstream/host/handle.h" namespace gfxstream { namespace host { diff --git a/host/gl/emulated_egl_window_surface.h b/host/gl/emulated_egl_window_surface.h index 197bde013..54e8542ae 100644 --- a/host/gl/emulated_egl_window_surface.h +++ b/host/gl/emulated_egl_window_surface.h @@ -27,7 +27,7 @@ #include "gfxstream/host/color_buffer_interface.h" #include "gl/color_buffer_gl.h" #include "gl/emulated_egl_context.h" -#include "handle.h" +#include "gfxstream/host/handle.h" namespace gfxstream { namespace host { diff --git a/host/gl/emulation_gl.h b/host/gl/emulation_gl.h index 27af2c61b..c477ce435 100644 --- a/host/gl/emulation_gl.h +++ b/host/gl/emulation_gl.h @@ -30,7 +30,6 @@ #include "OpenGLESDispatch/GLESv2Dispatch.h" #include "buffer_gl.h" #include "color_buffer_gl.h" -#include "compositor.h" #include "compositor_gl.h" #include "context_helper.h" #include "display_gl.h" @@ -39,6 +38,7 @@ #include "emulated_egl_fence_sync.h" #include "emulated_egl_image.h" #include "emulated_egl_window_surface.h" +#include "gfxstream/host/compositor.h" #include "gfxstream/host/display.h" #include "gfxstream/host/display_surface.h" #include "gfxstream/host/features.h" diff --git a/host/gl/readback_worker_gl.h b/host/gl/readback_worker_gl.h index 46a139f5c..324a8b26a 100644 --- a/host/gl/readback_worker_gl.h +++ b/host/gl/readback_worker_gl.h @@ -15,17 +15,17 @@ */ #pragma once -#include -#include -#include - #include #include +#include +#include +#include + +#include "display_surface_gl.h" #include "gfxstream/Compiler.h" +#include "gfxstream/host/readback_worker.h" #include "gfxstream/synchronization/Lock.h" -#include "display_surface_gl.h" -#include "readback_worker.h" namespace gfxstream { namespace host { diff --git a/host/gl/render_thread_info_gl.h b/host/gl/render_thread_info_gl.h index c23dfc5e4..597ce7285 100644 --- a/host/gl/render_thread_info_gl.h +++ b/host/gl/render_thread_info_gl.h @@ -17,7 +17,7 @@ #include #include -#include "handle.h" +#include "gfxstream/host/handle.h" #include "stale_ptr_registry.h" #include "render-utils/stream.h" #include "gl/emulated_egl_context.h" diff --git a/host/stale_ptr_registry.h b/host/gl/stale_ptr_registry.h similarity index 100% rename from host/stale_ptr_registry.h rename to host/gl/stale_ptr_registry.h diff --git a/host/gl/texture_draw.h b/host/gl/texture_draw.h index 88e2f8f33..0be18a7f6 100644 --- a/host/gl/texture_draw.h +++ b/host/gl/texture_draw.h @@ -23,7 +23,7 @@ #include #include -#include "hwc2.h" +#include "gfxstream/host/hwc2.h" #include "gfxstream/synchronization/Lock.h" namespace gfxstream { diff --git a/host/meson.build b/host/meson.build index fb2fc960a..b9b3d9b04 100644 --- a/host/meson.build +++ b/host/meson.build @@ -62,7 +62,6 @@ files_lib_gfxstream_backend = files( 'channel_stream.cpp', 'color_buffer.cpp', 'frame_buffer.cpp', - 'hwc2.cpp', 'post_worker.cpp', 'read_buffer.cpp', 'render_api.cpp', diff --git a/host/post_commands.h b/host/post_commands.h index 505cbea72..8fb2d09a9 100644 --- a/host/post_commands.h +++ b/host/post_commands.h @@ -23,7 +23,7 @@ #include "gfxstream/host/display_operations.h" #include "gfxstream/host/gfxstream_format.h" -#include "handle.h" +#include "gfxstream/host/handle.h" #include "render-utils/Renderer.h" namespace gfxstream { diff --git a/host/post_worker.h b/host/post_worker.h index 1a343b0ec..f850ad217 100644 --- a/host/post_worker.h +++ b/host/post_worker.h @@ -21,12 +21,12 @@ #include #include -#include "compositor.h" #include "gfxstream/Compiler.h" #include "gfxstream/host/color_buffer_interface.h" +#include "gfxstream/host/compositor.h" #include "gfxstream/host/gfxstream_format.h" #include "gfxstream/host/global_state.h" -#include "hwc2.h" +#include "gfxstream/host/hwc2.h" #include "post_commands.h" namespace gfxstream { diff --git a/host/testlibs/support/include/gfxstream/host/testing/SampleApplication.h b/host/testlibs/support/include/gfxstream/host/testing/SampleApplication.h index 93d1a19c8..c833b8c7e 100644 --- a/host/testlibs/support/include/gfxstream/host/testing/SampleApplication.h +++ b/host/testlibs/support/include/gfxstream/host/testing/SampleApplication.h @@ -18,14 +18,14 @@ #include #include -#include "host/frame_buffer.h" -#include "host/hwc2.h" #include "OpenGLESDispatch/GLESv2Dispatch.h" -#include "host/render_thread_info.h" #include "gfxstream/Compiler.h" +#include "gfxstream/host/hwc2.h" #include "gfxstream/host/testing/OSWindow.h" +#include "host/frame_buffer.h" #include "host/gl/emulated_egl_context.h" #include "host/gl/emulated_egl_fence_sync.h" +#include "host/render_thread_info.h" namespace gfxstream { namespace host { diff --git a/host/virtio_gpu_frontend.cpp b/host/virtio_gpu_frontend.cpp index 0fbf39c58..3b5eaaf16 100644 --- a/host/virtio_gpu_frontend.cpp +++ b/host/virtio_gpu_frontend.cpp @@ -24,15 +24,15 @@ #include #endif // ifdef GFXSTREAM_BUILD_WITH_SNAPSHOT_FRONTEND_SUPPORT +#include + #include #include #include -#include - #include "frame_buffer.h" -#include "framework_formats.h" #include "gfxstream/host/address_space_operations.h" +#include "gfxstream/host/framework_formats.h" #include "vulkan/vk_common_operations.h" // TODO: remove after moving save/load interface to ops. #include "gfxstream/common/logging.h" diff --git a/host/vulkan/compositor_vk.h b/host/vulkan/compositor_vk.h index 4b9e28959..978371269 100644 --- a/host/vulkan/compositor_vk.h +++ b/host/vulkan/compositor_vk.h @@ -27,13 +27,13 @@ #include #include "color_buffer_vk.h" -#include "compositor.h" #include "debug_utils_helper.h" #include "gfxstream/LruCache.h" +#include "gfxstream/host/compositor.h" #include "gfxstream/host/gfxstream_format.h" +#include "gfxstream/host/hwc2.h" #include "gfxstream/synchronization/Lock.h" #include "goldfish_vk_dispatch.h" -#include "host/hwc2.h" #include "vulkan/vk_format_support.h" #include "vulkan/vk_utils.h" diff --git a/host/vulkan/display_vk.h b/host/vulkan/display_vk.h index 2988eaee8..3d0a6a5a1 100644 --- a/host/vulkan/display_vk.h +++ b/host/vulkan/display_vk.h @@ -28,9 +28,9 @@ #include "debug_utils_helper.h" #include "display_surface_vk.h" #include "gfxstream/host/display.h" +#include "gfxstream/host/hwc2.h" #include "gfxstream/synchronization/Lock.h" #include "goldfish_vk_dispatch.h" -#include "host/hwc2.h" #include "swap_chain_state_vk.h" // The DisplayVk class holds the Vulkan and other states required to draw a diff --git a/host/vulkan/vk_common_operations.h b/host/vulkan/vk_common_operations.h index 193271857..0d5e5a9d8 100644 --- a/host/vulkan/vk_common_operations.h +++ b/host/vulkan/vk_common_operations.h @@ -35,12 +35,12 @@ #include "gfxstream/host/RenderDoc.h" #include "gfxstream/host/external_object_manager.h" #include "gfxstream/host/features.h" +#include "gfxstream/host/framework_formats.h" #include "gfxstream/host/gfxstream_format.h" #include "gfxstream/host/global_state.h" #include "gfxstream/host/vk_enums.h" #include "gfxstream/memory/UdmabufCreator.h" #include "goldfish_vk_private_defs.h" -#include "host/framework_formats.h" #include "render-utils/Renderer.h" #include "vk_format_support.h" #include "vk_utils.h" diff --git a/host/vulkan/vk_decoder_internal_structs.h b/host/vulkan/vk_decoder_internal_structs.h index db1dce285..eaf252592 100644 --- a/host/vulkan/vk_decoder_internal_structs.h +++ b/host/vulkan/vk_decoder_internal_structs.h @@ -31,7 +31,7 @@ #include "debug_utils_helper.h" #include "device_op_tracker.h" -#include "handle.h" +#include "gfxstream/host/handle.h" #include "vk_emulated_physical_device_memory.h" #include "vk_emulated_physical_device_queue.h" #include "render-utils/stream.h" From 10115ea8e6246c44c30ca404ce36d5fd5587eb88 Mon Sep 17 00:00:00 2001 From: Jason Macnak Date: Fri, 24 Jul 2026 14:14:51 -0700 Subject: [PATCH 19/33] Remove host/gl dependency on host Bug: b/537737772 Test: bazel test //host/... Low-Coverage-Reason: REFACTOR_ONLY Change-Id: If7c468e2463a1e4b4167ba0edc9bc518d4830d00 --- host/gl/Android.bp | 4 ++-- host/gl/BUILD.bazel | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/host/gl/Android.bp b/host/gl/Android.bp index 1cd9d65f1..0bb04fae2 100644 --- a/host/gl/Android.bp +++ b/host/gl/Android.bp @@ -41,12 +41,13 @@ cc_library_static { "yuv_converter.cpp", ], header_libs: [ - "libgfxstream_thirdparty_opengl_headers", "libgfxstream_backend_headers", "libgfxstream_thirdparty_glm", + "libgfxstream_thirdparty_opengl_headers", ], static_libs: [ "libgfxstream_common_base", + "libgfxstream_common_logging", "libgfxstream_host_common", "libgfxstream_host_decoder_common", "libgfxstream_host_features", @@ -54,7 +55,6 @@ cc_library_static { "libgfxstream_host_gles2_dec", "libgfxstream_host_glestranslator_glcommon", "libgfxstream_host_glsnapshot", - "libgfxstream_common_logging", "libgfxstream_host_openglesdispatch", "libgfxstream_host_renderdoc", ], diff --git a/host/gl/BUILD.bazel b/host/gl/BUILD.bazel index a1dfc7523..ce8c2398c 100644 --- a/host/gl/BUILD.bazel +++ b/host/gl/BUILD.bazel @@ -65,7 +65,7 @@ cc_library( "//common/logging:gfxstream_common_logging", "//common/utils:gfxstream_common_utils", "//host:gfxstream_backend_headers", - "//host:gfxstream_host_headers", + #"//host:gfxstream_host_headers", "//host/common:gfxstream_host_common", "//host/decoder_common:gfxstream_host_decoder_common", "//host/features:gfxstream_host_features", From 3cbccdbf4fa1b549eff8abda23051c5a5373dbc7 Mon Sep 17 00:00:00 2001 From: Jason Macnak Date: Wed, 29 Jul 2026 07:32:59 -0700 Subject: [PATCH 20/33] Remove gfxstream_host_headers Bug: b/537737772 Test: bazel test //host/... Low-Coverage-Reason: REFACTOR_ONLY Change-Id: Ie2670b3a0c8fc09b730b637437aae188651ffa16 --- host/BUILD.bazel | 38 +---------------- .../include/gfxstream/host}/post_commands.h | 8 ++-- .../include/gfxstream/host}/post_worker.h | 1 - host/frame_buffer.h | 4 +- host/gl/BUILD.bazel | 1 - host/gl/color_buffer_gl.cpp | 2 +- host/gl/compositor_gl.cpp | 2 +- host/gl/emulated_egl_window_surface.h | 4 +- host/gl/glestranslator/egl/BUILD.bazel | 1 - host/gl/readback_worker_gl.cpp | 2 +- host/gl/render_thread_info_gl.cpp | 1 + host/gl/render_thread_info_gl.h | 10 ++--- host/post_worker.cpp | 4 +- host/post_worker_gl.h | 2 +- host/testlibs/support/BUILD.bazel | 1 - host/tests/BUILD.bazel | 1 - host/vulkan/BUILD.bazel | 4 -- host/vulkan/cereal/BUILD.bazel | 1 - host/vulkan/compositor_vk.cpp | 12 +++--- host/vulkan/compositor_vk.h | 4 +- host/vulkan/device_lost_helper.h | 2 +- host/vulkan/display_vk.cpp | 7 ++-- host/vulkan/emulated_textures/BUILD.bazel | 1 - .../vulkan/emulated_textures/astc_texture.cpp | 2 +- host/vulkan/emulated_textures/astc_texture.h | 5 ++- .../compressed_image_info.cpp | 8 ++-- .../emulated_textures/compressed_image_info.h | 7 ++-- .../gpu_decompression_pipeline.cpp | 8 ++-- host/vulkan/post_worker_vk.cpp | 4 +- host/vulkan/post_worker_vk.h | 4 +- host/vulkan/swap_chain_state_vk.cpp | 5 ++- host/vulkan/vk_decoder.cpp | 1 - host/vulkan/vk_decoder_global_state.cpp | 41 +++++++++---------- host/vulkan/vk_decoder_internal_structs.h | 16 ++++---- host/vulkan/vk_decoder_snapshot_utils.cpp | 4 +- host/vulkan/vk_decoder_snapshot_utils.h | 2 +- host/vulkan/vulkan_unittest.cpp | 11 +++-- 37 files changed, 92 insertions(+), 139 deletions(-) rename host/{ => common/include/gfxstream/host}/post_commands.h (90%) rename host/{ => common/include/gfxstream/host}/post_worker.h (99%) diff --git a/host/BUILD.bazel b/host/BUILD.bazel index b10342144..b3003916b 100644 --- a/host/BUILD.bazel +++ b/host/BUILD.bazel @@ -62,39 +62,13 @@ cc_library( ], ) -cc_library( - name = "gfxstream_host_headers", - hdrs = [ - "buffer.h", - "color_buffer.h", - "frame_buffer.h", - "post_commands.h", - "post_worker.h", - "vsync_thread.h", - ], - copts = GFXSTREAM_HOST_COPTS, - defines = GFXSTREAM_HOST_DEFINES, - includes = ["."], - deps = [ - ":gfxstream_backend_headers", - "//common/base:gfxstream_common_base", - "//common/logging:gfxstream_common_logging", - "//host/common:gfxstream_host_common", - "//host/features:gfxstream_host_features", - "//host/snapshot:gfxstream_host_snapshot", - "//third_party/opengl:gfxstream_egl_headers", - "//third_party/opengl:gfxstream_gles2_headers", - "//third_party/opengl:gfxstream_gles3_headers", - "//third_party/vulkan:gfxstream_vulkan_headers", - "//third_party/xcb", - ], -) - cc_library( name = "gfxstream_backend_static", srcs = [ "buffer.cpp", + "buffer.h", "channel_stream.cpp", + "channel_stream.h", "color_buffer.cpp", "frame_buffer.cpp", "post_worker.cpp", @@ -118,12 +92,8 @@ cc_library( "vsync_thread.cpp", ], hdrs = [ - "buffer.h", - "channel_stream.h", "color_buffer.h", "frame_buffer.h", - "post_commands.h", - "post_worker.h", "post_worker_gl.h", "read_buffer.h", "render_channel_impl.h", @@ -154,14 +124,12 @@ cc_library( defines = GFXSTREAM_HOST_DEFINES + ["QEMU_NEXT"], includes = [ ".", - "gl", ], linkstatic = True, visibility = ["//visibility:public"], deps = [ ":gfxstream_backend_cc_proto", ":gfxstream_backend_headers", - ":gfxstream_host_headers", "//common/base:gfxstream_common_base", "//common/logging:gfxstream_common_logging", "//host/address_space:gfxstream_host_address_space", @@ -213,7 +181,6 @@ cc_library( ":gfxstream_backend_cc_proto", ":gfxstream_backend_headers", ":gfxstream_backend_static", - ":gfxstream_host_headers", "//common/base:gfxstream_common_base", "//common/logging:gfxstream_common_logging", "//common/utils:gfxstream_common_utils", @@ -238,7 +205,6 @@ cc_binary( ":gfxstream_backend_cc_proto", ":gfxstream_backend_headers", ":gfxstream_backend_static", - ":gfxstream_host_headers", "//common/base:gfxstream_common_base", "//common/logging:gfxstream_common_logging", "//common/utils:gfxstream_common_utils", diff --git a/host/post_commands.h b/host/common/include/gfxstream/host/post_commands.h similarity index 90% rename from host/post_commands.h rename to host/common/include/gfxstream/host/post_commands.h index 8fb2d09a9..90caac749 100644 --- a/host/post_commands.h +++ b/host/common/include/gfxstream/host/post_commands.h @@ -21,6 +21,7 @@ #include #include +#include "gfxstream/host/color_buffer_interface.h" #include "gfxstream/host/display_operations.h" #include "gfxstream/host/gfxstream_format.h" #include "gfxstream/host/handle.h" @@ -29,8 +30,6 @@ namespace gfxstream { namespace host { -class IColorBuffer; - // Posting enum class PostCmd { Post = 0, @@ -49,8 +48,7 @@ struct Post { // The block task won't stop until continueSignal is ready. std::future continueSignal; }; - using CompletionCallback = - std::function waitForGpu)>; + using CompletionCallback = std::function waitForGpu)>; PostCmd cmd; int composeVersion; std::vector composeBuffer; @@ -59,7 +57,7 @@ struct Post { HandleType cbHandle = 0; std::optional> colorTransform; - //TODO: remove union here and separate into message structures + // TODO: remove union here and separate into message structures union { IColorBuffer* cb; struct { diff --git a/host/post_worker.h b/host/common/include/gfxstream/host/post_worker.h similarity index 99% rename from host/post_worker.h rename to host/common/include/gfxstream/host/post_worker.h index f850ad217..1127f6ec5 100644 --- a/host/post_worker.h +++ b/host/common/include/gfxstream/host/post_worker.h @@ -31,7 +31,6 @@ namespace gfxstream { namespace host { -struct RenderThreadInfo; class PostWorker { public: diff --git a/host/frame_buffer.h b/host/frame_buffer.h index 5ae35413d..9d0357417 100644 --- a/host/frame_buffer.h +++ b/host/frame_buffer.h @@ -38,10 +38,10 @@ #include "gfxstream/host/framework_formats.h" #include "gfxstream/host/gfxstream_format.h" #include "gfxstream/host/gl_enums.h" +#include "gfxstream/host/handle.h" +#include "gfxstream/host/post_commands.h" #include "gfxstream/host/process_resources.h" #include "gfxstream/host/vk_enums.h" -#include "gfxstream/host/handle.h" -#include "post_commands.h" #include "render-utils/Renderer.h" #include "render-utils/render_api.h" #include "render-utils/stream.h" diff --git a/host/gl/BUILD.bazel b/host/gl/BUILD.bazel index ce8c2398c..496cdf105 100644 --- a/host/gl/BUILD.bazel +++ b/host/gl/BUILD.bazel @@ -65,7 +65,6 @@ cc_library( "//common/logging:gfxstream_common_logging", "//common/utils:gfxstream_common_utils", "//host:gfxstream_backend_headers", - #"//host:gfxstream_host_headers", "//host/common:gfxstream_host_common", "//host/decoder_common:gfxstream_host_decoder_common", "//host/features:gfxstream_host_features", diff --git a/host/gl/color_buffer_gl.cpp b/host/gl/color_buffer_gl.cpp index 2f872f392..a7fa337aa 100644 --- a/host/gl/color_buffer_gl.cpp +++ b/host/gl/color_buffer_gl.cpp @@ -27,10 +27,10 @@ #include "common/gl_utils.h" #include "debug_gl.h" #include "gfxstream/host/renderer_operations.h" -#include "gl/yuv_converter.h" #include "render_thread_info_gl.h" #include "texture_draw.h" #include "texture_resize.h" +#include "yuv_converter.h" namespace gfxstream { namespace host { diff --git a/host/gl/compositor_gl.cpp b/host/gl/compositor_gl.cpp index 4a7172fff..ccf88159c 100644 --- a/host/gl/compositor_gl.cpp +++ b/host/gl/compositor_gl.cpp @@ -15,10 +15,10 @@ #include "compositor_gl.h" #include "OpenGLESDispatch/DispatchTables.h" +#include "color_buffer_gl.h" #include "debug_gl.h" #include "display_surface_gl.h" #include "gfxstream/common/logging.h" -#include "gl/color_buffer_gl.h" #include "texture_draw.h" namespace gfxstream { diff --git a/host/gl/emulated_egl_window_surface.h b/host/gl/emulated_egl_window_surface.h index 54e8542ae..40d0482cb 100644 --- a/host/gl/emulated_egl_window_surface.h +++ b/host/gl/emulated_egl_window_surface.h @@ -24,9 +24,9 @@ #include #include +#include "color_buffer_gl.h" +#include "emulated_egl_context.h" #include "gfxstream/host/color_buffer_interface.h" -#include "gl/color_buffer_gl.h" -#include "gl/emulated_egl_context.h" #include "gfxstream/host/handle.h" namespace gfxstream { diff --git a/host/gl/glestranslator/egl/BUILD.bazel b/host/gl/glestranslator/egl/BUILD.bazel index 25899ad36..7b759c68d 100644 --- a/host/gl/glestranslator/egl/BUILD.bazel +++ b/host/gl/glestranslator/egl/BUILD.bazel @@ -150,7 +150,6 @@ cc_library( "//common/logging:gfxstream_common_logging", "//common/utils:gfxstream_common_utils", "//host:gfxstream_backend_headers", - "//host:gfxstream_host_headers", "//host/common:gfxstream_host_common", "//host/decoder_common:gfxstream_host_decoder_common", "//host/gl/glestranslator/common:gfxstream_glestranslator_common", diff --git a/host/gl/readback_worker_gl.cpp b/host/gl/readback_worker_gl.cpp index 3711d4dd2..b219482e1 100644 --- a/host/gl/readback_worker_gl.cpp +++ b/host/gl/readback_worker_gl.cpp @@ -20,10 +20,10 @@ #include "OpenGLESDispatch/DispatchTables.h" #include "OpenGLESDispatch/EGLDispatch.h" #include "OpenGLESDispatch/GLESv2Dispatch.h" +#include "color_buffer_gl.h" #include "context_helper.h" #include "gfxstream/common/logging.h" #include "gfxstream/host/color_buffer_interface.h" -#include "gl/color_buffer_gl.h" namespace gfxstream { namespace host { diff --git a/host/gl/render_thread_info_gl.cpp b/host/gl/render_thread_info_gl.cpp index 41b25a5f6..6e81b7c83 100644 --- a/host/gl/render_thread_info_gl.cpp +++ b/host/gl/render_thread_info_gl.cpp @@ -19,6 +19,7 @@ #include "OpenGLESDispatch/EGLDispatch.h" #include "OpenGLESDispatch/GLESv1Dispatch.h" #include "OpenGLESDispatch/GLESv2Dispatch.h" +#include "emulation_gl.h" #include "gfxstream/containers/Lookup.h" #include "gfxstream/host/global_state.h" #include "gfxstream/host/stream_utils.h" diff --git a/host/gl/render_thread_info_gl.h b/host/gl/render_thread_info_gl.h index 597ce7285..8dc767f02 100644 --- a/host/gl/render_thread_info_gl.h +++ b/host/gl/render_thread_info_gl.h @@ -17,13 +17,13 @@ #include #include +#include "emulated_egl_context.h" +#include "emulated_egl_window_surface.h" #include "gfxstream/host/handle.h" -#include "stale_ptr_registry.h" +#include "gles1_dec/gles_v1_decoder.h" +#include "gles2_dec/gles_v2_decoder.h" #include "render-utils/stream.h" -#include "gl/emulated_egl_context.h" -#include "gl/emulated_egl_window_surface.h" -#include "gl/gles1_dec/gles_v1_decoder.h" -#include "gl/gles2_dec/gles_v2_decoder.h" +#include "stale_ptr_registry.h" namespace gfxstream { namespace host { diff --git a/host/post_worker.cpp b/host/post_worker.cpp index dce82e934..14d5740a4 100644 --- a/host/post_worker.cpp +++ b/host/post_worker.cpp @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "post_worker.h" +#include "gfxstream/host/post_worker.h" #include @@ -24,8 +24,6 @@ #include "gfxstream/host/color_buffer_interface.h" #include "gfxstream/host/global_state.h" #include "gfxstream/host/window_operations.h" -#include "render_thread_info.h" -#include "vulkan/vk_common_operations.h" namespace gfxstream { namespace host { diff --git a/host/post_worker_gl.h b/host/post_worker_gl.h index 86a778c2f..c1ac19109 100644 --- a/host/post_worker_gl.h +++ b/host/post_worker_gl.h @@ -21,7 +21,7 @@ #include "gfxstream/host/color_buffer_interface.h" #include "gfxstream/host/display_surface_user.h" #include "gfxstream/host/global_state.h" -#include "post_worker.h" +#include "gfxstream/host/post_worker.h" #include "host/gl/display_gl.h" #include "host/gl/emulation_gl.h" diff --git a/host/testlibs/support/BUILD.bazel b/host/testlibs/support/BUILD.bazel index 7ad310cc5..59e1b03c7 100644 --- a/host/testlibs/support/BUILD.bazel +++ b/host/testlibs/support/BUILD.bazel @@ -41,7 +41,6 @@ cc_library( "//common/base:gfxstream_common_base", "//host:gfxstream_backend_headers", "//host:gfxstream_backend_static", - "//host:gfxstream_host_headers", "//host/common:gfxstream_host_common", "//host/decoder_common:gfxstream_host_decoder_common", "//host/features:gfxstream_host_features", diff --git a/host/tests/BUILD.bazel b/host/tests/BUILD.bazel index 283b43f14..acac2cb92 100644 --- a/host/tests/BUILD.bazel +++ b/host/tests/BUILD.bazel @@ -40,7 +40,6 @@ cc_test( ], deps = [ "//host:gfxstream_backend_static", - "//host:gfxstream_host_headers", "//host/decoder_common:gfxstream_host_decoder_common", "//host/testlibs/oswindow:gfxstream_oswindow_test_support", "//host/testlibs/support:gfxstream_host_testing_support", diff --git a/host/vulkan/BUILD.bazel b/host/vulkan/BUILD.bazel index 014b502bd..81835f357 100644 --- a/host/vulkan/BUILD.bazel +++ b/host/vulkan/BUILD.bazel @@ -156,7 +156,6 @@ cc_library( "//common/logging:gfxstream_common_logging", "//common/utils:gfxstream_common_utils", "//host:gfxstream_backend_headers", - "//host:gfxstream_host_headers", "//host/common:gfxstream_host_common", "//host/compressed_textures:gfxstream_host_compressed_textures", "//host/decoder_common:gfxstream_host_decoder_common", @@ -235,7 +234,6 @@ cc_test( deps = [ ":gfxstream_vulkan_server", "//common/base:gfxstream_common_base", - "//host:gfxstream_host_headers", "//host/testlibs/oswindow:gfxstream_oswindow_test_support", "//host/testlibs/support:gfxstream_host_testing_support", "@com_google_googletest//:gtest", @@ -284,7 +282,6 @@ cc_test( deps = [ ":gfxstream_vulkan_server", "//common/base:gfxstream_common_base", - "//host:gfxstream_host_headers", "//host/features:gfxstream_host_features", "//host/testlibs/support:gfxstream_host_testing_support", "@com_google_googletest//:gtest", @@ -301,7 +298,6 @@ cc_test( deps = [ ":gfxstream_vulkan_server", "//common/base:gfxstream_common_base", - "//host:gfxstream_host_headers", "//host/features:gfxstream_host_features", "//host/testlibs/support:gfxstream_host_testing_support", "//third_party/vulkan:gfxstream_vulkan_headers", diff --git a/host/vulkan/cereal/BUILD.bazel b/host/vulkan/cereal/BUILD.bazel index 3ec615d28..c932112a7 100644 --- a/host/vulkan/cereal/BUILD.bazel +++ b/host/vulkan/cereal/BUILD.bazel @@ -54,7 +54,6 @@ cc_library( deps = [ "//common/base:gfxstream_common_base", "//common/logging:gfxstream_common_logging", - "//host:gfxstream_host_headers", "//host/common:gfxstream_host_common", "//host/features:gfxstream_host_features", "//host/tracing:gfxstream_host_tracing", diff --git a/host/vulkan/compositor_vk.cpp b/host/vulkan/compositor_vk.cpp index 54a3fd741..01d82d025 100644 --- a/host/vulkan/compositor_vk.cpp +++ b/host/vulkan/compositor_vk.cpp @@ -15,19 +15,19 @@ #include "compositor_vk.h" #include +#include #include #include #include +#include "color_buffer_vk.h" +#include "compositor_fragment_shader.h" +#include "compositor_vertex_shader.h" #include "gfxstream/common/logging.h" #include "gfxstream/host/tracing.h" -#include "vulkan/color_buffer_vk.h" -#include "vulkan/compositor_fragment_shader.h" -#include "vulkan/compositor_vertex_shader.h" -#include "vulkan/vk_enum_string_helper.h" -#include "vulkan/vk_format_utils.h" -#include "vulkan/vk_utils.h" +#include "vk_format_utils.h" +#include "vk_utils.h" namespace gfxstream { namespace host { diff --git a/host/vulkan/compositor_vk.h b/host/vulkan/compositor_vk.h index 978371269..295116d89 100644 --- a/host/vulkan/compositor_vk.h +++ b/host/vulkan/compositor_vk.h @@ -34,8 +34,8 @@ #include "gfxstream/host/hwc2.h" #include "gfxstream/synchronization/Lock.h" #include "goldfish_vk_dispatch.h" -#include "vulkan/vk_format_support.h" -#include "vulkan/vk_utils.h" +#include "vk_format_support.h" +#include "vk_utils.h" namespace gfxstream { namespace host { diff --git a/host/vulkan/device_lost_helper.h b/host/vulkan/device_lost_helper.h index f282f532f..d21188943 100644 --- a/host/vulkan/device_lost_helper.h +++ b/host/vulkan/device_lost_helper.h @@ -22,8 +22,8 @@ #include #include +#include "common/goldfish_vk_dispatch.h" #include "gfxstream/ThreadAnnotations.h" -#include "vulkan/cereal/common/goldfish_vk_dispatch.h" namespace gfxstream { namespace host { diff --git a/host/vulkan/display_vk.cpp b/host/vulkan/display_vk.cpp index a99eaf3b3..c964d525b 100644 --- a/host/vulkan/display_vk.cpp +++ b/host/vulkan/display_vk.cpp @@ -14,17 +14,18 @@ #include "display_vk.h" +#include + #include #include #include #include +#include "color_buffer_vk.h" #include "gfxstream/common/logging.h" #include "gfxstream/host/display_operations.h" #include "gfxstream/system/System.h" -#include "vulkan/color_buffer_vk.h" -#include "vulkan/vk_enum_string_helper.h" -#include "vulkan/vk_format_utils.h" +#include "vk_format_utils.h" namespace gfxstream { namespace host { diff --git a/host/vulkan/emulated_textures/BUILD.bazel b/host/vulkan/emulated_textures/BUILD.bazel index 69a449fc1..63eb6ae4d 100644 --- a/host/vulkan/emulated_textures/BUILD.bazel +++ b/host/vulkan/emulated_textures/BUILD.bazel @@ -28,7 +28,6 @@ cc_library( deps = [ "//common/base:gfxstream_common_base", "//common/logging:gfxstream_common_logging", - "//host:gfxstream_host_headers", "//host/compressed_textures:gfxstream_host_compressed_textures", "//host/vulkan:gfxstream_vulkan_server_headers", "//host/vulkan/cereal:gfxstream_vulkan_cereal", diff --git a/host/vulkan/emulated_textures/astc_texture.cpp b/host/vulkan/emulated_textures/astc_texture.cpp index 70d0d0f27..41bbbf47a 100644 --- a/host/vulkan/emulated_textures/astc_texture.cpp +++ b/host/vulkan/emulated_textures/astc_texture.cpp @@ -21,7 +21,7 @@ #include #include "gfxstream/common/logging.h" -#include "vulkan/vk_utils.h" +#include "vk_utils.h" namespace gfxstream { namespace host { diff --git a/host/vulkan/emulated_textures/astc_texture.h b/host/vulkan/emulated_textures/astc_texture.h index 04ca46a20..18f6d136a 100644 --- a/host/vulkan/emulated_textures/astc_texture.h +++ b/host/vulkan/emulated_textures/astc_texture.h @@ -13,10 +13,11 @@ // limitations under the License. #pragma once +#include + #include "gfxstream/host/astc_cpu_decompressor.h" -#include "vulkan/vk_decoder_context.h" #include "goldfish_vk_dispatch.h" -#include "vulkan/vulkan.h" +#include "vk_decoder_context.h" namespace gfxstream { namespace host { diff --git a/host/vulkan/emulated_textures/compressed_image_info.cpp b/host/vulkan/emulated_textures/compressed_image_info.cpp index cd0913078..add9dd740 100644 --- a/host/vulkan/emulated_textures/compressed_image_info.cpp +++ b/host/vulkan/emulated_textures/compressed_image_info.cpp @@ -14,12 +14,12 @@ #include "compressed_image_info.h" +#include + +#include "emulated_textures/shaders/decompression_shaders.h" #include "gfxstream/ArraySize.h" #include "gfxstream/common/logging.h" -#include "vulkan/vk_format_utils.h" -#include "vulkan/emulated_textures/shaders/decompression_shaders.h" -#include "vulkan/vk_format_utils.h" -#include "vulkan/vk_enum_string_helper.h" +#include "vk_format_utils.h" namespace gfxstream { namespace host { diff --git a/host/vulkan/emulated_textures/compressed_image_info.h b/host/vulkan/emulated_textures/compressed_image_info.h index 4536fdb26..9db6cab36 100644 --- a/host/vulkan/emulated_textures/compressed_image_info.h +++ b/host/vulkan/emulated_textures/compressed_image_info.h @@ -14,15 +14,16 @@ #pragma once +#include + #include #include #include #include -#include "vulkan/emulated_textures/astc_texture.h" -#include "vulkan/emulated_textures/gpu_decompression_pipeline.h" +#include "emulated_textures/astc_texture.h" +#include "emulated_textures/gpu_decompression_pipeline.h" #include "goldfish_vk_dispatch.h" -#include "vulkan/vulkan.h" namespace gfxstream { namespace host { diff --git a/host/vulkan/emulated_textures/gpu_decompression_pipeline.cpp b/host/vulkan/emulated_textures/gpu_decompression_pipeline.cpp index dffd26ce6..e5e426e0a 100644 --- a/host/vulkan/emulated_textures/gpu_decompression_pipeline.cpp +++ b/host/vulkan/emulated_textures/gpu_decompression_pipeline.cpp @@ -14,15 +14,15 @@ #include "gpu_decompression_pipeline.h" +#include + +#include "emulated_textures/shaders/decompression_shaders.h" #include "gfxstream/common/logging.h" -#include "vulkan/vk_format_utils.h" -#include "vulkan/emulated_textures/shaders/decompression_shaders.h" -#include "vulkan/vk_enum_string_helper.h" +#include "vk_format_utils.h" namespace gfxstream { namespace host { namespace vk { - namespace { // Which GPU decoder we use for ASTC textures. diff --git a/host/vulkan/post_worker_vk.cpp b/host/vulkan/post_worker_vk.cpp index 50b37e6ba..4cd71d147 100644 --- a/host/vulkan/post_worker_vk.cpp +++ b/host/vulkan/post_worker_vk.cpp @@ -15,13 +15,13 @@ */ #include "post_worker_vk.h" +#include "color_buffer_vk.h" +#include "display_vk.h" #include "gfxstream/common/logging.h" #include "gfxstream/host/display_operations.h" #include "gfxstream/host/global_state.h" #include "gfxstream/host/renderer_operations.h" #include "gfxstream/host/window_operations.h" -#include "vulkan/color_buffer_vk.h" -#include "vulkan/display_vk.h" namespace gfxstream { namespace host { diff --git a/host/vulkan/post_worker_vk.h b/host/vulkan/post_worker_vk.h index e9ca11457..8a8c7f6de 100644 --- a/host/vulkan/post_worker_vk.h +++ b/host/vulkan/post_worker_vk.h @@ -16,11 +16,11 @@ #pragma once #include -#include #include +#include #include "gfxstream/host/display_surface_user.h" -#include "host/post_worker.h" +#include "gfxstream/host/post_worker.h" namespace gfxstream { namespace host { diff --git a/host/vulkan/swap_chain_state_vk.cpp b/host/vulkan/swap_chain_state_vk.cpp index ac7592e6c..897d6e678 100644 --- a/host/vulkan/swap_chain_state_vk.cpp +++ b/host/vulkan/swap_chain_state_vk.cpp @@ -14,12 +14,13 @@ #include "swap_chain_state_vk.h" +#include + #include #include #include "gfxstream/common/logging.h" -#include "vulkan/vk_enum_string_helper.h" -#include "vulkan/vk_utils.h" +#include "vk_utils.h" namespace gfxstream { namespace host { diff --git a/host/vulkan/vk_decoder.cpp b/host/vulkan/vk_decoder.cpp index 3174d3256..9728139e8 100644 --- a/host/vulkan/vk_decoder.cpp +++ b/host/vulkan/vk_decoder.cpp @@ -38,7 +38,6 @@ #include "common/goldfish_vk_marshaling.h" #include "common/goldfish_vk_reserved_marshaling.h" #include "common/goldfish_vk_transform.h" -#include "frame_buffer.h" #include "gfxstream/BumpPool.h" #include "gfxstream/common/logging.h" #include "gfxstream/host/iostream.h" diff --git a/host/vulkan/vk_decoder_global_state.cpp b/host/vulkan/vk_decoder_global_state.cpp index e4a1d9ab9..68a519714 100644 --- a/host/vulkan/vk_decoder_global_state.cpp +++ b/host/vulkan/vk_decoder_global_state.cpp @@ -13,15 +13,6 @@ // limitations under the License. #include "vk_decoder_global_state.h" -#include -#include -#include -#include -#include -#include -#include -#include - #ifndef _WIN32 #include #endif @@ -35,43 +26,51 @@ #include // for MoltenVK portability extensions #endif +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + #include "common/goldfish_vk_deepcopy.h" #include "common/goldfish_vk_dispatch.h" #include "common/goldfish_vk_marshaling.h" #include "common/goldfish_vk_reserved_marshaling.h" +#include "emulated_textures/astc_texture.h" +#include "emulated_textures/compressed_image_info.h" +#include "emulated_textures/gpu_decompression_pipeline.h" +#include "gfxstream/Macros.h" #include "gfxstream/common/logging.h" #include "gfxstream/containers/Lookup.h" +#include "gfxstream/host/RenderDoc.h" #include "gfxstream/host/address_space_operations.h" #include "gfxstream/host/astc_cpu_decompressor.h" #include "gfxstream/host/graphics_driver_lock.h" -#include "gfxstream/host/RenderDoc.h" #include "gfxstream/host/tracing.h" #include "gfxstream/host/vm_operations.h" -#include "gfxstream/Macros.h" #include "gfxstream/strings.h" -#include "host/frame_buffer.h" -#include "render_thread_info_vk.h" #include "render-utils/stream.h" +#include "render_thread_info_vk.h" #include "trivial_stream.h" #include "vk_android_native_buffer_operations.h" #include "vk_common_operations.h" #include "vk_decoder_context.h" #include "vk_decoder_internal_structs.h" -#include "vk_decoder_snapshot_utils.h" #include "vk_decoder_snapshot.h" +#include "vk_decoder_snapshot_utils.h" #include "vk_emulated_physical_device_memory.h" #include "vk_emulated_physical_device_queue.h" +#include "vk_format_utils.h" #include "vk_utils.h" #include "vulkan_boxed_handles.h" #include "vulkan_dispatch.h" #include "vulkan_stream.h" -#include "vulkan/emulated_textures/astc_texture.h" -#include "vulkan/emulated_textures/compressed_image_info.h" -#include "vulkan/emulated_textures/gpu_decompression_pipeline.h" -#include "vulkan/vk_enum_string_helper.h" -#include "vulkan/vk_format_utils.h" -#include "vulkan/vulkan_core.h" - // Verbose logging only when ANDROID_EMU_VK_LOG_CALLS is set #define LOG_CALLS_VERBOSE(fmt, ...) \ diff --git a/host/vulkan/vk_decoder_internal_structs.h b/host/vulkan/vk_decoder_internal_structs.h index eaf252592..42ef4a79b 100644 --- a/host/vulkan/vk_decoder_internal_structs.h +++ b/host/vulkan/vk_decoder_internal_structs.h @@ -29,20 +29,20 @@ #include #include +#include "common/goldfish_vk_deepcopy.h" #include "debug_utils_helper.h" #include "device_op_tracker.h" -#include "gfxstream/host/handle.h" -#include "vk_emulated_physical_device_memory.h" -#include "vk_emulated_physical_device_queue.h" -#include "render-utils/stream.h" +#include "emulated_textures/compressed_image_info.h" #include "gfxstream/common/logging.h" +#include "gfxstream/host/handle.h" #include "gfxstream/memory/SharedMemory.h" #include "gfxstream/synchronization/ConditionVariable.h" #include "gfxstream/synchronization/Lock.h" -#include "common/goldfish_vk_deepcopy.h" -#include "vulkan/vk_android_native_buffer_operations.h" -#include "vulkan/vk_format_utils.h" -#include "vulkan/emulated_textures/compressed_image_info.h" +#include "render-utils/stream.h" +#include "vk_android_native_buffer_operations.h" +#include "vk_emulated_physical_device_memory.h" +#include "vk_emulated_physical_device_queue.h" +#include "vk_format_utils.h" namespace gfxstream { namespace host { diff --git a/host/vulkan/vk_decoder_snapshot_utils.cpp b/host/vulkan/vk_decoder_snapshot_utils.cpp index 9be1e10c4..675c016cd 100644 --- a/host/vulkan/vk_decoder_snapshot_utils.cpp +++ b/host/vulkan/vk_decoder_snapshot_utils.cpp @@ -12,12 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "vulkan/vk_decoder_snapshot_utils.h" +#include "vk_decoder_snapshot_utils.h" +#include "gfxstream/common/logging.h" #include "vk_common_operations.h" #include "vk_utils.h" #include "vulkan_boxed_handles.h" -#include "gfxstream/common/logging.h" namespace gfxstream { namespace host { diff --git a/host/vulkan/vk_decoder_snapshot_utils.h b/host/vulkan/vk_decoder_snapshot_utils.h index 4f5504783..7c34d9ecf 100644 --- a/host/vulkan/vk_decoder_snapshot_utils.h +++ b/host/vulkan/vk_decoder_snapshot_utils.h @@ -14,7 +14,7 @@ #pragma once -#include "vulkan/vk_decoder_internal_structs.h" +#include "vk_decoder_internal_structs.h" namespace gfxstream { namespace host { diff --git a/host/vulkan/vulkan_unittest.cpp b/host/vulkan/vulkan_unittest.cpp index 18e6b0f0c..b153ee307 100644 --- a/host/vulkan/vulkan_unittest.cpp +++ b/host/vulkan/vulkan_unittest.cpp @@ -14,19 +14,18 @@ #include +#include + #include #include -#include - -#include "frame_buffer.h" #include "OpenGLESDispatch/OpenGLDispatchLoader.h" -#include "vk_common_operations.h" -#include "vulkan_dispatch.h" #include "gfxstream/ArraySize.h" #include "gfxstream/files/PathUtils.h" -#include "gfxstream/system/System.h" #include "gfxstream/host/testing/VkTestUtils.h" +#include "gfxstream/system/System.h" +#include "vk_common_operations.h" +#include "vulkan_dispatch.h" #ifdef _WIN32 #include From e33680dafc11e452ad30e7491a5e50ea9c295c77 Mon Sep 17 00:00:00 2001 From: Jason Macnak Date: Tue, 28 Jul 2026 11:25:19 -0700 Subject: [PATCH 21/33] Move GL handling to the GL server ... and out of FrameBuffer. Bug: b/537737772 Test: bazel test //host/... Low-Coverage-Reason: REFACTOR_ONLY Change-Id: I85b99b352df082daa8a7d7728c15346bb900520e --- host/BUILD.bazel | 1 + host/color_buffer.cpp | 199 +-- host/color_buffer.h | 24 +- .../gfxstream/host/color_buffer_interface.h | 1 + .../include/gfxstream/host/global_state.h | 10 +- .../include/gfxstream/host/readback_worker.h | 2 + host/frame_buffer.cpp | 1173 ++++------------- host/frame_buffer.h | 12 +- host/frame_buffer_unittest.cpp | 4 +- host/gl/emulation_gl.cpp | 869 +++++++++++- host/gl/emulation_gl.h | 218 ++- host/gl/readback_worker_gl.cpp | 17 + host/gl/readback_worker_gl.h | 2 + host/gl/render_thread_info_gl.cpp | 22 +- host/gl/render_thread_info_gl.h | 5 +- host/render_lib_impl.cpp | 4 +- host/render_thread.cpp | 2 +- host/render_thread_info.cpp | 6 +- host/render_thread_info.h | 2 +- host/testlibs/support/SampleApplication.cpp | 2 +- 20 files changed, 1344 insertions(+), 1231 deletions(-) diff --git a/host/BUILD.bazel b/host/BUILD.bazel index b3003916b..5dc4ba160 100644 --- a/host/BUILD.bazel +++ b/host/BUILD.bazel @@ -70,6 +70,7 @@ cc_library( "channel_stream.cpp", "channel_stream.h", "color_buffer.cpp", + "color_buffer.h", "frame_buffer.cpp", "post_worker.cpp", "post_worker_gl.cpp", diff --git a/host/color_buffer.cpp b/host/color_buffer.cpp index 0729035a9..ac927f93f 100644 --- a/host/color_buffer.cpp +++ b/host/color_buffer.cpp @@ -78,6 +78,7 @@ class ColorBuffer::Impl : public LazySnapshotObj { bool invalidateForGl(); bool invalidateForVk(); bool invalidateForBackend(Backend backend); + bool flushFromBackend(Backend backend); bool importHandle(void* handle, bool preserveContent); std::optional exportBlob(); @@ -92,25 +93,6 @@ class ColorBuffer::Impl : public LazySnapshotObj { vk::ColorBufferVk* getColorBufferVk() const { return mColorBufferVk.get(); } -#if GFXSTREAM_ENABLE_HOST_GLES - bool canUseGlOps(); - bool glOpBlitFromCurrentReadBuffer(); - bool glOpBindToTexture(); - bool glOpBindToTexture2(); - bool glOpBindToRenderbuffer(); - bool glOpReadback(unsigned char* img, bool readbackBgra); - bool glOpReadbackAsync(GLuint buffer, bool readbackBgra); - bool glOpImportEglNativePixmap(void* pixmap, bool preserveContent); - bool glOpSwapYuvTexturesAndUpdate(GLenum format, GLenum type, GfxstreamFormat texturesFormat, - GLuint* textures); - bool glOpIsFastBlitSupported() const; - bool glOpPostLayer(const ComposeLayer& l, int frameWidth, int frameHeight, - const std::optional>& colorTransform); - bool glOpPostViewportScaledWithOverlay( - float rotation, float dx, float dy, float scaleX, float scaleY, - const std::optional>& colorTransform); -#endif - private: Impl(HandleType, uint32_t width, uint32_t height, GfxstreamFormat format); @@ -351,6 +333,10 @@ bool ColorBuffer::Impl::invalidateForBackend(Backend backend) { return backend == Backend::VK ? invalidateForVk() : invalidateForGl(); } +bool ColorBuffer::Impl::flushFromBackend(Backend backend) { + return backend == Backend::VK ? flushFromVk() : flushFromGl(); +} + bool ColorBuffer::Impl::importHandle(void* handle, bool preserveContent) { #if GFXSTREAM_ENABLE_HOST_GLES if (mColorBufferGl) { @@ -475,133 +461,6 @@ std::optional ColorBuffer::Impl::exportBlob() { return mColorBufferVk->exportBlob(); } -#if GFXSTREAM_ENABLE_HOST_GLES -bool ColorBuffer::Impl::canUseGlOps() { return (mColorBufferGl != nullptr); } - -bool ColorBuffer::Impl::glOpBlitFromCurrentReadBuffer() { - if (!mColorBufferGl) { - GFXSTREAM_ERROR("%s: ColorBufferGl not available", __func__); - return false; - } - - touch(); - - return mColorBufferGl->blitFromCurrentReadBuffer(); -} - -bool ColorBuffer::Impl::glOpBindToTexture() { - if (!mColorBufferGl) { - GFXSTREAM_ERROR("%s: ColorBufferGl not available", __func__); - return false; - } - - touch(); - - return mColorBufferGl->bindToTexture(); -} - -bool ColorBuffer::Impl::glOpBindToTexture2() { - if (!mColorBufferGl) { - GFXSTREAM_ERROR("%s: ColorBufferGl not available", __func__); - return false; - } - - return mColorBufferGl->bindToTexture2(); -} - -bool ColorBuffer::Impl::glOpBindToRenderbuffer() { - if (!mColorBufferGl) { - GFXSTREAM_ERROR("%s: ColorBufferGl not available", __func__); - return false; - } - - touch(); - - return mColorBufferGl->bindToRenderbuffer(); -} - -bool ColorBuffer::Impl::glOpReadback(unsigned char* img, bool readbackBgra) { - if (!mColorBufferGl) { - GFXSTREAM_ERROR("%s: ColorBufferGl not available", __func__); - return false; - } - - touch(); - - return mColorBufferGl->readback(img, readbackBgra); -} - -bool ColorBuffer::Impl::glOpReadbackAsync(GLuint buffer, bool readbackBgra) { - if (!mColorBufferGl) { - GFXSTREAM_ERROR("%s: ColorBufferGl not available", __func__); - return false; - } - - touch(); - - return mColorBufferGl->readbackAsync(buffer, readbackBgra); -} - -bool ColorBuffer::Impl::glOpImportEglNativePixmap(void* pixmap, bool preserveContent) { - if (!mColorBufferGl) { - GFXSTREAM_ERROR("%s: ColorBufferGl not available", __func__); - return false; - } - - return mColorBufferGl->importEglNativePixmap(pixmap, preserveContent); -} - -bool ColorBuffer::Impl::glOpSwapYuvTexturesAndUpdate(GLenum format, GLenum type, - GfxstreamFormat texturesFormat, - GLuint* textures) { - if (!mColorBufferGl) { - GFXSTREAM_ERROR("%s: ColorBufferGl not available", __func__); - return false; - } - - mColorBufferGl->swapYUVTextures(texturesFormat, textures); - - // This makes ColorBufferGl regenerate the RGBA texture using - // YUVConverter::drawConvert() with the updated YUV textures. - mColorBufferGl->subUpdate(0, 0, mWidth, mHeight, texturesFormat, /*pixels=*/nullptr); - - flushFromGl(); - return true; -} - -bool ColorBuffer::Impl::glOpIsFastBlitSupported() const { - if (!mColorBufferGl) { - GFXSTREAM_ERROR("%s: ColorBufferGl not available", __func__); - return false; - } - - return mColorBufferGl->isFastBlitSupported(); -} - -bool ColorBuffer::Impl::glOpPostLayer(const ComposeLayer& l, int frameWidth, int frameHeight, - const std::optional>& colorTransform) { - if (!mColorBufferGl) { - GFXSTREAM_ERROR("%s: ColorBufferGl not available", __func__); - return false; - } - - mColorBufferGl->postLayer(l, frameWidth, frameHeight, colorTransform); - return true; -} - -bool ColorBuffer::Impl::glOpPostViewportScaledWithOverlay( - float rotation, float dx, float dy, float scaleX, float scaleY, - const std::optional>& colorTransform) { - if (!mColorBufferGl) { - GFXSTREAM_ERROR("%s: ColorBufferGl not available", __func__); - return false; - } - - mColorBufferGl->postViewportScaledWithOverlay(rotation, dx, dy, scaleX, scaleY, colorTransform); - return true; -} -#endif - //////////////////////////////////////////////////////////////////////////////////////////////// /*static*/ @@ -683,6 +542,10 @@ bool ColorBuffer::invalidateForBackend(Backend backend) { return mImpl->invalidateForBackend(backend); } +bool ColorBuffer::flushFromBackend(Backend backend) { + return mImpl->flushFromBackend(backend); +} + bool ColorBuffer::importHandle(void* handle, bool preserveContent) { return mImpl->importHandle(handle, preserveContent); } @@ -697,49 +560,5 @@ bool ColorBuffer::flushFromVkBytes(const void* bytes, size_t bytesSize) { std::optional ColorBuffer::exportBlob() { return mImpl->exportBlob(); } -#if GFXSTREAM_ENABLE_HOST_GLES -bool ColorBuffer::canUseGlOps() { return mImpl->canUseGlOps(); } - -bool ColorBuffer::glOpBlitFromCurrentReadBuffer() { return mImpl->glOpBlitFromCurrentReadBuffer(); } - -bool ColorBuffer::glOpBindToTexture() { return mImpl->glOpBindToTexture(); } - -bool ColorBuffer::glOpBindToTexture2() { return mImpl->glOpBindToTexture2(); } - -bool ColorBuffer::glOpBindToRenderbuffer() { return mImpl->glOpBindToRenderbuffer(); } - -bool ColorBuffer::glOpReadback(unsigned char* img, bool readbackBgra) { - return mImpl->glOpReadback(img, readbackBgra); -} - -bool ColorBuffer::glOpReadbackAsync(GLuint buffer, bool readbackBgra) { - return mImpl->glOpReadbackAsync(buffer, readbackBgra); -} - -bool ColorBuffer::glOpImportEglNativePixmap(void* pixmap, bool preserveContent) { - return mImpl->glOpImportEglNativePixmap(pixmap, preserveContent); -} - -bool ColorBuffer::glOpSwapYuvTexturesAndUpdate(GLenum format, GLenum type, - GfxstreamFormat texturesFormat, GLuint* textures) { - return mImpl->glOpSwapYuvTexturesAndUpdate(format, type, texturesFormat, textures); -} - -bool ColorBuffer::glOpIsFastBlitSupported() const { return mImpl->glOpIsFastBlitSupported(); } - -bool ColorBuffer::glOpPostLayer(const ComposeLayer& l, int frameWidth, int frameHeight, - const std::optional>& colorTransform) { - return mImpl->glOpPostLayer(l, frameWidth, frameHeight, colorTransform); -} - -bool ColorBuffer::glOpPostViewportScaledWithOverlay( - float rotation, float dx, float dy, float scaleX, float scaleY, - const std::optional>& colorTransform) { - return mImpl->glOpPostViewportScaledWithOverlay(rotation, dx, dy, scaleX, scaleY, - colorTransform); -} - -#endif - } // namespace host } // namespace gfxstream diff --git a/host/color_buffer.h b/host/color_buffer.h index e82f3e12b..7698f22aa 100644 --- a/host/color_buffer.h +++ b/host/color_buffer.h @@ -14,10 +14,6 @@ #pragma once -#if GFXSTREAM_ENABLE_HOST_GLES -#include -#endif - #include #include #include @@ -85,6 +81,7 @@ class ColorBuffer : public IColorBuffer, public LazySnapshotObj { bool updateGlFromBytes(const void* bytes, std::size_t bytesSize); bool invalidateForBackend(Backend backend) override; + bool flushFromBackend(Backend backend) override; bool importHandle(void* handle, bool preserveContent) override; bool flushFromGl(); @@ -93,25 +90,6 @@ class ColorBuffer : public IColorBuffer, public LazySnapshotObj { std::optional exportBlob() override; -#if GFXSTREAM_ENABLE_HOST_GLES - bool canUseGlOps(); - bool glOpBlitFromCurrentReadBuffer(); - bool glOpBindToTexture(); - bool glOpBindToTexture2(); - bool glOpBindToRenderbuffer(); - bool glOpReadback(unsigned char* img, bool readbackBgra); - bool glOpReadbackAsync(GLuint buffer, bool readbackBgra); - bool glOpImportEglNativePixmap(void* pixmap, bool preserveContent); - bool glOpSwapYuvTexturesAndUpdate(GLenum format, GLenum type, GfxstreamFormat texturesFormat, - GLuint* textures); - bool glOpIsFastBlitSupported() const; - bool glOpPostLayer(const ComposeLayer& l, int frameWidth, int frameHeight, - const std::optional>& colorTransform); - bool glOpPostViewportScaledWithOverlay( - float rotation, float dx, float dy, float scaleX, float scaleY, - const std::optional>& colorTransform); -#endif - private: ColorBuffer() = default; diff --git a/host/common/include/gfxstream/host/color_buffer_interface.h b/host/common/include/gfxstream/host/color_buffer_interface.h index 5f7da5e77..e73c7eb98 100644 --- a/host/common/include/gfxstream/host/color_buffer_interface.h +++ b/host/common/include/gfxstream/host/color_buffer_interface.h @@ -53,6 +53,7 @@ class IColorBuffer { virtual vk::ColorBufferVk* getColorBufferVk() = 0; virtual bool invalidateForBackend(Backend backend) = 0; + virtual bool flushFromBackend(Backend backend) = 0; virtual bool importHandle(void* handle, bool preserveContent) = 0; virtual void readToBytes(int x, int y, int width, int height, GfxstreamFormat pixelsFormat, diff --git a/host/common/include/gfxstream/host/global_state.h b/host/common/include/gfxstream/host/global_state.h index 279566d76..0bdc1c0c7 100644 --- a/host/common/include/gfxstream/host/global_state.h +++ b/host/common/include/gfxstream/host/global_state.h @@ -19,6 +19,7 @@ #include "gfxstream/CancelableFuture.h" #include "gfxstream/host/color_buffer_interface.h" +#include "gfxstream/synchronization/Lock.h" namespace gfxstream { namespace host { @@ -28,13 +29,17 @@ class GlobalState { virtual ~GlobalState() = default; virtual IColorBufferRef findColorBuffer(uint32_t colorBufferHandle) = 0; + virtual void openColorBufferByWindow(uint32_t colorBufferHandle) = 0; + virtual bool closeColorBufferByWindow(uint32_t colorBufferHandle) = 0; + virtual uint32_t genHandleLocked() = 0; virtual void registerProcessCleanupCallback(void* key, uint64_t contextId, std::function callback) = 0; virtual void unregisterProcessCleanupCallback(void* key) = 0; - virtual void lockGlobalState() = 0; - virtual void unlockGlobalState() = 0; + virtual gfxstream::base::Lock& getGlobalLock() = 0; + virtual void lockGlobalState() ACQUIRE(getGlobalLock()) = 0; + virtual void unlockGlobalState() RELEASE(getGlobalLock()) = 0; virtual int getColorBufferScreenshot( IColorBuffer* cb, int targetWidth, int targetHeight, int skinRotation, @@ -48,7 +53,6 @@ class GlobalState { virtual float getPy() const = 0; virtual int getZrot() const = 0; - virtual void postLoadRenderThreadContextSurfacePtrs() = 0; virtual bool bindContext(uint32_t p_context, uint32_t p_drawSurface, uint32_t p_readSurface) = 0; diff --git a/host/common/include/gfxstream/host/readback_worker.h b/host/common/include/gfxstream/host/readback_worker.h index c31572049..9b3d53bba 100644 --- a/host/common/include/gfxstream/host/readback_worker.h +++ b/host/common/include/gfxstream/host/readback_worker.h @@ -55,6 +55,8 @@ class ReadbackWorker { virtual DoNextReadbackResult doNextReadback(uint32_t displayId, IColorBuffer* cb, void* fbImage, bool repaint, bool readbackBgra) = 0; + virtual void doNextReadbackSync(IColorBuffer* cb, void* fbImage, bool readbackBgra) = 0; + // Retrieves the latest framebuffer that has been posted and read with // doNextReadback. This is meant for apps like video encoding to use as // input; they will need to do synchronized communication with the thread diff --git a/host/frame_buffer.cpp b/host/frame_buffer.cpp index 6347b9d3b..6e44741da 100644 --- a/host/frame_buffer.cpp +++ b/host/frame_buffer.cpp @@ -22,7 +22,6 @@ #include -#include "gfxstream/host/global_state.h" #if defined(__linux__) #include @@ -40,10 +39,12 @@ #include "gl/glestranslator/egl/egl_global_info.h" #endif +#include "color_buffer.h" #include "gfxstream/Tracing.h" #include "gfxstream/common/logging.h" #include "gfxstream/containers/Lookup.h" #include "gfxstream/host/display_operations.h" +#include "gfxstream/host/global_state.h" #include "gfxstream/host/guest_operations.h" #include "gfxstream/host/hwc2.h" #include "gfxstream/host/native_sub_window.h" @@ -77,25 +78,15 @@ using gfxstream::host::gl::GLESApi_CM; #if GFXSTREAM_ENABLE_HOST_GLES using gfxstream::host::gl::ContextHelper; using gfxstream::host::gl::DisplaySurfaceGl; -using gfxstream::host::gl::EmulatedEglConfig; -using gfxstream::host::gl::EmulatedEglConfigList; using gfxstream::host::gl::EmulatedEglContext; -using gfxstream::host::gl::EmulatedEglContextMap; -using gfxstream::host::gl::EmulatedEglContextPtr; using gfxstream::host::gl::EmulatedEglFenceSync; using gfxstream::host::gl::EmulatedEglWindowSurface; -using gfxstream::host::gl::EmulatedEglWindowSurfaceMap; -using gfxstream::host::gl::EmulatedEglWindowSurfacePtr; using gfxstream::host::gl::EmulationGl; using gfxstream::host::gl::GLES_DISPATCH_MAX_VERSION_2; using gfxstream::host::gl::GLESDispatchMaxVersion; using gfxstream::host::gl::PostWorkerGl; using gfxstream::host::gl::RecursiveScopedContextBind; -using gfxstream::host::gl::RenderThreadInfoGl; -using gfxstream::host::gl::s_egl; -using gfxstream::host::gl::s_gles2; using gfxstream::host::gl::TextureDraw; -using gfxstream::host::gl::YUVConverter; #endif using gfxstream::host::vk::AstcEmulationMode; using gfxstream::host::vk::VkEmulation; @@ -283,28 +274,6 @@ std::optional GetGfxstreamFormat( } } -std::optional GetGfxstreamFormat( - const gfxstream::host::FeatureSet& features, - FrameworkFormat format) { - switch (format) { - case FRAMEWORK_FORMAT_NV12: - return GfxstreamFormat::NV12; - case FRAMEWORK_FORMAT_YV12: - return GfxstreamFormat::YV12; - case FRAMEWORK_FORMAT_P010: - return GfxstreamFormat::P010; - case FRAMEWORK_FORMAT_YUV_420_888: { - if (features.Yuv420888ToNv21.enabled()) { - return GfxstreamFormat::NV21; - } else { - return GfxstreamFormat::YV21; - } - } - default: - return std::nullopt; - } -} - static std::optional> GetColorTransform(uint32_t displayId = 0) { float displayColorTransformData[16]; if (get_gfxstream_multi_display_operations().get_color_transform_matrix( @@ -334,6 +303,27 @@ static std::optional> GetColorTransform(uint32_t displayId } // namespace +std::optional GetGfxstreamFormat(const gfxstream::host::FeatureSet& features, + FrameworkFormat format) { + switch (format) { + case FRAMEWORK_FORMAT_NV12: + return GfxstreamFormat::NV12; + case FRAMEWORK_FORMAT_YV12: + return GfxstreamFormat::YV12; + case FRAMEWORK_FORMAT_P010: + return GfxstreamFormat::P010; + case FRAMEWORK_FORMAT_YUV_420_888: { + if (features.Yuv420888ToNv21.enabled()) { + return GfxstreamFormat::NV21; + } else { + return GfxstreamFormat::YV21; + } + } + default: + return std::nullopt; + } +} + static HandleType sNextHandle = 0; struct BufferRef { @@ -482,15 +472,24 @@ class FrameBuffer::Impl : public gfxstream::base::EventNotificationSupportlockContextStructureRead(); + } + } + void unlockContextStructureRead() { + if (m_emulationGl) { + m_emulationGl->unlockContextStructureRead(); + } + } // For use with sync threads and otherwise, any time we need a GL context // not specifically for drawing, but to obtain certain things about // GL state. // It can be unsafe / leaky to change the structure of contexts // outside the facilities the FrameBuffer class provides. - void createTrivialContext(HandleType shared, HandleType* contextOut, HandleType* surfOut); + void createTrivialContext(HandleType shared, HandleType* contextOut, + HandleType* surfOut) NO_THREAD_SAFETY_ANALYSIS; void setShuttingDown() { m_shuttingDown = true; } bool isShuttingDown() const { return m_shuttingDown; } @@ -556,15 +555,20 @@ class FrameBuffer::Impl : public gfxstream::base::EventNotificationSupport>& colorTransform) override; void onLastColorBufferRef(uint32_t handle); + IColorBufferRef findColorBuffer(HandleType p_colorbuffer) override; + void openColorBufferByWindow(uint32_t colorBufferHandle) override; + bool closeColorBufferByWindow(uint32_t colorBufferHandle) override; + uint32_t genHandleLocked() override; BufferPtr findBuffer(HandleType p_buffer); void registerProcessCleanupCallback(void* key, uint64_t contextId, std::function callback) override; void unregisterProcessCleanupCallback(void* key) override; - void lockGlobalState() override; - void unlockGlobalState() override; + gfxstream::base::Lock& getGlobalLock() override LOCK_RETURNED(m_lock); + void lockGlobalState() override ACQUIRE(getGlobalLock()); + void unlockGlobalState() override RELEASE(getGlobalLock()); void invalidateColorBuffer(uint32_t colorBufferHandle) override; void flushColorBuffer(uint32_t colorBufferHandle) override; @@ -619,8 +623,9 @@ class FrameBuffer::Impl : public gfxstream::base::EventNotificationSupport cleanupProcGLObjects_locked(uint64_t puid, bool forced = false); @@ -875,8 +865,7 @@ class FrameBuffer::Impl : public gfxstream::base::EventNotificationSupport m_displaySurface; +#if GFXSTREAM_ENABLE_HOST_GLES + gl::DisplayGl* m_displayGl = nullptr; +#endif + // CompositorGl. // TODO: update RenderDoc to be a DisplaySurfaceUser. std::vector m_displaySurfaceUsers; @@ -1092,26 +1085,6 @@ class FrameBuffer::Impl : public gfxstream::base::EventNotificationSupport m_EmulatedEglWindowSurfaceToColorBuffer; - - ProcOwnedEmulatedEGLImages m_procOwnedEmulatedEglImages; - ProcOwnedEmulatedEglContexts m_procOwnedEmulatedEglContexts; - ProcOwnedEmulatedEglWindowSurfaces m_procOwnedEmulatedEglWindowSurfaces; - gl::DisplayGl* m_displayGl = nullptr; - - struct PlatformEglContextInfo { - EGLContext context; - EGLSurface surface; - }; - - std::unordered_map m_platformEglContexts; -#endif }; void MaybeIncreaseFileDescriptorSoftLimit() { @@ -1314,7 +1287,7 @@ std::unique_ptr FrameBuffer::Impl::Create(FrameBuffer* frameb // Do not initialize GL emulation if the guest is using ANGLE. if (needEmulationGl) { impl->m_emulationGl = - EmulationGl::create(width, height, impl->m_features, useSubWindow); + EmulationGl::create(width, height, impl->m_features, useSubWindow, impl.get()); if (!impl->m_emulationGl) { GFXSTREAM_ERROR("Failed to initialize GL emulation."); return nullptr; @@ -1601,15 +1574,6 @@ FrameBuffer::Impl::~Impl() { } m_colorBufferDelayedCloseList.clear(); -#if GFXSTREAM_ENABLE_HOST_GLES - m_windows.clear(); - m_contexts.clear(); - - for (auto it : m_platformEglContexts) { - destroySharedTrivialContext(it.second.context, it.second.surface); - } -#endif - if (m_emulationGl) { m_emulationGl.reset(); } @@ -2035,13 +1999,13 @@ bool FrameBuffer::Impl::removeSubWindow_locked() { return removed; } -HandleType FrameBuffer::Impl::genHandle_locked() { +uint32_t FrameBuffer::Impl::genHandleLocked() NO_THREAD_SAFETY_ANALYSIS { HandleType id; do { id = ++sNextHandle; } while (id == 0 || #if GFXSTREAM_ENABLE_HOST_GLES - m_contexts.find(id) != m_contexts.end() || m_windows.find(id) != m_windows.end() || + (m_emulationGl && m_emulationGl->isHandleInUse(id)) || #endif m_colorbuffers.find(id) != m_colorbuffers.end() || m_buffers.find(id) != m_buffers.end()); @@ -2065,7 +2029,7 @@ HandleType FrameBuffer::Impl::createColorBuffer(int p_width, int p_height, Gfxst sweepColorBuffersLocked(); AutoLock colorBufferMapLock(m_colorBufferMapLock); - HandleType handle = genHandle_locked(); + HandleType handle = genHandleLocked(); if (!createColorBufferWithResourceHandleLocked(p_width, p_height, format, handle)) { GFXSTREAM_ERROR("Failed to create color buffer with resource handle"); return 0; @@ -2167,7 +2131,7 @@ bool FrameBuffer::Impl::createColorBufferWithResourceHandleLocked(int p_width, i HandleType FrameBuffer::Impl::createBuffer(uint64_t p_size, uint32_t memoryProperty) { AutoLock mutex(m_lock); AutoLock colorBufferMapLock(m_colorBufferMapLock); - HandleType handle = genHandle_locked(); + HandleType handle = genHandleLocked(); if (!createBufferWithResourceHandleLocked(p_size, handle, memoryProperty)) { GFXSTREAM_ERROR("Failed to create buffer"); return 0; @@ -2438,7 +2402,8 @@ void FrameBuffer::Impl::cleanupProcGLObjects(uint64_t puid) { } } -std::vector FrameBuffer::Impl::cleanupProcGLObjects_locked(uint64_t puid, bool forced) { +std::vector FrameBuffer::Impl::cleanupProcGLObjects_locked(uint64_t puid, bool forced) + NO_THREAD_SAFETY_ANALYSIS { std::vector colorBuffersToCleanup; { std::unique_ptr bind = nullptr; @@ -2446,30 +2411,21 @@ std::vector FrameBuffer::Impl::cleanupProcGLObjects_locked(uint64_t if (m_emulationGl) { bind = std::make_unique(getPbufferSurfaceContextHelper()); } - // Clean up window surfaces + // Clean up GLES window surfaces and contexts if (m_emulationGl) { - auto procIte = m_procOwnedEmulatedEglWindowSurfaces.find(puid); - if (procIte != m_procOwnedEmulatedEglWindowSurfaces.end()) { - for (auto whndl : procIte->second) { - auto w = m_windows.find(whndl); - // TODO(b/265186226): figure out if we are leaking? - if (w == m_windows.end()) { - continue; - } - if (!m_guestManagedColorBufferLifetime) { - if (m_refCountPipeEnabled) { - if (decColorBufferRefCountLocked(w->second.second)) { - colorBuffersToCleanup.push_back(w->second.second); - } - } else { - if (closeColorBufferLocked(w->second.second, forced)) { - colorBuffersToCleanup.push_back(w->second.second); - } + auto colorBuffers = m_emulationGl->cleanupProcGLObjects(puid); + for (auto cb : colorBuffers) { + if (!m_guestManagedColorBufferLifetime) { + if (m_refCountPipeEnabled) { + if (decColorBufferRefCountLocked(cb)) { + colorBuffersToCleanup.push_back(cb); + } + } else { + if (closeColorBufferLocked(cb, forced)) { + colorBuffersToCleanup.push_back(cb); } } - m_windows.erase(w); } - m_procOwnedEmulatedEglWindowSurfaces.erase(procIte); } } #endif @@ -2491,35 +2447,8 @@ std::vector FrameBuffer::Impl::cleanupProcGLObjects_locked(uint64_t } } } - -#if GFXSTREAM_ENABLE_HOST_GLES - // Clean up EGLImage handles - if (m_emulationGl) { - auto procImagesIt = m_procOwnedEmulatedEglImages.find(puid); - if (procImagesIt != m_procOwnedEmulatedEglImages.end()) { - for (auto image : procImagesIt->second) { - m_images.erase(image); - } - m_procOwnedEmulatedEglImages.erase(procImagesIt); - } - } -#endif } -#if GFXSTREAM_ENABLE_HOST_GLES - // Unbind before cleaning up contexts - // Cleanup render contexts - if (m_emulationGl) { - auto procIte = m_procOwnedEmulatedEglContexts.find(puid); - if (procIte != m_procOwnedEmulatedEglContexts.end()) { - for (auto ctx : procIte->second) { - m_contexts.erase(ctx); - } - m_procOwnedEmulatedEglContexts.erase(procIte); - } - } -#endif - return colorBuffersToCleanup; } @@ -2781,9 +2710,11 @@ AsyncResult FrameBuffer::Impl::postImpl(HandleType p_colorbuffer, Post::Completi doPostCallback(iter.second.img, iter.first); } } else { - #if GFXSTREAM_ENABLE_HOST_GLES - cb->glOpReadback(iter.second.img, iter.second.readBgra); - #endif + ensureReadbackWorker(); + if (m_readbackWorker) { + m_readbackWorker->doNextReadbackSync(cb.get(), iter.second.img, + iter.second.readBgra); + } doPostCallback(iter.second.img, iter.first); } } @@ -3219,7 +3150,8 @@ AsyncResult FrameBuffer::Impl::composeWithCallback(uint32_t bufferSize, void* bu } } -bool FrameBuffer::Impl::onSave(Stream* stream, const ITextureSaverPtr& textureSaver) { +bool FrameBuffer::Impl::onSave(Stream* stream, + const ITextureSaverPtr& textureSaver) NO_THREAD_SAFETY_ANALYSIS { // Things we do not need to snapshot: // m_eglSurface // m_eglContext @@ -3243,12 +3175,7 @@ bool FrameBuffer::Impl::onSave(Stream* stream, const ITextureSaverPtr& textureSa // (textures created by the host are not saved!) // eglSaveAllImages labels all EGLImages (both host and guest) to be saved // and save all labeled textures and EGLImages. - if (s_egl.eglPreSaveContext && s_egl.eglSaveAllImages) { - for (const auto& ctx : m_contexts) { - s_egl.eglPreSaveContext(getDisplay(), ctx.second->getEGLContext(), stream); - } - s_egl.eglSaveAllImages(getDisplay(), stream, &textureSaver); - } + m_emulationGl->preSave(stream, textureSaver); } #endif @@ -3296,9 +3223,9 @@ bool FrameBuffer::Impl::onSave(Stream* stream, const ITextureSaverPtr& textureSa // objects). // TODO: skip reading from GPU even for texture objects. #if GFXSTREAM_ENABLE_HOST_GLES - saveCollection( - stream, m_contexts, - [](Stream* s, const EmulatedEglContextMap::value_type& pair) { pair.second->onSave(s); }); + if (m_emulationGl) { + m_emulationGl->saveContexts(stream); + } #endif // We don't need to save |m_colorBufferCloseTsMap| here - there's enough @@ -3319,20 +3246,22 @@ bool FrameBuffer::Impl::onSave(Stream* stream, const ITextureSaverPtr& textureSa } stream->putBe32(m_lastPostedColorBuffer); #if GFXSTREAM_ENABLE_HOST_GLES - saveCollection(stream, m_windows, - [](Stream* s, const EmulatedEglWindowSurfaceMap::value_type& pair) { - pair.second.first->onSave(s); - s->putBe32(pair.second.second); // Color buffer handle. - }); + if (m_emulationGl) { + m_emulationGl->saveWindowSurfaces(stream); + } #endif #if GFXSTREAM_ENABLE_HOST_GLES - saveProcOwnedCollection(stream, m_procOwnedEmulatedEglWindowSurfaces); + if (m_emulationGl) { + m_emulationGl->saveProcOwnedWindowSurfaces(stream); + } #endif saveProcOwnedCollection(stream, m_procOwnedColorBuffers); #if GFXSTREAM_ENABLE_HOST_GLES - saveProcOwnedCollection(stream, m_procOwnedEmulatedEglImages); - saveProcOwnedCollection(stream, m_procOwnedEmulatedEglContexts); + if (m_emulationGl) { + m_emulationGl->saveProcOwnedImages(stream); + m_emulationGl->saveProcOwnedContexts(stream); + } #endif // TODO(b/309858017): remove if when ready to bump snapshot version @@ -3355,24 +3284,15 @@ bool FrameBuffer::Impl::onSave(Stream* stream, const ITextureSaverPtr& textureSa #if GFXSTREAM_ENABLE_HOST_GLES if (m_emulationGl) { - if (s_egl.eglPostSaveContext) { - for (const auto& ctx : m_contexts) { - s_egl.eglPostSaveContext(getDisplay(), ctx.second->getEGLContext(), stream); - } - // We need to run the post save step for m_eglContext - // to mark their texture handles dirty - if (getContext() != EGL_NO_CONTEXT) { - s_egl.eglPostSaveContext(getDisplay(), getContext(), stream); - } - } - + m_emulationGl->postSave(stream); EmulatedEglFenceSync::onSave(stream); } #endif return true; } -bool FrameBuffer::Impl::onLoad(Stream* stream, const ITextureLoaderPtr& textureLoader) { +bool FrameBuffer::Impl::onLoad(Stream* stream, + const ITextureLoaderPtr& textureLoader) NO_THREAD_SAFETY_ANALYSIS { AutoLock lock(m_lock); // cleanups { @@ -3394,19 +3314,19 @@ bool FrameBuffer::Impl::onLoad(Stream* stream, const ITextureLoaderPtr& textureL AutoLock colorBufferMapLock(m_colorBufferMapLock); if (m_procOwnedCleanupCallbacks.empty() && m_procOwnedColorBuffers.empty() && #if GFXSTREAM_ENABLE_HOST_GLES - m_procOwnedEmulatedEglContexts.empty() && m_procOwnedEmulatedEglImages.empty() && - m_procOwnedEmulatedEglWindowSurfaces.empty() && + (!m_emulationGl || !m_emulationGl->hasProcOwnedResources()) && #endif ( #if GFXSTREAM_ENABLE_HOST_GLES - !m_contexts.empty() || !m_windows.empty() || + (m_emulationGl && m_emulationGl->hasContextsOrWindowSurfaces()) || #endif m_colorbuffers.size() > m_colorBufferDelayedCloseList.size())) { // we are likely on a legacy system image, which does not have // process owned objects. We need to force cleanup everything #if GFXSTREAM_ENABLE_HOST_GLES - m_contexts.clear(); - m_windows.clear(); + if (m_emulationGl) { + m_emulationGl->clearContextsAndWindowSurfaces(); + } #endif m_colorbuffers.clear(); cleanupComplete = true; @@ -3416,11 +3336,13 @@ bool FrameBuffer::Impl::onLoad(Stream* stream, const ITextureLoaderPtr& textureL std::vector colorBuffersToCleanup; #if GFXSTREAM_ENABLE_HOST_GLES - while (m_procOwnedEmulatedEglWindowSurfaces.size()) { - auto cleanupHandles = cleanupProcGLObjects_locked( - m_procOwnedEmulatedEglWindowSurfaces.begin()->first, true); - colorBuffersToCleanup.insert(colorBuffersToCleanup.end(), cleanupHandles.begin(), - cleanupHandles.end()); + if (m_emulationGl) { + auto glPuids = m_emulationGl->getGLPUIDs(); + for (uint64_t puid : glPuids) { + auto cleanupHandles = cleanupProcGLObjects_locked(puid, true); + colorBuffersToCleanup.insert(colorBuffersToCleanup.end(), + cleanupHandles.begin(), cleanupHandles.end()); + } } #endif while (m_procOwnedColorBuffers.size()) { @@ -3429,20 +3351,6 @@ bool FrameBuffer::Impl::onLoad(Stream* stream, const ITextureLoaderPtr& textureL colorBuffersToCleanup.insert(colorBuffersToCleanup.end(), cleanupHandles.begin(), cleanupHandles.end()); } -#if GFXSTREAM_ENABLE_HOST_GLES - while (m_procOwnedEmulatedEglImages.size()) { - auto cleanupHandles = - cleanupProcGLObjects_locked(m_procOwnedEmulatedEglImages.begin()->first, true); - colorBuffersToCleanup.insert(colorBuffersToCleanup.end(), cleanupHandles.begin(), - cleanupHandles.end()); - } - while (m_procOwnedEmulatedEglContexts.size()) { - auto cleanupHandles = cleanupProcGLObjects_locked( - m_procOwnedEmulatedEglContexts.begin()->first, true); - colorBuffersToCleanup.insert(colorBuffersToCleanup.end(), cleanupHandles.begin(), - cleanupHandles.end()); - } -#endif std::vector> cleanupCallbacks; @@ -3474,8 +3382,9 @@ bool FrameBuffer::Impl::onLoad(Stream* stream, const ITextureLoaderPtr& textureL } m_colorBufferDelayedCloseList.clear(); #if GFXSTREAM_ENABLE_HOST_GLES - assert(m_contexts.empty()); - assert(m_windows.empty()); + if (m_emulationGl) { + assert(!m_emulationGl->hasContextsOrWindowSurfaces()); + } #endif { AutoLock colorBufferMapLock(m_colorBufferMapLock); @@ -3487,9 +3396,7 @@ bool FrameBuffer::Impl::onLoad(Stream* stream, const ITextureLoaderPtr& textureL } #if GFXSTREAM_ENABLE_HOST_GLES if (m_emulationGl) { - if (s_egl.eglLoadAllImages) { - s_egl.eglLoadAllImages(getDisplay(), stream, &textureLoader); - } + m_emulationGl->loadAllImages(stream, textureLoader); } #endif } @@ -3524,15 +3431,12 @@ bool FrameBuffer::Impl::onLoad(Stream* stream, const ITextureLoaderPtr& textureL m_statsStartTime = stream->getBe64(); #if GFXSTREAM_ENABLE_HOST_GLES - loadCollection( - stream, &m_contexts, [this](Stream* stream) -> EmulatedEglContextMap::value_type { - ENSURE_GL_EMULATION_FATAL(); - - auto context = m_emulationGl->loadEmulatedEglContext(stream); - auto contextHandle = context ? context->getHndl() : 0; - return {contextHandle, std::move(context)}; - }); - assert(!gfxstream::base::find(m_contexts, 0)); + if (m_emulationGl) { + if (!m_emulationGl->loadContexts(stream)) { + GFXSTREAM_ERROR("Failed to load GL contexts."); + return false; + } + } #endif auto now = gfxstream::base::getUnixTimeUs(); @@ -3564,32 +3468,32 @@ bool FrameBuffer::Impl::onLoad(Stream* stream, const ITextureLoaderPtr& textureL { AutoLock colorBufferMapLock(m_colorBufferMapLock); #if GFXSTREAM_ENABLE_HOST_GLES - loadCollection( - stream, &m_windows, [this](Stream* stream) -> EmulatedEglWindowSurfaceMap::value_type { - ENSURE_GL_EMULATION_FATAL(); - auto window = m_emulationGl->loadEmulatedEglWindowSurface( - stream, - [this](uint32_t handle) -> IColorBufferRef { - auto it = m_colorbuffers.find(handle); - if (it == m_colorbuffers.end()) return nullptr; - return it->second.cb; - }, - m_contexts); - - HandleType handle = window->getHndl(); - HandleType colorBufferHandle = stream->getBe32(); - return {handle, {std::move(window), colorBufferHandle}}; - }); + if (m_emulationGl) { + if (!m_emulationGl->loadWindowSurfaces(stream, + [this](uint32_t handle) -> IColorBufferRef { + auto it = m_colorbuffers.find(handle); + if (it == m_colorbuffers.end()) + return nullptr; + return it->second.cb; + })) { + GFXSTREAM_ERROR("Failed to load GL window surfaces."); + return false; + } + } #endif } #if GFXSTREAM_ENABLE_HOST_GLES - loadProcOwnedCollection(stream, &m_procOwnedEmulatedEglWindowSurfaces); + if (m_emulationGl) { + m_emulationGl->loadProcOwnedWindowSurfaces(stream); + } #endif loadProcOwnedCollection(stream, &m_procOwnedColorBuffers); #if GFXSTREAM_ENABLE_HOST_GLES - loadProcOwnedCollection(stream, &m_procOwnedEmulatedEglImages); - loadProcOwnedCollection(stream, &m_procOwnedEmulatedEglContexts); + if (m_emulationGl) { + m_emulationGl->loadProcOwnedImages(stream); + m_emulationGl->loadProcOwnedContexts(stream); + } #endif // TODO(b/309858017): remove if when ready to bump snapshot version if (m_features.VulkanSnapshots.enabled()) { @@ -3608,9 +3512,7 @@ bool FrameBuffer::Impl::onLoad(Stream* stream, const ITextureLoaderPtr& textureL #if GFXSTREAM_ENABLE_HOST_GLES if (m_emulationGl) { - if (s_egl.eglPostLoadAllImages) { - s_egl.eglPostLoadAllImages(getDisplay(), stream); - } + m_emulationGl->postLoad(stream); } registerTriggerWait(); @@ -3660,9 +3562,11 @@ void FrameBuffer::Impl::lock() { m_lock.lock(); } void FrameBuffer::Impl::unlock() { m_lock.unlock(); } -void FrameBuffer::Impl::lockGlobalState() NO_THREAD_SAFETY_ANALYSIS { lock(); } +gfxstream::base::Lock& FrameBuffer::Impl::getGlobalLock() { return m_lock; } -void FrameBuffer::Impl::unlockGlobalState() NO_THREAD_SAFETY_ANALYSIS { unlock(); } +void FrameBuffer::Impl::lockGlobalState() { lock(); } + +void FrameBuffer::Impl::unlockGlobalState() { unlock(); } IColorBufferRef FrameBuffer::Impl::findColorBuffer(HandleType p_colorbuffer) { AutoLock colorBufferMapLock(m_colorBufferMapLock); @@ -3673,6 +3577,28 @@ IColorBufferRef FrameBuffer::Impl::findColorBuffer(HandleType p_colorbuffer) { return std::dynamic_pointer_cast(it->second.cb); } +void FrameBuffer::Impl::openColorBufferByWindow(uint32_t colorBufferHandle) { + AutoLock colorBufferMapLock(m_colorBufferMapLock); + auto c = m_colorbuffers.find(colorBufferHandle); + if (c != m_colorbuffers.end()) { + markOpened(&c->second); + if (!m_guestManagedColorBufferLifetime) { + c->second.refcount++; + } + } +} + +bool FrameBuffer::Impl::closeColorBufferByWindow(uint32_t colorBufferHandle) { + if (!m_guestManagedColorBufferLifetime) { + if (m_refCountPipeEnabled) { + return decColorBufferRefCountLocked(colorBufferHandle); + } else { + return closeColorBufferLocked(colorBufferHandle); + } + } + return false; +} + BufferPtr FrameBuffer::Impl::findBuffer(HandleType p_buffer) { AutoLock colorBufferMapLock(m_colorBufferMapLock); auto it = m_buffers.find(p_buffer); @@ -3993,15 +3919,11 @@ int32_t FrameBuffer::Impl::mapGpaToBufferHandle(uint32_t bufferHandle, uint64_t } #if GFXSTREAM_ENABLE_HOST_GLES -HandleType FrameBuffer::Impl::getEmulatedEglWindowSurfaceColorBufferHandle(HandleType p_surface) { +HandleType FrameBuffer::Impl::getEmulatedEglWindowSurfaceColorBufferHandle(HandleType p_surface) + NO_THREAD_SAFETY_ANALYSIS { + ENSURE_GL_EMULATION_VALUE(0); AutoLock mutex(m_lock); - - auto it = m_EmulatedEglWindowSurfaceToColorBuffer.find(p_surface); - if (it == m_EmulatedEglWindowSurfaceToColorBuffer.end()) { - return 0; - } - - return it->second; + return m_emulationGl->getWindowSurfaceColorBufferHandle(p_surface); } void FrameBuffer::Impl::setScreenMask(int width, int height, const uint8_t* rgbaData) { @@ -4079,88 +4001,34 @@ void FrameBuffer::Impl::unregisterVulkanInstance(uint64_t id) const {} #endif void FrameBuffer::Impl::createTrivialContext(HandleType shared, HandleType* contextOut, - HandleType* surfOut) { - assert(contextOut); - assert(surfOut); - - *contextOut = createEmulatedEglContext(0, shared, GLESApi_2); - // Zero size is formally allowed here, but SwiftShader doesn't like it and - // fails. - *surfOut = createEmulatedEglWindowSurface(0, 1, 1); -} - -void FrameBuffer::Impl::createSharedTrivialContext(EGLContext* contextOut, EGLSurface* surfOut) { - assert(contextOut); - assert(surfOut); - - ENSURE_GL_EMULATION_VOID(); - - if (m_emulationGl->mEglConfig == EGL_NO_CONFIG) { - GFXSTREAM_FATAL("GL/EGL emulation has not chosen a config."); + HandleType* surfOut) NO_THREAD_SAFETY_ANALYSIS { + AutoLock mutex(m_lock); + if (m_emulationGl) { + m_emulationGl->createTrivialContext(shared, contextOut, surfOut); } - - int maj, min; - get_gfxstream_gles_version(&maj, &min); - - const EGLint contextAttribs[] = {EGL_CONTEXT_MAJOR_VERSION_KHR, maj, - EGL_CONTEXT_MINOR_VERSION_KHR, min, EGL_NONE}; - - *contextOut = s_egl.eglCreateContext(getDisplay(), m_emulationGl->mEglConfig, - getGlobalEGLContext(), contextAttribs); - - const EGLint pbufAttribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE}; - - *surfOut = s_egl.eglCreatePbufferSurface(getDisplay(), m_emulationGl->mEglConfig, pbufAttribs); } -void FrameBuffer::Impl::destroySharedTrivialContext(EGLContext context, EGLSurface surface) { - if (getDisplay() != EGL_NO_DISPLAY) { - s_egl.eglDestroyContext(getDisplay(), context); - s_egl.eglDestroySurface(getDisplay(), surface); +void FrameBuffer::Impl::createSharedTrivialContext(EGLContext* contextOut, + EGLSurface* surfOut) NO_THREAD_SAFETY_ANALYSIS { + AutoLock mutex(m_lock); + if (m_emulationGl) { + m_emulationGl->createSharedTrivialContext(contextOut, surfOut); } } -bool FrameBuffer::Impl::setEmulatedEglWindowSurfaceColorBuffer(HandleType p_surface, - HandleType p_colorbuffer) { +void FrameBuffer::Impl::destroySharedTrivialContext(EGLContext context, + EGLSurface surface) NO_THREAD_SAFETY_ANALYSIS { AutoLock mutex(m_lock); - - EmulatedEglWindowSurfaceMap::iterator w(m_windows.find(p_surface)); - if (w == m_windows.end()) { - // bad surface handle - GFXSTREAM_ERROR("bad window surface handle %#x", p_surface); - return false; - } - - { - AutoLock colorBufferMapLock(m_colorBufferMapLock); - auto c = m_colorbuffers.find(p_colorbuffer); - if (c == m_colorbuffers.end()) { - GFXSTREAM_ERROR("bad color buffer handle %d", p_colorbuffer); - // bad colorbuffer handle - return false; - } - - (*w).second.first->setColorBuffer((*c).second.cb); - markOpened(&c->second); - if (!m_guestManagedColorBufferLifetime) { - c->second.refcount++; - } - } - if (w->second.second) { - if (!m_guestManagedColorBufferLifetime) { - if (m_refCountPipeEnabled) { - decColorBufferRefCountLocked(w->second.second); - } else { - closeColorBufferLocked(w->second.second); - } - } + if (m_emulationGl) { + m_emulationGl->destroySharedTrivialContext(context, surface); } +} - (*w).second.second = p_colorbuffer; - - m_EmulatedEglWindowSurfaceToColorBuffer[p_surface] = p_colorbuffer; - - return true; +bool FrameBuffer::Impl::setEmulatedEglWindowSurfaceColorBuffer( + HandleType p_surface, HandleType p_colorbuffer) NO_THREAD_SAFETY_ANALYSIS { + ENSURE_GL_EMULATION_VALUE(false); + AutoLock mutex(m_lock); + return m_emulationGl->setEmulatedEglWindowSurfaceColorBuffer(p_surface, p_colorbuffer); } std::string FrameBuffer::Impl::getEglString(EGLenum name) { @@ -4207,109 +4075,30 @@ EGLint FrameBuffer::Impl::chooseConfig(EGLint* attribs, EGLint* configs, EGLint } HandleType FrameBuffer::Impl::createEmulatedEglContext(int config, HandleType shareContextHandle, - GLESApi version) { + GLESApi version) NO_THREAD_SAFETY_ANALYSIS { ENSURE_GL_EMULATION_VALUE(0); AutoLock mutex(m_lock); - gfxstream::base::AutoWriteLock contextLock(m_contextStructureLock); - // Hold the ColorBuffer map lock so that the new handle won't collide with a - // ColorBuffer handle. AutoLock colorBufferMapLock(m_colorBufferMapLock); - EmulatedEglContextPtr shareContext = nullptr; - if (shareContextHandle != 0) { - auto shareContextIt = m_contexts.find(shareContextHandle); - if (shareContextIt == m_contexts.end()) { - GFXSTREAM_ERROR("Failed to find share EmulatedEglContext:%d", shareContextHandle); - return 0; - } - shareContext = shareContextIt->second; - } - - HandleType contextHandle = genHandle_locked(); - auto context = - m_emulationGl->createEmulatedEglContext(config, shareContext.get(), version, contextHandle); - if (!context) { - GFXSTREAM_ERROR("Failed to create EmulatedEglContext."); - return 0; - } - - m_contexts[contextHandle] = std::move(context); - - RenderThreadInfo* tinfo = RenderThreadInfo::get(); - uint64_t puid = tinfo->m_puid; - // The new emulator manages render contexts per guest process. - // Fall back to per-thread management if the system image does not - // support it. - if (puid) { - m_procOwnedEmulatedEglContexts[puid].insert(contextHandle); - } else { // legacy path to manage context lifetime by threads - if (!tinfo->m_glInfo) { - GFXSTREAM_ERROR("RenderThreadGL not available."); - } - else { - tinfo->m_glInfo->m_contextSet.insert(contextHandle); - } - } - - return contextHandle; + return m_emulationGl->createEmulatedEglContext(config, shareContextHandle, version); } -void FrameBuffer::Impl::destroyEmulatedEglContext(HandleType contextHandle) { +void FrameBuffer::Impl::destroyEmulatedEglContext(HandleType contextHandle) + NO_THREAD_SAFETY_ANALYSIS { + ENSURE_GL_EMULATION_VOID(); AutoLock mutex(m_lock); sweepColorBuffersLocked(); - gfxstream::base::AutoWriteLock contextLock(m_contextStructureLock); - m_contexts.erase(contextHandle); - RenderThreadInfo* tinfo = RenderThreadInfo::get(); - uint64_t puid = tinfo->m_puid; - // The new emulator manages render contexts per guest process. - // Fall back to per-thread management if the system image does not - // support it. - if (puid) { - auto it = m_procOwnedEmulatedEglContexts.find(puid); - if (it != m_procOwnedEmulatedEglContexts.end()) { - it->second.erase(contextHandle); - } - } else { - if (!tinfo->m_glInfo) { - GFXSTREAM_FATAL("RenderThreadGL not available."); - } - tinfo->m_glInfo->m_contextSet.erase(contextHandle); - } + m_emulationGl->destroyEmulatedEglContext(contextHandle); } -HandleType FrameBuffer::Impl::createEmulatedEglWindowSurface(int p_config, int p_width, - int p_height) { +HandleType FrameBuffer::Impl::createEmulatedEglWindowSurface( + int p_config, int p_width, int p_height) NO_THREAD_SAFETY_ANALYSIS { ENSURE_GL_EMULATION_VALUE(0); AutoLock mutex(m_lock); - // Hold the ColorBuffer map lock so that the new handle won't collide with a - // ColorBuffer handle. AutoLock colorBufferMapLock(m_colorBufferMapLock); - HandleType handle = genHandle_locked(); - - auto window = - m_emulationGl->createEmulatedEglWindowSurface(p_config, p_width, p_height, handle); - if (!window) { - GFXSTREAM_ERROR("Failed to create EmulatedEglWindowSurface."); - return 0; - } - - m_windows[handle] = {std::move(window), 0}; - - RenderThreadInfo* info = RenderThreadInfo::get(); - if (!info->m_glInfo) { - GFXSTREAM_FATAL("RRenderThreadInfoGl not available."); - } - - uint64_t puid = info->m_puid; - if (puid) { - m_procOwnedEmulatedEglWindowSurfaces[puid].insert(handle); - } else { // legacy path to manage window surface lifetime by threads - info->m_glInfo->m_windowSet.insert(handle); - } - - return handle; + return m_emulationGl->createEmulatedEglWindowSurface(p_config, p_width, p_height); } void FrameBuffer::Impl::destroyEmulatedEglWindowSurface(HandleType p_surface) { @@ -4321,36 +4110,21 @@ void FrameBuffer::Impl::destroyEmulatedEglWindowSurface(HandleType p_surface) { } std::vector FrameBuffer::Impl::destroyEmulatedEglWindowSurfaceLocked( - HandleType p_surface) { + HandleType p_surface) NO_THREAD_SAFETY_ANALYSIS { std::vector colorBuffersToCleanUp; - const auto w = m_windows.find(p_surface); - if (w != m_windows.end()) { - RecursiveScopedContextBind bind(getPbufferSurfaceContextHelper()); + auto colorBuffers = m_emulationGl->destroyEmulatedEglWindowSurface(p_surface); + for (auto cb : colorBuffers) { if (!m_guestManagedColorBufferLifetime) { if (m_refCountPipeEnabled) { - if (decColorBufferRefCountLocked(w->second.second)) { - colorBuffersToCleanUp.push_back(w->second.second); + if (decColorBufferRefCountLocked(cb)) { + colorBuffersToCleanUp.push_back(cb); } } else { - if (closeColorBufferLocked(w->second.second)) { - colorBuffersToCleanUp.push_back(w->second.second); + if (closeColorBufferLocked(cb)) { + colorBuffersToCleanUp.push_back(cb); } } } - m_windows.erase(w); - RenderThreadInfo* tinfo = RenderThreadInfo::get(); - uint64_t puid = tinfo->m_puid; - if (puid) { - auto ite = m_procOwnedEmulatedEglWindowSurfaces.find(puid); - if (ite != m_procOwnedEmulatedEglWindowSurfaces.end()) { - ite->second.erase(p_surface); - } - } else { - if (!tinfo->m_glInfo) { - GFXSTREAM_FATAL("RenderThreadGL not available."); - } - tinfo->m_glInfo->m_windowSet.erase(p_surface); - } } return colorBuffersToCleanUp; } @@ -4365,49 +4139,20 @@ void FrameBuffer::Impl::createEmulatedEglFenceSync(EGLenum type, int destroyWhen } if (m_emulationGl) { - // TODO(b/233939967): move RenderThreadInfoGl usage to EmulationGl. - RenderThreadInfoGl* const info = RenderThreadInfoGl::get(); - if (!info) { - GFXSTREAM_FATAL("RenderThreadGL not available."); - } - if (!info->currContext) { - uint32_t syncContext; - uint32_t syncSurface; - createTrivialContext(0, // There is no context to share. - &syncContext, &syncSurface); - bindContext(syncContext, syncSurface, syncSurface); - // This context is then cleaned up when the render thread exits. - } - - auto sync = m_emulationGl->createEmulatedEglFenceSync(type, destroyWhenSignaled); - if (sync && outSync) { - *outSync = (uint64_t)(uintptr_t)sync.release(); + if (outSync) { + *outSync = m_emulationGl->createEmulatedEglFenceSync(type, destroyWhenSignaled); } - } - else if (m_emulationVk) { + } else if (m_emulationVk) { // No-op: compose operations using this callback will be waited on the futures // generated before processing later rc commands. This ensures CPU and GPU // synchronization is established for non-async compose scenarios, where this // codepath is used via HostFrameComposer on non-virtiogpu/minigbm images. // Egl fences are not used on newer images with virtiogpu/minigbm. - } - else { + } else { GFXSTREAM_FATAL("Unimplemented"); } } -void FrameBuffer::Impl::postLoadRenderThreadContextSurfacePtrs() { - RenderThreadInfoGl* const info = RenderThreadInfoGl::get(); - if (!info) { - GFXSTREAM_FATAL("RenderThreadGL not available."); - } - - AutoLock lock(m_lock); - info->currContext = getContext_locked(info->currContextHandleFromLoad); - info->currDrawSurf = getWindowSurface_locked(info->currDrawSurfHandleFromLoad); - info->currReadSurf = getWindowSurface_locked(info->currReadSurfHandleFromLoad); -} - void FrameBuffer::Impl::drainGlRenderThreadResources() { // If we're already exiting then snapshot should not contain // this thread information at all. @@ -4415,77 +4160,31 @@ void FrameBuffer::Impl::drainGlRenderThreadResources() { return; } - // Release references to the current thread's context/surfaces if any - bindContext(0, 0, 0); - - drainGlRenderThreadSurfaces(); - drainGlRenderThreadContexts(); - - if (!s_egl.eglReleaseThread()) { - GFXSTREAM_ERROR("Error: RenderThread @%p failed to eglReleaseThread()", this); + if (m_emulationGl) { + m_emulationGl->drainRenderThreadResources(); } } -void FrameBuffer::Impl::drainGlRenderThreadContexts() { +void FrameBuffer::Impl::drainGlRenderThreadContexts() NO_THREAD_SAFETY_ANALYSIS { if (isShuttingDown()) { return; } - RenderThreadInfoGl* const tinfo = RenderThreadInfoGl::get(); - if (!tinfo) { - GFXSTREAM_FATAL("RenderThreadGL not available."); - } - - if (tinfo->m_contextSet.empty()) { - return; - } - AutoLock mutex(m_lock); - gfxstream::base::AutoWriteLock contextLock(m_contextStructureLock); - for (const HandleType contextHandle : tinfo->m_contextSet) { - m_contexts.erase(contextHandle); + if (m_emulationGl) { + m_emulationGl->drainRenderThreadContexts(); } - tinfo->m_contextSet.clear(); } -void FrameBuffer::Impl::drainGlRenderThreadSurfaces() { +void FrameBuffer::Impl::drainGlRenderThreadSurfaces() NO_THREAD_SAFETY_ANALYSIS { if (isShuttingDown()) { return; } - RenderThreadInfoGl* const tinfo = RenderThreadInfoGl::get(); - if (!tinfo) { - GFXSTREAM_FATAL("RenderThreadGL not available."); - } - - if (tinfo->m_windowSet.empty()) { - return; - } - - std::vector colorBuffersToCleanup; - AutoLock mutex(m_lock); - RecursiveScopedContextBind bind(getPbufferSurfaceContextHelper()); - for (const HandleType winHandle : tinfo->m_windowSet) { - const auto winIt = m_windows.find(winHandle); - if (winIt != m_windows.end()) { - if (const HandleType oldColorBufferHandle = winIt->second.second) { - if (!m_guestManagedColorBufferLifetime) { - if (m_refCountPipeEnabled) { - if (decColorBufferRefCountLocked(oldColorBufferHandle)) { - colorBuffersToCleanup.push_back(oldColorBufferHandle); - } - } else { - if (closeColorBufferLocked(oldColorBufferHandle)) { - colorBuffersToCleanup.push_back(oldColorBufferHandle); - } - } - } - m_windows.erase(winIt); - } - } + if (m_emulationGl) { + m_emulationGl->drainRenderThreadSurfaces(); } - tinfo->m_windowSet.clear(); } EmulationGl& FrameBuffer::Impl::getEmulationGl() { @@ -4493,6 +4192,8 @@ EmulationGl& FrameBuffer::Impl::getEmulationGl() { return *m_emulationGl; } +gl::EmulationGl* FrameBuffer::Impl::getEmulationGlPtr() { return m_emulationGl.get(); } + VkEmulation& FrameBuffer::Impl::getEmulationVk() { if (!m_emulationVk) { GFXSTREAM_FATAL("Vulkan emulation is not enabled."); @@ -4500,56 +4201,19 @@ VkEmulation& FrameBuffer::Impl::getEmulationVk() { return *m_emulationVk; } -EGLDisplay FrameBuffer::Impl::getDisplay() const { - ENSURE_GL_EMULATION_VALUE(nullptr); - return m_emulationGl->mEglDisplay; -} - -EGLSurface FrameBuffer::Impl::getWindowSurface() const { - ENSURE_GL_EMULATION_VALUE(0); - if (!m_emulationGl->mWindowSurface) { - return EGL_NO_SURFACE; - } - - const auto* displaySurfaceGl = - reinterpret_cast(m_emulationGl->mWindowSurface->getImpl()); - - return displaySurfaceGl->getSurface(); -} - -EGLContext FrameBuffer::Impl::getContext() const { - ENSURE_GL_EMULATION_VALUE(0); - return m_emulationGl->mEglContext; -} - -EGLContext FrameBuffer::Impl::getConfig() const { - ENSURE_GL_EMULATION_VALUE(nullptr); - return m_emulationGl->mEglConfig; +bool FrameBuffer::Impl::getRenderOpt(RenderOpt* opt) const { + ENSURE_GL_EMULATION_VALUE(false); + return m_emulationGl->getRenderOpt(opt); } EGLContext FrameBuffer::Impl::getGlobalEGLContext() const { ENSURE_GL_EMULATION_VALUE(0); - if (!m_emulationGl->mPbufferSurface) { - GFXSTREAM_FATAL("FrameBuffer pbuffer surface not available."); - } - - const auto* displaySurfaceGl = - reinterpret_cast(m_emulationGl->mPbufferSurface->getImpl()); - - return displaySurfaceGl->getContextForShareContext(); -} - -EmulatedEglContextPtr FrameBuffer::Impl::getContext_locked(HandleType p_context) { - return gfxstream::base::findOrDefault(m_contexts, p_context); -} - -EmulatedEglWindowSurfacePtr FrameBuffer::Impl::getWindowSurface_locked(HandleType p_windowsurface) { - return gfxstream::base::findOrDefault(m_windows, p_windowsurface).first; + return m_emulationGl->getGlobalEGLContext(); } TextureDraw* FrameBuffer::Impl::getTextureDraw() const { ENSURE_GL_EMULATION_VALUE(nullptr); - return m_emulationGl->mTextureDraw.get(); + return m_emulationGl->getTextureDraw(); } bool FrameBuffer::Impl::isFastBlitSupported() const { @@ -4563,136 +4227,42 @@ void FrameBuffer::Impl::disableFastBlitForTesting() { } HandleType FrameBuffer::Impl::createEmulatedEglImage(HandleType contextHandle, EGLenum target, - GLuint buffer) { + GLuint buffer) NO_THREAD_SAFETY_ANALYSIS { ENSURE_GL_EMULATION_VALUE(0); AutoLock mutex(m_lock); - - EmulatedEglContext* context = nullptr; - if (contextHandle) { - gfxstream::base::AutoWriteLock contextLock(m_contextStructureLock); - - auto it = m_contexts.find(contextHandle); - if (it == m_contexts.end()) { - GFXSTREAM_ERROR("Failed to find EmulatedEglContext:%d", contextHandle); - return 0; - } - - context = it->second.get(); - } - - auto image = m_emulationGl->createEmulatedEglImage(context, target, - reinterpret_cast(buffer)); - if (!image) { - GFXSTREAM_ERROR("Failed to create EmulatedEglImage"); - return 0; - } - - HandleType imageHandle = image->getHandle(); - - m_images[imageHandle] = std::move(image); - - RenderThreadInfo* tInfo = RenderThreadInfo::get(); - uint64_t puid = tInfo->m_puid; - if (puid) { - m_procOwnedEmulatedEglImages[puid].insert(imageHandle); - } - return imageHandle; + return m_emulationGl->createEmulatedEglImage(contextHandle, target, + reinterpret_cast(buffer)); } -bool FrameBuffer::Impl::destroyEmulatedEglImage(HandleType imageHandle) { +bool FrameBuffer::Impl::destroyEmulatedEglImage(HandleType imageHandle) NO_THREAD_SAFETY_ANALYSIS { ENSURE_GL_EMULATION_VALUE(false); AutoLock mutex(m_lock); - - auto imageIt = m_images.find(imageHandle); - if (imageIt == m_images.end()) { - GFXSTREAM_ERROR("Failed to find EmulatedEglImage:%d", imageHandle); - return false; - } - auto& image = imageIt->second; - - EGLBoolean success = image->destroy(); - m_images.erase(imageIt); - - RenderThreadInfo* tInfo = RenderThreadInfo::get(); - uint64_t puid = tInfo->m_puid; - if (puid) { - m_procOwnedEmulatedEglImages[puid].erase(imageHandle); - // We don't explicitly call m_procOwnedEmulatedEglImages.erase(puid) when the - // size reaches 0, since it could go between zero and one many times in - // the lifetime of a process. It will be cleaned up by - // cleanupProcGLObjects(puid) when the process is dead. - } - return (success == EGL_TRUE); + return m_emulationGl->destroyEmulatedEglImage(imageHandle); } -bool FrameBuffer::Impl::flushEmulatedEglWindowSurfaceColorBuffer(HandleType p_surface) { +bool FrameBuffer::Impl::flushEmulatedEglWindowSurfaceColorBuffer(HandleType p_surface) + NO_THREAD_SAFETY_ANALYSIS { + ENSURE_GL_EMULATION_VALUE(false); AutoLock mutex(m_lock); - - auto it = m_windows.find(p_surface); - if (it == m_windows.end()) { - GFXSTREAM_ERROR("FB::flushEmulatedEglWindowSurfaceColorBuffer: window handle %#x not found", - p_surface); - // bad surface handle - return false; - } - - EmulatedEglWindowSurface* surface = it->second.first.get(); - surface->flushColorBuffer(); - - return true; + return m_emulationGl->flushEmulatedEglWindowSurfaceColorBuffer(p_surface); } void FrameBuffer::Impl::fillGLESUsages(android_studio::EmulatorGLESUsages* usages) { - if (s_egl.eglFillUsages) { - s_egl.eglFillUsages(usages); + if (m_emulationGl) { + m_emulationGl->fillGlesUsages(usages); } } void* FrameBuffer::Impl::platformCreateSharedEglContext(void) { + ENSURE_GL_EMULATION_VALUE(nullptr); AutoLock lock(m_lock); - - EGLContext context = 0; - EGLSurface surface = 0; - createSharedTrivialContext(&context, &surface); - - void* underlyingContext = s_egl.eglGetNativeContextANDROID(getDisplay(), context); - if (!underlyingContext) { - GFXSTREAM_ERROR("Error: Underlying egl backend could not produce a native EGL context."); - return nullptr; - } - - m_platformEglContexts[underlyingContext] = {context, surface}; - -#if defined(__QNX__) - EGLDisplay currDisplay = eglGetCurrentDisplay(); - EGLSurface currRead = eglGetCurrentSurface(EGL_READ); - EGLSurface currDraw = eglGetCurrentSurface(EGL_DRAW); - EGLSurface currContext = eglGetCurrentContext(); - // Make this context current to ensure thread-state is initialized - s_egl.eglMakeCurrent(getDisplay(), surface, surface, context); - // Revert back to original state - s_egl.eglMakeCurrent(currDisplay, currRead, currDraw, currContext); -#endif - - return underlyingContext; + return m_emulationGl->platformCreateSharedEglContext(); } bool FrameBuffer::Impl::platformDestroySharedEglContext(void* underlyingContext) { + ENSURE_GL_EMULATION_VALUE(false); AutoLock lock(m_lock); - - auto it = m_platformEglContexts.find(underlyingContext); - if (it == m_platformEglContexts.end()) { - GFXSTREAM_ERROR( - "Error: Could not find underlying egl context %p (perhaps already destroyed?)", - underlyingContext); - return false; - } - - destroySharedTrivialContext(it->second.context, it->second.surface); - - m_platformEglContexts.erase(it); - - return true; + return m_emulationGl->platformDestroySharedEglContext(underlyingContext); } bool FrameBuffer::Impl::flushColorBufferFromGl(HandleType colorBufferHandle) { @@ -4716,29 +4286,26 @@ bool FrameBuffer::Impl::invalidateColorBufferForGl(HandleType colorBufferHandle) ContextHelper* FrameBuffer::Impl::getPbufferSurfaceContextHelper() const { ENSURE_GL_EMULATION_VALUE(nullptr); - if (!m_emulationGl->mPbufferSurface) { + auto* pbufferSurface = m_emulationGl->getPbufferSurface(); + if (!pbufferSurface) { GFXSTREAM_FATAL("EGL emulation pbuffer surface not available."); } const auto* displaySurfaceGl = - reinterpret_cast(m_emulationGl->mPbufferSurface->getImpl()); + reinterpret_cast(pbufferSurface->getImpl()); return displaySurfaceGl->getContextHelper(); } -bool FrameBuffer::Impl::bindColorBufferToTexture(HandleType p_colorbuffer) { +bool FrameBuffer::Impl::bindColorBufferToTexture(HandleType p_colorbuffer) + NO_THREAD_SAFETY_ANALYSIS { + ENSURE_GL_EMULATION_VALUE(false); AutoLock mutex(m_lock); - - ColorBufferPtr colorBuffer = - std::static_pointer_cast(findColorBuffer(p_colorbuffer)); - if (!colorBuffer) { - // bad colorbuffer handle - return false; - } - - return colorBuffer->glOpBindToTexture(); + return m_emulationGl->bindColorBufferToTexture(p_colorbuffer); } -bool FrameBuffer::Impl::bindColorBufferToTexture2(HandleType p_colorbuffer) { +bool FrameBuffer::Impl::bindColorBufferToTexture2(HandleType p_colorbuffer) + NO_THREAD_SAFETY_ANALYSIS { + ENSURE_GL_EMULATION_VALUE(false); // This is only called when using multi window display // It will deadlock when posting from main thread. std::unique_ptr mutex; @@ -4746,239 +4313,67 @@ bool FrameBuffer::Impl::bindColorBufferToTexture2(HandleType p_colorbuffer) { mutex = std::make_unique(m_lock); } - ColorBufferPtr colorBuffer = - std::static_pointer_cast(findColorBuffer(p_colorbuffer)); - if (!colorBuffer) { - // bad colorbuffer handle - return false; - } - - if (!colorBuffer->canUseGlOps()) { - // cannot call glOpBindToTexture2 without a valid gl colorbuffer - static bool errorReported = false; - if (!errorReported) { - GFXSTREAM_ERROR("%s: Cannot use GL colorbuffer operations", __func__); - errorReported = true; - } - return false; - } - - return colorBuffer->glOpBindToTexture2(); + return m_emulationGl->bindColorBufferToTexture2(p_colorbuffer); } -bool FrameBuffer::Impl::bindColorBufferToRenderbuffer(HandleType p_colorbuffer) { +bool FrameBuffer::Impl::bindColorBufferToRenderbuffer(HandleType p_colorbuffer) + NO_THREAD_SAFETY_ANALYSIS { + ENSURE_GL_EMULATION_VALUE(false); AutoLock mutex(m_lock); - - ColorBufferPtr colorBuffer = - std::static_pointer_cast(findColorBuffer(p_colorbuffer)); - if (!colorBuffer) { - // bad colorbuffer handle - return false; - } - - return colorBuffer->glOpBindToRenderbuffer(); + return m_emulationGl->bindColorBufferToRenderbuffer(p_colorbuffer); } bool FrameBuffer::Impl::bindContext(HandleType p_context, HandleType p_drawSurface, - HandleType p_readSurface) { + HandleType p_readSurface) NO_THREAD_SAFETY_ANALYSIS { + ENSURE_GL_EMULATION_VALUE(false); if (m_shuttingDown) { return false; } AutoLock mutex(m_lock); - EmulatedEglWindowSurfacePtr draw, read; - EmulatedEglContextPtr ctx; - - // - // if this is not an unbind operation - make sure all handles are good - // - if (p_context || p_drawSurface || p_readSurface) { - ctx = getContext_locked(p_context); - if (!ctx) return false; - auto drawWindowIt = m_windows.find(p_drawSurface); - if (drawWindowIt == m_windows.end()) { - // bad surface handle - return false; - } - draw = (*drawWindowIt).second.first; - - if (p_readSurface != p_drawSurface) { - auto readWindowIt = m_windows.find(p_readSurface); - if (readWindowIt == m_windows.end()) { - // bad surface handle - return false; - } - read = (*readWindowIt).second.first; - } else { - read = draw; - } - } else { - // if unbind operation, sweep color buffers + if (!p_context && !p_drawSurface && !p_readSurface) { sweepColorBuffersLocked(); } - if (!s_egl.eglMakeCurrent(getDisplay(), draw ? draw->getEGLSurface() : EGL_NO_SURFACE, - read ? read->getEGLSurface() : EGL_NO_SURFACE, - ctx ? ctx->getEGLContext() : EGL_NO_CONTEXT)) { - GFXSTREAM_ERROR("eglMakeCurrent failed"); - return false; - } - - // - // Bind the surface(s) to the context - // - RenderThreadInfoGl* const tinfo = RenderThreadInfoGl::get(); - if (!tinfo) { - GFXSTREAM_FATAL("RenderThreadGl not available."); - } - - EmulatedEglWindowSurfacePtr bindDraw, bindRead; - if (draw.get() == NULL && read.get() == NULL) { - // Unbind the current read and draw surfaces from the context - bindDraw = tinfo->currDrawSurf; - bindRead = tinfo->currReadSurf; - } else { - bindDraw = draw; - bindRead = read; - } - - if (bindDraw.get() != NULL && bindRead.get() != NULL) { - if (bindDraw.get() != bindRead.get()) { - bindDraw->bind(ctx, EmulatedEglWindowSurface::BIND_DRAW); - bindRead->bind(ctx, EmulatedEglWindowSurface::BIND_READ); - } else { - bindDraw->bind(ctx, EmulatedEglWindowSurface::BIND_READDRAW); - } - } - - // - // update thread info with current bound context - // - tinfo->currContext = ctx; - tinfo->currDrawSurf = draw; - tinfo->currReadSurf = read; - if (ctx) { - if (ctx->clientVersion() > GLESApi_CM) - tinfo->m_gl2Dec.setContextData(&ctx->decoderContextData()); - else - tinfo->m_glDec.setContextData(&ctx->decoderContextData()); - } else { - tinfo->m_glDec.setContextData(NULL); - tinfo->m_gl2Dec.setContextData(NULL); - } - return true; + return m_emulationGl->bindContext(p_context, p_drawSurface, p_readSurface); } void FrameBuffer::Impl::createYUVTextures(uint32_t type, uint32_t count, int width, int height, - uint32_t* output) { - auto formatOpt = GetGfxstreamFormat(m_features, static_cast(type)); - if (!formatOpt) { - GFXSTREAM_ERROR("Unsupported framework format %d", type); - return; - } - auto format = *formatOpt; - + uint32_t* output) NO_THREAD_SAFETY_ANALYSIS { + ENSURE_GL_EMULATION_VOID(); AutoLock mutex(m_lock); - auto contextHelper = getPbufferSurfaceContextHelper(); - if (!contextHelper) { - // This should not be called in vulkan-only mode - GFXSTREAM_ERROR("%s: invalid pbuffer surface context", __func__); - return; - } - RecursiveScopedContextBind bind(contextHelper); - if (!bind.isOk()) { - GFXSTREAM_ERROR("%s: could not bind context helper", __func__); - return; - } - for (uint32_t i = 0; i < count; ++i) { - if (format == GfxstreamFormat::NV12 || format == GfxstreamFormat::NV21) { - YUVConverter::createYUVGLTex(GL_TEXTURE0, width, height, format, YuvPlane::Y, &output[2 * i]); - YUVConverter::createYUVGLTex(GL_TEXTURE1, width / 2, height / 2, format, YuvPlane::UV, &output[2 * i + 1]); - } else if (format == GfxstreamFormat::YV12 || format == GfxstreamFormat::YV21) { - YUVConverter::createYUVGLTex(GL_TEXTURE0, width, height, format, YuvPlane::Y, &output[3 * i]); - YUVConverter::createYUVGLTex(GL_TEXTURE1, width / 2, height / 2, format, YuvPlane::U, &output[3 * i + 1]); - YUVConverter::createYUVGLTex(GL_TEXTURE2, width / 2, height / 2, format, YuvPlane::V, &output[3 * i + 2]); - } - } + m_emulationGl->createYUVTextures(type, count, width, height, output); } -void FrameBuffer::Impl::destroyYUVTextures(uint32_t type, uint32_t count, uint32_t* textures) { - auto formatOpt = GetGfxstreamFormat(m_features, static_cast(type)); - if (!formatOpt) { - GFXSTREAM_ERROR("Unsupported framework format %d", type); - return; - } - auto format = *formatOpt; - +void FrameBuffer::Impl::destroyYUVTextures(uint32_t type, uint32_t count, + uint32_t* textures) NO_THREAD_SAFETY_ANALYSIS { + ENSURE_GL_EMULATION_VOID(); AutoLock mutex(m_lock); - RecursiveScopedContextBind bind(getPbufferSurfaceContextHelper()); - if (format == GfxstreamFormat::NV12 || format == GfxstreamFormat::NV21) { - s_gles2.glDeleteTextures(2 * count, textures); - } else if (format == GfxstreamFormat::YV12 || format == GfxstreamFormat::YV21) { - s_gles2.glDeleteTextures(3 * count, textures); - } + m_emulationGl->destroyYUVTextures(type, count, textures); } -void FrameBuffer::Impl::updateYUVTextures(uint32_t type, uint32_t* textures, void* privData, void* func) { - auto formatOpt = GetGfxstreamFormat(m_features, static_cast(type)); - if (!formatOpt) { - GFXSTREAM_ERROR("Unsupported framework format %d", type); - return; - } - auto format = *formatOpt; - +void FrameBuffer::Impl::updateYUVTextures(uint32_t type, uint32_t* textures, void* privData, + void* func) NO_THREAD_SAFETY_ANALYSIS { + ENSURE_GL_EMULATION_VOID(); AutoLock mutex(m_lock); - RecursiveScopedContextBind bind(getPbufferSurfaceContextHelper()); - - yuv_updater_t updater = (yuv_updater_t)func; - uint32_t gtextures[3] = {0, 0, 0}; - - if (format == GfxstreamFormat::NV12 || format == GfxstreamFormat::NV21) { - gtextures[0] = s_gles2.glGetGlobalTexName(textures[0]); - gtextures[1] = s_gles2.glGetGlobalTexName(textures[1]); - } else if (format == GfxstreamFormat::YV12 || format == GfxstreamFormat::YV21) { - gtextures[0] = s_gles2.glGetGlobalTexName(textures[0]); - gtextures[1] = s_gles2.glGetGlobalTexName(textures[1]); - gtextures[2] = s_gles2.glGetGlobalTexName(textures[2]); - } - -#ifdef __APPLE__ - EGLContext prevContext = s_egl.eglGetCurrentContext(); - auto mydisp = EglGlobalInfo::getInstance()->getDisplayFromDisplayType(EGL_DEFAULT_DISPLAY); - void* nativecontext = mydisp->getLowLevelContext(prevContext); - struct MediaNativeCallerData callerdata; - callerdata.ctx = nativecontext; - callerdata.converter = nsConvertVideoFrameToNV12Textures; - void* pcallerdata = &callerdata; -#else - void* pcallerdata = nullptr; -#endif - - updater(privData, type, gtextures, pcallerdata); + m_emulationGl->updateYUVTextures(type, textures, privData, func); } void FrameBuffer::Impl::swapTexturesAndUpdateColorBuffer(uint32_t p_colorbuffer, int x, int y, int width, int height, uint32_t format, uint32_t type, uint32_t texturesType, uint32_t* textures) { - auto texturesFormatOpt = GetGfxstreamFormat(m_features, (FrameworkFormat)texturesType); - if (!texturesFormatOpt) { - GFXSTREAM_ERROR("Unsupported framework format %d", texturesType); + AutoLock mutex(m_lock); + IColorBufferRef colorBuffer = findColorBuffer(p_colorbuffer); + if (!colorBuffer) { + // bad colorbuffer handle return; } - auto texturesFormat = *texturesFormatOpt; - - { - AutoLock mutex(m_lock); - ColorBufferPtr colorBuffer = - std::static_pointer_cast(findColorBuffer(p_colorbuffer)); - if (!colorBuffer) { - // bad colorbuffer handle - return; - } - colorBuffer->glOpSwapYuvTexturesAndUpdate(format, type, texturesFormat, textures); - } +#if GFXSTREAM_ENABLE_HOST_GLES + m_emulationGl->swapTexturesAndUpdateColorBuffer(colorBuffer.get(), format, type, texturesType, + textures); +#endif } void FrameBuffer::Impl::asyncWaitForGpuWithCb(uint64_t eglsync, FenceCompletionCallback cb) { @@ -5341,7 +4736,7 @@ int FrameBuffer::getScreenshot(unsigned int nChannels, unsigned int* width, unsi } int FrameBuffer::getColorBufferScreenshot( - ColorBuffer* cb, int targetWidth, int targetHeight, int skinRotation, + IColorBuffer* cb, int targetWidth, int targetHeight, int skinRotation, GfxstreamFormat pixelsFormat, void* outPixels, const Rect& rect, const std::optional>& colorTransform) { return mImpl->getColorBufferScreenshot(cb, targetWidth, targetHeight, skinRotation, @@ -5473,6 +4868,10 @@ int32_t FrameBuffer::mapGpaToBufferHandle(uint32_t bufferHandle, uint64_t gpa, u #if GFXSTREAM_ENABLE_HOST_GLES +gl::EmulationGl* FrameBuffer::getEmulationGl() { + return mImpl ? mImpl->getEmulationGlPtr() : nullptr; +} + HandleType FrameBuffer::getEmulatedEglWindowSurfaceColorBufferHandle(HandleType p_surface) { return mImpl->getEmulatedEglWindowSurfaceColorBufferHandle(p_surface); } @@ -5553,17 +4952,7 @@ void FrameBuffer::drainGlRenderThreadContexts() { mImpl->drainGlRenderThreadCont void FrameBuffer::drainGlRenderThreadSurfaces() { mImpl->drainGlRenderThreadSurfaces(); } -void FrameBuffer::postLoadRenderThreadContextSurfacePtrs() { - mImpl->postLoadRenderThreadContextSurfacePtrs(); -} - -EGLDisplay FrameBuffer::getDisplay() const { return mImpl->getDisplay(); } - -EGLSurface FrameBuffer::getWindowSurface() const { return mImpl->getWindowSurface(); } - -EGLContext FrameBuffer::getContext() const { return mImpl->getContext(); } - -EGLConfig FrameBuffer::getConfig() const { return mImpl->getConfig(); } +bool FrameBuffer::getRenderOpt(RenderOpt* opt) const { return mImpl->getRenderOpt(opt); } EGLContext FrameBuffer::getGlobalEGLContext() const { return mImpl->getGlobalEGLContext(); } diff --git a/host/frame_buffer.h b/host/frame_buffer.h index 9d0357417..2c1586b2b 100644 --- a/host/frame_buffer.h +++ b/host/frame_buffer.h @@ -30,7 +30,6 @@ #include #include "buffer.h" -#include "color_buffer.h" #include "gfxstream/AsyncResult.h" #include "gfxstream/EventNotificationSupport.h" #include "gfxstream/host/color_buffer_interface.h" @@ -58,6 +57,7 @@ #define FB_MAX_SWAP_INTERVAL 7 namespace gfxstream { +struct RenderOpt; namespace host { class GlobalState; @@ -366,7 +366,7 @@ class FrameBuffer : public gfxstream::base::EventNotificationSupport>& colorTransform); @@ -441,6 +441,7 @@ class FrameBuffer : public gfxstream::base::EventNotificationSupport -#include #include #include @@ -104,7 +102,7 @@ class FrameBufferTest : public ::testing::Test { EXPECT_EQ(EGL_SUCCESS, egl->eglGetError()); mRenderThreadInfo = new RenderThreadInfo(); - mRenderThreadInfo->initGl(mFb->getGlobalState()); + mRenderThreadInfo->initGl(mFb->getEmulationGl()); } virtual void TearDown() override { diff --git a/host/gl/emulation_gl.cpp b/host/gl/emulation_gl.cpp index ef96d9570..45287777e 100644 --- a/host/gl/emulation_gl.cpp +++ b/host/gl/emulation_gl.cpp @@ -19,19 +19,32 @@ #include #include -#include "display_surface_gl.h" -#include "gles_version_detector.h" -#include "common/gles_context.h" #include "OpenGLESDispatch/DispatchTables.h" #include "OpenGLESDispatch/EGLDispatch.h" #include "OpenGLESDispatch/GLESv2Dispatch.h" #include "OpenGLESDispatch/OpenGLDispatchLoader.h" -#include "render_thread_info_gl.h" +#include "common/gles_context.h" +#include "display_surface_gl.h" #include "gfxstream/ThreadAnnotations.h" #include "gfxstream/common/logging.h" +#include "gfxstream/host/color_buffer_interface.h" #include "gfxstream/host/driver_info.h" +#include "gfxstream/host/global_state.h" #include "gfxstream/host/renderer_operations.h" +#include "gfxstream/host/stream_utils.h" #include "gfxstream/misc/StringUtils.h" +#include "gles_version_detector.h" +#include "render-utils/MediaNative.h" +#include "render-utils/RenderLib.h" +#include "render_thread_info_gl.h" +#include "yuv_converter.h" + +namespace gfxstream { +namespace host { +std::optional GetGfxstreamFormat(const FeatureSet& features, + FrameworkFormat format); +} +} // namespace gfxstream namespace gfxstream { namespace host { @@ -39,6 +52,34 @@ namespace gl { namespace { using gfxstream::host::GfxstreamFormat; +using gfxstream::host::loadCollection; +using gfxstream::host::saveCollection; + +template +static void saveProcOwnedCollection(gfxstream::Stream* stream, const Collection& c) { + const int count = std::count_if( + c.begin(), c.end(), + [](const typename Collection::value_type& pair) { return !pair.second.empty(); }); + stream->putBe32(count); + for (const auto& pair : c) { + if (pair.second.empty()) { + continue; + } + stream->putBe64(pair.first); + saveCollection(stream, pair.second, + [](gfxstream::Stream* s, HandleType h) { s->putBe32(h); }); + } +} + +template +static void loadProcOwnedCollection(gfxstream::Stream* stream, Collection* c) { + loadCollection(stream, c, [](gfxstream::Stream* stream) -> typename Collection::value_type { + const int processId = stream->getBe64(); + typename Collection::mapped_type handles; + loadCollection(stream, &handles, [](gfxstream::Stream* s) { return s->getBe32(); }); + return {processId, std::move(handles)}; + }); +} #ifdef ENABLE_GFXSTREAM_DEBUG @@ -247,12 +288,14 @@ bool EmulationGl::initDispatchers(bool eglOnEgl) { std::unique_ptr EmulationGl::create(uint32_t width, uint32_t height, const gfxstream::host::FeatureSet& features, - bool allowWindowSurface) { + bool allowWindowSurface, + GlobalState* globalState) { std::unique_ptr emulationGl(new EmulationGl()); emulationGl->mFeatures = features; emulationGl->mWidth = width; emulationGl->mHeight = height; + emulationGl->mGlobalState = globalState; emulationGl->mEglDisplay = s_egl.eglGetDisplay(EGL_DEFAULT_DISPLAY); if (emulationGl->mEglDisplay == EGL_NO_DISPLAY) { @@ -597,6 +640,10 @@ EmulationGl::~EmulationGl() { } } + for (auto it : mPlatformEglContexts) { + destroySharedTrivialContext(it.second.context, it.second.surface); + } + if (mEglDisplay != EGL_NO_DISPLAY) { s_egl.eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); if (mEglContext != EGL_NO_CONTEXT) { @@ -743,6 +790,16 @@ ContextHelper* EmulationGl::getColorBufferContextHelper() { return surfaceGl->getContextHelper(); } +ContextHelper* EmulationGl::getPbufferSurfaceContextHelper() const { + if (!mPbufferSurface) { + GFXSTREAM_FATAL("EGL emulation pbuffer surface not available."); + } + const auto* displaySurfaceGl = + reinterpret_cast(mPbufferSurface->getImpl()); + + return displaySurfaceGl->getContextHelper(); +} + std::unique_ptr EmulationGl::createBuffer(uint64_t size, HandleType handle) { return BufferGl::create(size, handle, getColorBufferContextHelper()); } @@ -782,11 +839,9 @@ std::unique_ptr EmulationGl::loadColorBuffer(gfxstream::Stream* s mPixelReadFormats); } -std::unique_ptr EmulationGl::createEmulatedEglContext( - uint32_t emulatedEglConfigIndex, - const EmulatedEglContext* sharedContext, - GLESApi api, - HandleType handle) { +std::unique_ptr EmulationGl::createEmulatedEglContextImpl( + uint32_t emulatedEglConfigIndex, const EmulatedEglContext* sharedContext, GLESApi api, + HandleType handle) { if (!mEmulatedEglConfigs) { GFXSTREAM_ERROR("EmulatedEglConfigs unavailable."); return nullptr; @@ -809,29 +864,75 @@ std::unique_ptr EmulationGl::loadEmulatedEglContext( return EmulatedEglContext::onLoad(stream, mEglDisplay); } -std::unique_ptr EmulationGl::createEmulatedEglFenceSync( - EGLenum type, - int destroyWhenSignaled) { +uint64_t EmulationGl::createEmulatedEglFenceSync(EGLenum type, int destroyWhenSignaled) { + RenderThreadInfoGl* const info = RenderThreadInfoGl::get(); + if (!info) { + GFXSTREAM_FATAL("RenderThreadGL not available."); + } + if (!info->currContext) { + uint32_t syncContext; + uint32_t syncSurface; + createTrivialContext(0, // There is no context to share. + &syncContext, &syncSurface); + bindContext(syncContext, syncSurface, syncSurface); + // This context is then cleaned up when the render thread exits. + } + const bool hasNativeFence = type == EGL_SYNC_NATIVE_FENCE_ANDROID; - return EmulatedEglFenceSync::create(mEglDisplay, - hasNativeFence, - destroyWhenSignaled); + auto sync = EmulatedEglFenceSync::create(mEglDisplay, hasNativeFence, destroyWhenSignaled); + return sync ? (uint64_t)(uintptr_t)sync.release() : 0; +} +HandleType EmulationGl::createEmulatedEglImage(HandleType contextHandle, EGLenum target, + EGLClientBuffer buffer) { + EGLContext eglContext = EGL_NO_CONTEXT; + if (contextHandle) { + auto it = mContexts.find(contextHandle); + if (it != mContexts.end()) { + eglContext = it->second->getEGLContext(); + } else { + GFXSTREAM_ERROR("Failed to find EmulatedEglContext:%d", contextHandle); + return 0; + } + } + auto image = EmulatedEglImage::create(mEglDisplay, eglContext, target, buffer); + if (!image) { + GFXSTREAM_ERROR("Failed to create EmulatedEglImage"); + return 0; + } + + HandleType imageHandle = image->getHandle(); + mImages[imageHandle] = std::move(image); + + RenderThreadInfoGl* tInfo = RenderThreadInfoGl::get(); + uint64_t puid = tInfo->m_puid; + if (puid) { + mProcOwnedEmulatedEglImages[puid].insert(imageHandle); + } + return imageHandle; } -std::unique_ptr EmulationGl::createEmulatedEglImage( - EmulatedEglContext* context, - EGLenum target, - EGLClientBuffer buffer) { - EGLContext eglContext = context ? context->getEGLContext() : EGL_NO_CONTEXT; - return EmulatedEglImage::create(mEglDisplay, eglContext, target, buffer); +bool EmulationGl::destroyEmulatedEglImage(HandleType imageHandle) { + auto imageIt = mImages.find(imageHandle); + if (imageIt == mImages.end()) { + GFXSTREAM_ERROR("Failed to find EmulatedEglImage:%d", imageHandle); + return false; + } + auto& image = imageIt->second; + + EGLBoolean success = image->destroy(); + mImages.erase(imageIt); + + RenderThreadInfoGl* tInfo = RenderThreadInfoGl::get(); + uint64_t puid = tInfo->m_puid; + if (puid) { + mProcOwnedEmulatedEglImages[puid].erase(imageHandle); + } + return (success == EGL_TRUE); } -std::unique_ptr EmulationGl::createEmulatedEglWindowSurface( - uint32_t emulatedConfigIndex, - uint32_t width, - uint32_t height, - HandleType handle) { +std::unique_ptr EmulationGl::createEmulatedEglWindowSurfaceImpl( + uint32_t emulatedConfigIndex, uint32_t width, uint32_t height, HandleType handle) { if (!mEmulatedEglConfigs) { GFXSTREAM_ERROR("EmulatedEglConfigs unavailable."); return nullptr; @@ -854,6 +955,720 @@ std::unique_ptr EmulationGl::loadEmulatedEglWindowSurf return EmulatedEglWindowSurface::onLoad(stream, mEglDisplay, colorBufferLookup, contexts); } +HandleType EmulationGl::createEmulatedEglContext(uint32_t emulatedConfigIndex, + HandleType shareContextHandle, GLESApi api) { + gfxstream::base::AutoWriteLock contextLock(mContextStructureLock); + HandleType handle = mGlobalState->genHandleLocked(); + + EmulatedEglContextPtr shareContext = nullptr; + if (shareContextHandle != 0) { + auto shareContextIt = mContexts.find(shareContextHandle); + if (shareContextIt == mContexts.end()) { + GFXSTREAM_ERROR("Failed to find share EmulatedEglContext:%d", shareContextHandle); + return 0; + } + shareContext = shareContextIt->second; + } + + auto context = + createEmulatedEglContextImpl(emulatedConfigIndex, shareContext.get(), api, handle); + if (!context) { + GFXSTREAM_ERROR("Failed to create EmulatedEglContext."); + return 0; + } + + mContexts[handle] = std::move(context); + + RenderThreadInfoGl* tinfo = RenderThreadInfoGl::get(); + if (!tinfo) { + GFXSTREAM_FATAL("RenderThreadInfoGl not available."); + } + uint64_t puid = tinfo->m_puid; + if (puid) { + mProcOwnedEmulatedEglContexts[puid].insert(handle); + } + return handle; +} + +void EmulationGl::destroyEmulatedEglContext(HandleType contextHandle) { + gfxstream::base::AutoWriteLock contextLock(mContextStructureLock); + auto it = mContexts.find(contextHandle); + if (it == mContexts.end()) { + GFXSTREAM_ERROR("Failed to find EmulatedEglContext:%d", contextHandle); + return; + } + mContexts.erase(it); + + RenderThreadInfoGl* tinfo = RenderThreadInfoGl::get(); + if (!tinfo) { + GFXSTREAM_FATAL("RenderThreadInfoGl not available."); + } + uint64_t puid = tinfo->m_puid; + if (puid) { + auto procIte = mProcOwnedEmulatedEglContexts.find(puid); + if (procIte != mProcOwnedEmulatedEglContexts.end()) { + procIte->second.erase(contextHandle); + } + } else { + tinfo->m_contextSet.erase(contextHandle); + } +} + +HandleType EmulationGl::createEmulatedEglWindowSurface(uint32_t emulatedConfigIndex, uint32_t width, + uint32_t height) { + HandleType handle = mGlobalState->genHandleLocked(); + auto window = createEmulatedEglWindowSurfaceImpl(emulatedConfigIndex, width, height, handle); + if (!window) { + GFXSTREAM_ERROR("Failed to create EmulatedEglWindowSurface."); + return 0; + } + + mWindows[handle] = {std::move(window), 0}; + + RenderThreadInfoGl* info = RenderThreadInfoGl::get(); + if (!info) { + GFXSTREAM_FATAL("RenderThreadInfoGl not available."); + } + + uint64_t puid = info->m_puid; + if (puid) { + mProcOwnedEmulatedEglWindowSurfaces[puid].insert(handle); + } else { + info->m_windowSet.insert(handle); + } + + return handle; +} + +std::vector EmulationGl::destroyEmulatedEglWindowSurface(HandleType surfaceHandle) { + std::vector colorBuffersToCleanUp; + const auto w = mWindows.find(surfaceHandle); + if (w != mWindows.end()) { + RecursiveScopedContextBind bind(getColorBufferContextHelper()); + if (w->second.second != 0) { + colorBuffersToCleanUp.push_back(w->second.second); + } + mWindows.erase(w); + RenderThreadInfoGl* tinfo = RenderThreadInfoGl::get(); + if (!tinfo) { + GFXSTREAM_FATAL("RenderThreadInfoGl not available."); + } + uint64_t puid = tinfo->m_puid; + if (puid) { + auto ite = mProcOwnedEmulatedEglWindowSurfaces.find(puid); + if (ite != mProcOwnedEmulatedEglWindowSurfaces.end()) { + ite->second.erase(surfaceHandle); + } + } else { + tinfo->m_windowSet.erase(surfaceHandle); + } + } + return colorBuffersToCleanUp; +} + +bool EmulationGl::isHandleInUse(HandleType handle) const { + return mContexts.find(handle) != mContexts.end() || mWindows.find(handle) != mWindows.end(); +} + +EmulatedEglContextPtr EmulationGl::getContext(HandleType contextHandle) { + return gfxstream::base::findOrDefault(mContexts, contextHandle); +} + +EmulatedEglWindowSurfacePtr EmulationGl::getWindowSurface(HandleType surfaceHandle) { + return gfxstream::base::findOrDefault(mWindows, surfaceHandle).first; +} + +bool EmulationGl::bindColorBufferToTexture(HandleType colorBufferHandle) { + IColorBufferRef cb = mGlobalState->findColorBuffer(colorBufferHandle); + if (!cb) return false; + cb->touch(); + auto cbGl = cb->getColorBufferGl(); + if (!cbGl) return false; + return cbGl->bindToTexture(); +} + +bool EmulationGl::bindColorBufferToTexture2(HandleType colorBufferHandle) { + IColorBufferRef cb = mGlobalState->findColorBuffer(colorBufferHandle); + if (!cb) return false; + cb->touch(); + auto cbGl = cb->getColorBufferGl(); + if (!cbGl) return false; + return cbGl->bindToTexture2(); +} + +bool EmulationGl::bindColorBufferToRenderbuffer(HandleType colorBufferHandle) { + IColorBufferRef cb = mGlobalState->findColorBuffer(colorBufferHandle); + if (!cb) return false; + cb->touch(); + auto cbGl = cb->getColorBufferGl(); + if (!cbGl) return false; + return cbGl->bindToRenderbuffer(); +} + +bool EmulationGl::bindContext(HandleType contextHandle, HandleType drawSurfaceHandle, + HandleType readSurfaceHandle) { + EmulatedEglWindowSurfacePtr draw = nullptr; + EmulatedEglWindowSurfacePtr read = nullptr; + EmulatedEglContextPtr ctx = nullptr; + + if (contextHandle || drawSurfaceHandle || readSurfaceHandle) { + ctx = getContext(contextHandle); + if (!ctx) return false; + + auto drawWindowIt = mWindows.find(drawSurfaceHandle); + if (drawWindowIt == mWindows.end()) { + return false; + } + draw = drawWindowIt->second.first; + + if (readSurfaceHandle != drawSurfaceHandle) { + auto readWindowIt = mWindows.find(readSurfaceHandle); + if (readWindowIt == mWindows.end()) { + return false; + } + read = readWindowIt->second.first; + } else { + read = draw; + } + } + + if (!s_egl.eglMakeCurrent(mEglDisplay, draw ? draw->getEGLSurface() : EGL_NO_SURFACE, + read ? read->getEGLSurface() : EGL_NO_SURFACE, + ctx ? ctx->getEGLContext() : EGL_NO_CONTEXT)) { + GFXSTREAM_ERROR("eglMakeCurrent failed"); + return false; + } + + RenderThreadInfoGl* const tinfo = RenderThreadInfoGl::get(); + if (!tinfo) { + GFXSTREAM_FATAL("RenderThreadGl not available."); + } + + EmulatedEglWindowSurfacePtr bindDraw, bindRead; + if (draw.get() == NULL && read.get() == NULL) { + bindDraw = tinfo->currDrawSurf; + bindRead = tinfo->currReadSurf; + } else { + bindDraw = draw; + bindRead = read; + } + + if (bindDraw.get() != NULL && bindRead.get() != NULL) { + if (bindDraw.get() != bindRead.get()) { + bindDraw->bind(ctx, EmulatedEglWindowSurface::BIND_DRAW); + bindRead->bind(ctx, EmulatedEglWindowSurface::BIND_READ); + } else { + bindDraw->bind(ctx, EmulatedEglWindowSurface::BIND_READDRAW); + } + } + + tinfo->currContext = ctx; + tinfo->currDrawSurf = draw; + tinfo->currReadSurf = read; + if (ctx) { + if (ctx->clientVersion() > GLESApi_CM) + tinfo->m_gl2Dec.setContextData(&ctx->decoderContextData()); + else + tinfo->m_glDec.setContextData(&ctx->decoderContextData()); + } else { + tinfo->m_glDec.setContextData(NULL); + tinfo->m_gl2Dec.setContextData(NULL); + } + return true; +} + +void EmulationGl::preSave(Stream* stream, const gfxstream::ITextureSaverPtr& textureSaver) { + if (s_egl.eglPreSaveContext && s_egl.eglSaveAllImages) { + for (const auto& ctx : mContexts) { + s_egl.eglPreSaveContext(mEglDisplay, ctx.second->getEGLContext(), stream); + } + s_egl.eglSaveAllImages(mEglDisplay, stream, &textureSaver); + } +} + +void EmulationGl::saveContexts(Stream* stream) { + saveCollection(stream, mContexts, [](Stream* s, const EmulatedEglContextMap::value_type& pair) { + pair.second->onSave(s); + }); +} + +void EmulationGl::saveWindowSurfaces(Stream* stream) { + saveCollection(stream, mWindows, + [](Stream* s, const EmulatedEglWindowSurfaceMap::value_type& pair) { + pair.second.first->onSave(s); + s->putBe32(pair.second.second); + }); +} + +void EmulationGl::saveProcOwnedWindowSurfaces(Stream* stream) { + saveProcOwnedCollection(stream, mProcOwnedEmulatedEglWindowSurfaces); +} + +void EmulationGl::saveProcOwnedContexts(Stream* stream) { + saveProcOwnedCollection(stream, mProcOwnedEmulatedEglContexts); +} + +void EmulationGl::saveProcOwnedImages(Stream* stream) { + saveProcOwnedCollection(stream, mProcOwnedEmulatedEglImages); +} + +bool EmulationGl::loadContexts(Stream* stream) { + loadCollection(stream, &mContexts, [this](Stream* stream) -> EmulatedEglContextMap::value_type { + auto context = loadEmulatedEglContext(stream); + auto contextHandle = context ? context->getHndl() : 0; + return {contextHandle, std::move(context)}; + }); + assert(!gfxstream::base::find(mContexts, 0)); + return true; +} + +bool EmulationGl::loadWindowSurfaces( + Stream* stream, const std::function& colorBufferLookup) { + loadCollection( + stream, &mWindows, + [this, &colorBufferLookup](Stream* stream) -> EmulatedEglWindowSurfaceMap::value_type { + auto window = loadEmulatedEglWindowSurface(stream, colorBufferLookup, mContexts); + + HandleType handle = window->getHndl(); + HandleType colorBufferHandle = stream->getBe32(); + return {handle, {std::move(window), colorBufferHandle}}; + }); + return true; +} + +void EmulationGl::loadProcOwnedWindowSurfaces(Stream* stream) { + loadProcOwnedCollection(stream, &mProcOwnedEmulatedEglWindowSurfaces); +} + +void EmulationGl::loadProcOwnedContexts(Stream* stream) { + loadProcOwnedCollection(stream, &mProcOwnedEmulatedEglContexts); +} + +void EmulationGl::loadProcOwnedImages(Stream* stream) { + loadProcOwnedCollection(stream, &mProcOwnedEmulatedEglImages); +} + +void EmulationGl::loadAllImages(Stream* stream, const gfxstream::ITextureLoaderPtr& textureLoader) { + if (s_egl.eglLoadAllImages) { + s_egl.eglLoadAllImages(mEglDisplay, stream, &textureLoader); + } +} + +void EmulationGl::postLoad(Stream* stream) { + if (s_egl.eglPostLoadAllImages) { + s_egl.eglPostLoadAllImages(mEglDisplay, stream); + } +} + +bool EmulationGl::bindColorBufferToWindowSurface(HandleType surfaceHandle, + HandleType colorBufferHandle, + HandleType* outOldColorBufferHandle) { + auto w = mWindows.find(surfaceHandle); + if (w == mWindows.end()) { + return false; + } + + IColorBufferRef cb = nullptr; + if (colorBufferHandle) { + cb = mGlobalState->findColorBuffer(colorBufferHandle); + if (!cb) { + GFXSTREAM_ERROR("bad color buffer handle %d", colorBufferHandle); + return false; + } + } + + w->second.first->setColorBuffer(cb); + *outOldColorBufferHandle = w->second.second; + w->second.second = colorBufferHandle; + return true; +} + +HandleType EmulationGl::getWindowSurfaceColorBufferHandle(HandleType surfaceHandle) const { + auto it = mWindows.find(surfaceHandle); + if (it == mWindows.end()) { + return 0; + } + return it->second.second; +} + +std::vector EmulationGl::cleanupProcGLObjects(uint64_t puid) { + RecursiveScopedContextBind bind(getColorBufferContextHelper()); + std::vector colorBuffersToCleanUp; + + // Clean up window surfaces + auto procWindowsIt = mProcOwnedEmulatedEglWindowSurfaces.find(puid); + if (procWindowsIt != mProcOwnedEmulatedEglWindowSurfaces.end()) { + for (auto whndl : procWindowsIt->second) { + auto w = mWindows.find(whndl); + if (w != mWindows.end()) { + if (w->second.second != 0) { + colorBuffersToCleanUp.push_back(w->second.second); + } + mWindows.erase(w); + } + } + mProcOwnedEmulatedEglWindowSurfaces.erase(procWindowsIt); + } + + // Cleanup render contexts + auto procContextsIt = mProcOwnedEmulatedEglContexts.find(puid); + if (procContextsIt != mProcOwnedEmulatedEglContexts.end()) { + for (auto ctx : procContextsIt->second) { + mContexts.erase(ctx); + } + mProcOwnedEmulatedEglContexts.erase(procContextsIt); + } + + // Cleanup EGLImages + auto procImagesIt = mProcOwnedEmulatedEglImages.find(puid); + if (procImagesIt != mProcOwnedEmulatedEglImages.end()) { + for (auto image : procImagesIt->second) { + mImages.erase(image); + } + mProcOwnedEmulatedEglImages.erase(procImagesIt); + } + return colorBuffersToCleanUp; +} + +void EmulationGl::postSave(Stream* stream) { + if (s_egl.eglPostSaveContext) { + for (const auto& ctx : mContexts) { + s_egl.eglPostSaveContext(mEglDisplay, ctx.second->getEGLContext(), stream); + } + if (mEglContext != EGL_NO_CONTEXT) { + s_egl.eglPostSaveContext(mEglDisplay, mEglContext, stream); + } + } +} + +bool EmulationGl::hasContextsOrWindowSurfaces() const { + return !mContexts.empty() || !mWindows.empty(); +} + +void EmulationGl::clearContextsAndWindowSurfaces() { + mContexts.clear(); + mWindows.clear(); +} + +bool EmulationGl::hasProcOwnedResources() const { + return !mProcOwnedEmulatedEglContexts.empty() || !mProcOwnedEmulatedEglWindowSurfaces.empty() || + !mProcOwnedEmulatedEglImages.empty(); +} + +std::vector EmulationGl::getGLPUIDs() const { + std::vector puids; + for (const auto& pair : mProcOwnedEmulatedEglContexts) { + puids.push_back(pair.first); + } + for (const auto& pair : mProcOwnedEmulatedEglWindowSurfaces) { + if (std::find(puids.begin(), puids.end(), pair.first) == puids.end()) { + puids.push_back(pair.first); + } + } + for (const auto& pair : mProcOwnedEmulatedEglImages) { + if (std::find(puids.begin(), puids.end(), pair.first) == puids.end()) { + puids.push_back(pair.first); + } + } + return puids; +} + +void EmulationGl::drainRenderThreadContexts() { + gfxstream::base::AutoWriteLock contextLock(mContextStructureLock); + RenderThreadInfoGl* const tinfo = RenderThreadInfoGl::get(); + if (!tinfo) { + GFXSTREAM_FATAL("RenderThreadGL not available."); + } + for (const HandleType contextHandle : tinfo->m_contextSet) { + mContexts.erase(contextHandle); + } + tinfo->m_contextSet.clear(); +} + +void EmulationGl::drainRenderThreadSurfaces() { + RenderThreadInfoGl* const tinfo = RenderThreadInfoGl::get(); + if (!tinfo) { + GFXSTREAM_FATAL("RenderThreadGL not available."); + } + RecursiveScopedContextBind bind(getColorBufferContextHelper()); + for (const HandleType winHandle : tinfo->m_windowSet) { + const auto winIt = mWindows.find(winHandle); + if (winIt != mWindows.end()) { + if (winIt->second.second != 0) { + mGlobalState->closeColorBufferByWindow(winIt->second.second); + } + mWindows.erase(winIt); + } + } + tinfo->m_windowSet.clear(); +} + +bool EmulationGl::flushEmulatedEglWindowSurfaceColorBuffer(HandleType surfaceHandle) { + auto it = mWindows.find(surfaceHandle); + if (it == mWindows.end()) { + GFXSTREAM_ERROR("flushEmulatedEglWindowSurfaceColorBuffer: window handle %#x not found", + surfaceHandle); + return false; + } + it->second.first->flushColorBuffer(); + return true; +} + +void EmulationGl::createTrivialContext(HandleType shared, HandleType* contextOut, + HandleType* surfOut) { + assert(contextOut); + assert(surfOut); + + *contextOut = createEmulatedEglContext(0, shared, GLESApi_2); + *surfOut = createEmulatedEglWindowSurface(0, 1, 1); +} + +void EmulationGl::createSharedTrivialContext(EGLContext* contextOut, EGLSurface* surfOut) { + assert(contextOut); + assert(surfOut); + + if (mEglConfig == EGL_NO_CONFIG) { + GFXSTREAM_FATAL("GL/EGL emulation has not chosen a config."); + } + + int maj, min; + get_gfxstream_gles_version(&maj, &min); + + const EGLint contextAttribs[] = {EGL_CONTEXT_MAJOR_VERSION_KHR, maj, + EGL_CONTEXT_MINOR_VERSION_KHR, min, EGL_NONE}; + + *contextOut = s_egl.eglCreateContext(mEglDisplay, mEglConfig, mEglContext, contextAttribs); + + const EGLint pbufAttribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE}; + + *surfOut = s_egl.eglCreatePbufferSurface(mEglDisplay, mEglConfig, pbufAttribs); +} + +void EmulationGl::destroySharedTrivialContext(EGLContext context, EGLSurface surface) { + if (mEglDisplay != EGL_NO_DISPLAY) { + s_egl.eglDestroyContext(mEglDisplay, context); + s_egl.eglDestroySurface(mEglDisplay, surface); + } +} + +bool EmulationGl::setEmulatedEglWindowSurfaceColorBuffer(HandleType surfaceHandle, + HandleType colorBufferHandle) { + HandleType oldColorBuffer = 0; + if (!bindColorBufferToWindowSurface(surfaceHandle, colorBufferHandle, &oldColorBuffer)) { + return false; + } + + if (colorBufferHandle) { + mGlobalState->openColorBufferByWindow(colorBufferHandle); + } + + if (oldColorBuffer) { + mGlobalState->closeColorBufferByWindow(oldColorBuffer); + } + + return true; +} + +void* EmulationGl::platformCreateSharedEglContext() { + EGLContext context = 0; + EGLSurface surface = 0; + createSharedTrivialContext(&context, &surface); + + void* underlyingContext = s_egl.eglGetNativeContextANDROID(mEglDisplay, context); + if (!underlyingContext) { + GFXSTREAM_ERROR("Error: Underlying egl backend could not produce a native EGL context."); + return nullptr; + } + + mPlatformEglContexts[underlyingContext] = {context, surface}; + +#if defined(__QNX__) + EGLDisplay currDisplay = eglGetCurrentDisplay(); + EGLSurface currRead = eglGetCurrentSurface(EGL_READ); + EGLSurface currDraw = eglGetCurrentSurface(EGL_DRAW); + EGLSurface currContext = eglGetCurrentContext(); + // Make this context current to ensure thread-state is initialized + s_egl.eglMakeCurrent(mEglDisplay, surface, surface, context); + // Revert back to original state + s_egl.eglMakeCurrent(currDisplay, currRead, currDraw, currContext); +#endif + + return underlyingContext; +} + +bool EmulationGl::platformDestroySharedEglContext(void* underlyingContext) { + auto it = mPlatformEglContexts.find(underlyingContext); + if (it == mPlatformEglContexts.end()) { + GFXSTREAM_ERROR( + "Error: Could not find underlying egl context %p (perhaps already destroyed?)", + underlyingContext); + return false; + } + + destroySharedTrivialContext(it->second.context, it->second.surface); + + mPlatformEglContexts.erase(it); + + return true; +} + +void EmulationGl::createYUVTextures(uint32_t type, uint32_t count, int width, int height, + uint32_t* output) { + auto formatOpt = + gfxstream::host::GetGfxstreamFormat(mFeatures, static_cast(type)); + if (!formatOpt) { + GFXSTREAM_ERROR("Unsupported framework format %d", type); + return; + } + auto format = *formatOpt; + + auto contextHelper = getPbufferSurfaceContextHelper(); + if (!contextHelper) { + // This should not be called in vulkan-only mode + GFXSTREAM_ERROR("%s: invalid pbuffer surface context", __func__); + return; + } + RecursiveScopedContextBind bind(contextHelper); + if (!bind.isOk()) { + GFXSTREAM_ERROR("%s: could not bind context helper", __func__); + return; + } + for (uint32_t i = 0; i < count; ++i) { + if (format == GfxstreamFormat::NV12 || format == GfxstreamFormat::NV21) { + YUVConverter::createYUVGLTex(GL_TEXTURE0, width, height, format, YuvPlane::Y, + &output[2 * i]); + YUVConverter::createYUVGLTex(GL_TEXTURE1, width / 2, height / 2, format, YuvPlane::UV, + &output[2 * i + 1]); + } else if (format == GfxstreamFormat::YV12 || format == GfxstreamFormat::YV21) { + YUVConverter::createYUVGLTex(GL_TEXTURE0, width, height, format, YuvPlane::Y, + &output[3 * i]); + YUVConverter::createYUVGLTex(GL_TEXTURE1, width / 2, height / 2, format, YuvPlane::U, + &output[3 * i + 1]); + YUVConverter::createYUVGLTex(GL_TEXTURE2, width / 2, height / 2, format, YuvPlane::V, + &output[3 * i + 2]); + } + } +} + +void EmulationGl::destroyYUVTextures(uint32_t type, uint32_t count, uint32_t* textures) { + auto formatOpt = + gfxstream::host::GetGfxstreamFormat(mFeatures, static_cast(type)); + if (!formatOpt) { + GFXSTREAM_ERROR("Unsupported framework format %d", type); + return; + } + auto format = *formatOpt; + + RecursiveScopedContextBind bind(getPbufferSurfaceContextHelper()); + if (format == GfxstreamFormat::NV12 || format == GfxstreamFormat::NV21) { + s_gles2.glDeleteTextures(2 * count, textures); + } else if (format == GfxstreamFormat::YV12 || format == GfxstreamFormat::YV21) { + s_gles2.glDeleteTextures(3 * count, textures); + } +} + +void EmulationGl::updateYUVTextures(uint32_t type, uint32_t* textures, void* privData, void* func) { + auto formatOpt = + gfxstream::host::GetGfxstreamFormat(mFeatures, static_cast(type)); + if (!formatOpt) { + GFXSTREAM_ERROR("Unsupported framework format %d", type); + return; + } + auto format = *formatOpt; + + RecursiveScopedContextBind bind(getPbufferSurfaceContextHelper()); + + yuv_updater_t updater = (yuv_updater_t)func; + uint32_t gtextures[3] = {0, 0, 0}; + + if (format == GfxstreamFormat::NV12 || format == GfxstreamFormat::NV21) { + gtextures[0] = s_gles2.glGetGlobalTexName(textures[0]); + gtextures[1] = s_gles2.glGetGlobalTexName(textures[1]); + } else if (format == GfxstreamFormat::YV12 || format == GfxstreamFormat::YV21) { + gtextures[0] = s_gles2.glGetGlobalTexName(textures[0]); + gtextures[1] = s_gles2.glGetGlobalTexName(textures[1]); + gtextures[2] = s_gles2.glGetGlobalTexName(textures[2]); + } + +#ifdef __APPLE__ + EGLContext prevContext = s_egl.eglGetCurrentContext(); + auto mydisp = EglGlobalInfo::getInstance()->getDisplayFromDisplayType(EGL_DEFAULT_DISPLAY); + void* nativecontext = mydisp->getLowLevelContext(prevContext); + struct MediaNativeCallerData callerdata; + callerdata.ctx = nativecontext; + callerdata.converter = nsConvertVideoFrameToNV12Textures; + void* pcallerdata = &callerdata; +#else + void* pcallerdata = nullptr; +#endif + + updater(privData, type, gtextures, pcallerdata); +} + +void EmulationGl::drainRenderThreadResources() { + bindContext(0, 0, 0); + drainRenderThreadSurfaces(); + drainRenderThreadContexts(); + if (!s_egl.eglReleaseThread()) { + GFXSTREAM_ERROR("Error: RenderThread failed to eglReleaseThread()"); + } +} + +void EmulationGl::fillGlesUsages(android_studio::EmulatorGLESUsages* usages) { + if (s_egl.eglFillUsages) { + s_egl.eglFillUsages(usages); + } +} + +bool EmulationGl::getRenderOpt(gfxstream::RenderOpt* opt) const { + if (!opt) { + return false; + } + opt->display = mEglDisplay; + opt->config = mEglConfig; + + if (!mWindowSurface) { + opt->surface = EGL_NO_SURFACE; + } else { + const auto* displaySurfaceGl = + reinterpret_cast(mWindowSurface->getImpl()); + opt->surface = displaySurfaceGl->getSurface(); + } + + return (opt->display && opt->surface && opt->config); +} + +EGLContext EmulationGl::getGlobalEGLContext() const { + if (!mPbufferSurface) { + GFXSTREAM_FATAL("FrameBuffer pbuffer surface not available."); + } + const auto* displaySurfaceGl = + reinterpret_cast(mPbufferSurface->getImpl()); + return displaySurfaceGl->getContextForShareContext(); +} + +void EmulationGl::swapTexturesAndUpdateColorBuffer(IColorBuffer* colorBuffer, uint32_t format, + uint32_t type, uint32_t texturesType, + uint32_t* textures) { + auto texturesFormatOpt = GetGfxstreamFormat(mFeatures, (FrameworkFormat)texturesType); + if (!texturesFormatOpt) { + GFXSTREAM_ERROR("Unsupported framework format %d", texturesType); + return; + } + auto texturesFormat = *texturesFormatOpt; + + ColorBufferGl* colorBufferGl = colorBuffer->getColorBufferGl(); + if (!colorBufferGl) { + return; + } + + colorBufferGl->swapYUVTextures(texturesFormat, textures); + colorBufferGl->subUpdate(0, 0, colorBuffer->getWidth(), colorBuffer->getHeight(), + texturesFormat, nullptr); + + colorBuffer->flushFromBackend(Backend::GL); +} + } // namespace gl } // namespace host } // namespace gfxstream diff --git a/host/gl/emulation_gl.h b/host/gl/emulation_gl.h index c477ce435..b7d88839e 100644 --- a/host/gl/emulation_gl.h +++ b/host/gl/emulation_gl.h @@ -21,11 +21,20 @@ #include #include +#include #include #include #include #include +namespace android_studio { +class EmulatorGLESUsages; +} + +namespace gfxstream { +struct RenderOpt; +} + #include "OpenGLESDispatch/EGLDispatch.h" #include "OpenGLESDispatch/GLESv2Dispatch.h" #include "buffer_gl.h" @@ -38,12 +47,17 @@ #include "emulated_egl_fence_sync.h" #include "emulated_egl_image.h" #include "emulated_egl_window_surface.h" +#include "gfxstream/host/color_buffer_interface.h" #include "gfxstream/host/compositor.h" #include "gfxstream/host/display.h" #include "gfxstream/host/display_surface.h" +#include "gfxstream/host/display_surface_user.h" #include "gfxstream/host/features.h" +#include "gfxstream/host/framework_formats.h" #include "gfxstream/host/gfxstream_format.h" #include "gfxstream/host/gl_enums.h" +#include "gfxstream/host/global_state.h" +#include "gfxstream/synchronization/Lock.h" #include "pixel_read_formats.h" #include "readback_worker_gl.h" #include "render-utils/stream.h" @@ -51,12 +65,6 @@ #define EGL_NO_CONFIG ((EGLConfig)0) -namespace gfxstream { -namespace host { -class FrameBuffer; -} // namespace host -} // namespace gfxstream - namespace gfxstream { namespace host { namespace gl { @@ -65,8 +73,8 @@ class EmulationGl { public: static bool initDispatchers(bool eglOnEgl); static std::unique_ptr create(uint32_t width, uint32_t height, - const FeatureSet& features, - bool allowWindowSurface); + const FeatureSet& features, bool allowWindowSurface, + GlobalState* globalState); ~EmulationGl(); @@ -106,6 +114,9 @@ class EmulationGl { CompositorGl* getCompositor() { return mCompositorGl.get(); } DisplayGl* getDisplay() { return mDisplayGl.get(); } + EGLDisplay getEglDisplay() const { return mEglDisplay; } + DisplaySurface* getPbufferSurface() const { return mPbufferSurface.get(); } + TextureDraw* getTextureDraw() const { return mTextureDraw.get(); } ReadbackWorkerGl* getReadbackWorker() { return mReadbackWorkerGl.get(); } @@ -124,86 +135,167 @@ class EmulationGl { std::unique_ptr loadColorBuffer(Stream* stream); - std::unique_ptr createEmulatedEglContext( - uint32_t emulatedEglConfigIndex, - const EmulatedEglContext* shareContext, - GLESApi api, - HandleType handle); + HandleType createEmulatedEglContext(uint32_t emulatedConfigIndex, HandleType shareContextHandle, + GLESApi api); + + void destroyEmulatedEglContext(HandleType contextHandle); + + HandleType createEmulatedEglWindowSurface(uint32_t emulatedConfigIndex, uint32_t width, + uint32_t height); + + std::vector destroyEmulatedEglWindowSurface(HandleType surfaceHandle); - std::unique_ptr loadEmulatedEglContext( - Stream* stream); + bool isHandleInUse(HandleType handle) const; - std::unique_ptr createEmulatedEglFenceSync( - EGLenum type, - int destroyWhenSignaled); + EmulatedEglContextPtr getContext(HandleType contextHandle); + EmulatedEglWindowSurfacePtr getWindowSurface(HandleType surfaceHandle); - std::unique_ptr createEmulatedEglImage( - EmulatedEglContext* context, - EGLenum target, - EGLClientBuffer buffer); + uint64_t createEmulatedEglFenceSync(EGLenum type, int destroyWhenSignaled); - std::unique_ptr createEmulatedEglWindowSurface( - uint32_t emulatedConfigIndex, - uint32_t width, - uint32_t height, + HandleType createEmulatedEglImage(HandleType contextHandle, EGLenum target, + EGLClientBuffer buffer); + + bool destroyEmulatedEglImage(HandleType imageHandle); + + std::unique_ptr createFakeWindowSurface(); + + bool bindColorBufferToTexture(HandleType colorBufferHandle); + bool bindColorBufferToTexture2(HandleType colorBufferHandle); + bool bindColorBufferToRenderbuffer(HandleType colorBufferHandle); + bool bindContext(HandleType contextHandle, HandleType drawSurfaceHandle, + HandleType readSurfaceHandle); + bool bindColorBufferToWindowSurface(HandleType surfaceHandle, HandleType colorBufferHandle, + HandleType* outOldColorBufferHandle); + HandleType getWindowSurfaceColorBufferHandle(HandleType surfaceHandle) const; + + void preSave(Stream* stream, const gfxstream::ITextureSaverPtr& textureSaver); + void postSave(Stream* stream); + void saveContexts(Stream* stream); + void saveWindowSurfaces(Stream* stream); + void saveProcOwnedWindowSurfaces(Stream* stream); + void saveProcOwnedContexts(Stream* stream); + void saveProcOwnedImages(Stream* stream); + + bool loadContexts(Stream* stream); + bool loadWindowSurfaces(Stream* stream, + const std::function& colorBufferLookup); + void loadProcOwnedWindowSurfaces(Stream* stream); + void loadProcOwnedContexts(Stream* stream); + void loadProcOwnedImages(Stream* stream); + void loadAllImages(Stream* stream, const gfxstream::ITextureLoaderPtr& textureLoader); + void postLoad(Stream* stream); + std::vector cleanupProcGLObjects(uint64_t puid); + bool hasContextsOrWindowSurfaces() const; + void clearContextsAndWindowSurfaces(); + bool hasProcOwnedResources() const; + std::vector getGLPUIDs() const; + void drainRenderThreadContexts(); + void drainRenderThreadSurfaces(); + void drainRenderThreadResources(); + bool flushEmulatedEglWindowSurfaceColorBuffer(HandleType surfaceHandle); + void fillGlesUsages(android_studio::EmulatorGLESUsages* usages); + bool getRenderOpt(gfxstream::RenderOpt* opt) const; + ContextHelper* getPbufferSurfaceContextHelper() const; + EGLContext getGlobalEGLContext() const; + + void lockContextStructureRead() { mContextStructureLock.lockRead(); } + void unlockContextStructureRead() { mContextStructureLock.unlockRead(); } + + void createTrivialContext(HandleType shared, HandleType* contextOut, HandleType* surfOut); + void createSharedTrivialContext(EGLContext* contextOut, EGLSurface* surfOut); + void destroySharedTrivialContext(EGLContext context, EGLSurface surface); + bool setEmulatedEglWindowSurfaceColorBuffer(HandleType surfaceHandle, + HandleType colorBufferHandle); + void* platformCreateSharedEglContext(); + bool platformDestroySharedEglContext(void* underlyingContext); + + void createYUVTextures(uint32_t type, uint32_t count, int width, int height, uint32_t* output); + void destroyYUVTextures(uint32_t type, uint32_t count, uint32_t* textures); + void updateYUVTextures(uint32_t type, uint32_t* textures, void* privData, void* func); + void swapTexturesAndUpdateColorBuffer(IColorBuffer* colorBuffer, uint32_t format, uint32_t type, + uint32_t texturesType, uint32_t* textures); + + private: + EmulationGl() = default; + + std::unique_ptr createEmulatedEglContextImpl( + uint32_t emulatedEglConfigIndex, const EmulatedEglContext* shareContext, GLESApi api, HandleType handle); + std::unique_ptr loadEmulatedEglContext(Stream* stream); + + std::unique_ptr createEmulatedEglWindowSurfaceImpl( + uint32_t emulatedConfigIndex, uint32_t width, uint32_t height, HandleType handle); + std::unique_ptr loadEmulatedEglWindowSurface( Stream* stream, const std::function& colorBufferLookup, const EmulatedEglContextMap& contexts); - std::unique_ptr createFakeWindowSurface(); + ContextHelper* getColorBufferContextHelper(); - private: - // TODO(b/233939967): Remove this after fully transitioning to EmulationGl. - friend class ::gfxstream::host::FrameBuffer; + FeatureSet mFeatures; + + EGLDisplay mEglDisplay = EGL_NO_DISPLAY; + EGLint mEglVersionMajor = 0; + EGLint mEglVersionMinor = 0; + std::string mEglVendor; + std::unordered_set mEglExtensions; + EGLConfig mEglConfig = EGL_NO_CONFIG; - EmulationGl() = default; + // The "global" context that all other contexts are shared with. + EGLContext mEglContext = EGL_NO_CONTEXT; - ContextHelper* getColorBufferContextHelper(); + // Used for ColorBuffer ops. + std::unique_ptr mPbufferSurface; - FeatureSet mFeatures; + // Used for Composition and Display ops. + std::unique_ptr mWindowSurface; - EGLDisplay mEglDisplay = EGL_NO_DISPLAY; - EGLint mEglVersionMajor = 0; - EGLint mEglVersionMinor = 0; - std::string mEglVendor; - std::unordered_set mEglExtensions; - EGLConfig mEglConfig = EGL_NO_CONFIG; + GLint mGlesVersionMajor = 0; + GLint mGlesVersionMinor = 0; + GLESDispatchMaxVersion mGlesDispatchMaxVersion = GLES_DISPATCH_MAX_VERSION_2; + std::string mGlesVendor; + std::string mGlesRenderer; + std::string mGlesVersion; + std::string mGlesExtensions; + std::optional mGlesDeviceUuid; + bool mGlesVulkanInteropSupported = false; - // The "global" context that all other contexts are shared with. - EGLContext mEglContext = EGL_NO_CONTEXT; + std::unique_ptr mEmulatedEglConfigs; - // Used for ColorBuffer ops. - std::unique_ptr mPbufferSurface; + bool mFastBlitSupported = false; - // Used for Composition and Display ops. - std::unique_ptr mWindowSurface; + std::unique_ptr mCompositorGl; + std::unique_ptr mDisplayGl; + std::unique_ptr mReadbackWorkerGl; - GLint mGlesVersionMajor = 0; - GLint mGlesVersionMinor = 0; - GLESDispatchMaxVersion mGlesDispatchMaxVersion = GLES_DISPATCH_MAX_VERSION_2; - std::string mGlesVendor; - std::string mGlesRenderer; - std::string mGlesVersion; - std::string mGlesExtensions; - std::optional mGlesDeviceUuid; - bool mGlesVulkanInteropSupported = false; + std::unique_ptr mTextureDraw; - std::unique_ptr mEmulatedEglConfigs; + PixelReadFormats mPixelReadFormats; - bool mFastBlitSupported = false; + uint32_t mWidth = 0; + uint32_t mHeight = 0; - std::unique_ptr mCompositorGl; - std::unique_ptr mDisplayGl; - std::unique_ptr mReadbackWorkerGl; + GlobalState* mGlobalState = nullptr; - std::unique_ptr mTextureDraw; + EmulatedEglContextMap mContexts; + EmulatedEglWindowSurfaceMap mWindows; + using ProcOwnedEmulatedEglContexts = std::unordered_map; + ProcOwnedEmulatedEglContexts mProcOwnedEmulatedEglContexts; + using ProcOwnedEmulatedEglWindowSurfaces = + std::unordered_map; + ProcOwnedEmulatedEglWindowSurfaces mProcOwnedEmulatedEglWindowSurfaces; + EmulatedEglImageMap mImages; + using ProcOwnedEmulatedEglImages = std::unordered_map; + ProcOwnedEmulatedEglImages mProcOwnedEmulatedEglImages; - PixelReadFormats mPixelReadFormats; + struct PlatformEglContextInfo { + EGLContext context; + EGLSurface surface; + }; + std::unordered_map mPlatformEglContexts; - uint32_t mWidth = 0; - uint32_t mHeight = 0; + gfxstream::base::ReadWriteLock mContextStructureLock; }; } // namespace gl diff --git a/host/gl/readback_worker_gl.cpp b/host/gl/readback_worker_gl.cpp index b219482e1..e771f4384 100644 --- a/host/gl/readback_worker_gl.cpp +++ b/host/gl/readback_worker_gl.cpp @@ -178,6 +178,23 @@ ReadbackWorkerGl::DoNextReadbackResult ReadbackWorkerGl::doNextReadback(uint32_t return ret; } +void ReadbackWorkerGl::doNextReadbackSync(IColorBuffer* colorBuffer, void* fbImage, + bool readbackBgra) { + if (!colorBuffer) { + return; + } + + ColorBufferGl* colorBufferGl = colorBuffer->getColorBufferGl(); + if (!colorBufferGl) { + GFXSTREAM_ERROR("Failed to get ColorBufferGl"); + return; + } + + colorBuffer->touch(); + + colorBufferGl->readback(static_cast(fbImage), readbackBgra); +} + ReadbackWorkerGl::FlushResult ReadbackWorkerGl::flushPipeline(uint32_t displayId) { gfxstream::base::AutoLock lock(mLock); diff --git a/host/gl/readback_worker_gl.h b/host/gl/readback_worker_gl.h index 324a8b26a..13a4d0344 100644 --- a/host/gl/readback_worker_gl.h +++ b/host/gl/readback_worker_gl.h @@ -64,6 +64,8 @@ class ReadbackWorkerGl : public ReadbackWorker { DoNextReadbackResult doNextReadback(uint32_t displayId, IColorBuffer* cb, void* fbImage, bool repaint, bool readbackBgra) override; + void doNextReadbackSync(IColorBuffer* cb, void* fbImage, bool readbackBgra) override; + // getPixels(): Run this on a separate GL thread. This retrieves the // latest framebuffer that has been posted and read with doNextReadback. // This is meant for apps like video encoding to use as input; they will diff --git a/host/gl/render_thread_info_gl.cpp b/host/gl/render_thread_info_gl.cpp index 6e81b7c83..455e28129 100644 --- a/host/gl/render_thread_info_gl.cpp +++ b/host/gl/render_thread_info_gl.cpp @@ -21,7 +21,6 @@ #include "OpenGLESDispatch/GLESv2Dispatch.h" #include "emulation_gl.h" #include "gfxstream/containers/Lookup.h" -#include "gfxstream/host/global_state.h" #include "gfxstream/host/stream_utils.h" #include "gfxstream/synchronization/Lock.h" @@ -35,8 +34,7 @@ using gfxstream::Stream; static thread_local RenderThreadInfoGl* tlThreadInfo = nullptr; -RenderThreadInfoGl::RenderThreadInfoGl(gfxstream::host::GlobalState* globalState) - : m_globalState(globalState) { +RenderThreadInfoGl::RenderThreadInfoGl(EmulationGl* emulationGl) : m_emulationGl(emulationGl) { m_glDec.initGL(gles1_dispatch_get_proc_func, nullptr); m_gl2Dec.initGL(gles2_dispatch_get_proc_func, nullptr); @@ -85,8 +83,8 @@ void RenderThreadInfoGl::onSave(Stream* stream) { stream->putBe64(0); } -bool RenderThreadInfoGl::onLoad(Stream* stream) { - assert(m_globalState); +bool RenderThreadInfoGl::onLoad(Stream* stream) NO_THREAD_SAFETY_ANALYSIS { + assert(m_emulationGl); HandleType ctxHndl = stream->getBe32(); HandleType drawSurf = stream->getBe32(); @@ -96,7 +94,9 @@ bool RenderThreadInfoGl::onLoad(Stream* stream) { currDrawSurfHandleFromLoad = drawSurf; currReadSurfHandleFromLoad = readSurf; - m_globalState->postLoadRenderThreadContextSurfacePtrs(); + currContext = m_emulationGl->getContext(ctxHndl); + currDrawSurf = m_emulationGl->getWindowSurface(drawSurf); + currReadSurf = m_emulationGl->getWindowSurface(readSurf); loadCollection(stream, &m_contextSet, [](Stream* stream) { return stream->getBe32(); @@ -113,15 +113,17 @@ bool RenderThreadInfoGl::onLoad(Stream* stream) { return true; } -void RenderThreadInfoGl::postLoadRefreshCurrentContextSurfacePtrs() { - assert(m_globalState); +void RenderThreadInfoGl::postLoadRefreshCurrentContextSurfacePtrs() NO_THREAD_SAFETY_ANALYSIS { + assert(m_emulationGl); - m_globalState->postLoadRenderThreadContextSurfacePtrs(); + currContext = m_emulationGl->getContext(currContextHandleFromLoad); + currDrawSurf = m_emulationGl->getWindowSurface(currDrawSurfHandleFromLoad); + currReadSurf = m_emulationGl->getWindowSurface(currReadSurfHandleFromLoad); const HandleType ctx = currContext ? currContext->getHndl() : 0; const HandleType draw = currDrawSurf ? currDrawSurf->getHndl() : 0; const HandleType read = currReadSurf ? currReadSurf->getHndl() : 0; - m_globalState->bindContext(ctx, draw, read); + m_emulationGl->bindContext(ctx, draw, read); } } // namespace gl diff --git a/host/gl/render_thread_info_gl.h b/host/gl/render_thread_info_gl.h index 8dc767f02..8acedddbb 100644 --- a/host/gl/render_thread_info_gl.h +++ b/host/gl/render_thread_info_gl.h @@ -29,12 +29,13 @@ namespace gfxstream { namespace host { class GlobalState; namespace gl { +class EmulationGl; struct RenderThreadInfoGl { // Create new instance. Only call this once per thread. // Future calls to get() will return this instance until // it is destroyed. - RenderThreadInfoGl(gfxstream::host::GlobalState* globalState); + RenderThreadInfoGl(EmulationGl* emulationGl); // Destructor. ~RenderThreadInfoGl(); @@ -75,7 +76,7 @@ struct RenderThreadInfoGl { GLESv1Decoder m_glDec; GLESv2Decoder m_gl2Dec; - gfxstream::host::GlobalState* m_globalState = nullptr; + EmulationGl* m_emulationGl = nullptr; }; } // namespace gl diff --git a/host/render_lib_impl.cpp b/host/render_lib_impl.cpp index 3e9ef95c2..45681f48c 100644 --- a/host/render_lib_impl.cpp +++ b/host/render_lib_impl.cpp @@ -132,9 +132,7 @@ bool RenderLibImpl::getOpt(RenderOpt* opt) { } #if GFXSTREAM_ENABLE_HOST_GLES - opt->display = fb->getDisplay(); - opt->surface = fb->getWindowSurface(); - opt->config = fb->getConfig(); + fb->getRenderOpt(opt); #endif return (opt->display && opt->surface && opt->config); } diff --git a/host/render_thread.cpp b/host/render_thread.cpp index a255d1303..050077b3e 100644 --- a/host/render_thread.cpp +++ b/host/render_thread.cpp @@ -285,7 +285,7 @@ intptr_t RenderThread::main() { // initialize decoders #if GFXSTREAM_ENABLE_HOST_GLES if (FrameBuffer::getFB()->hasEmulationGl()) { - tInfo->initGl(FrameBuffer::getFB()->getGlobalState()); + tInfo->initGl(FrameBuffer::getFB()->getEmulationGl()); } initRenderControlContext(&(tInfo->m_rcDec)); diff --git a/host/render_thread_info.cpp b/host/render_thread_info.cpp index 001db5b3d..b533d5e53 100644 --- a/host/render_thread_info.cpp +++ b/host/render_thread_info.cpp @@ -63,9 +63,7 @@ void RenderThreadInfo::forAllRenderThreadInfos(std::functiongetBe32() == 1; if (loadGlInfo) { if (!m_glInfo) { - m_glInfo.emplace(FrameBuffer::getFB()->getGlobalState()); + m_glInfo.emplace(FrameBuffer::getFB()->getEmulationGl()); } if (!m_glInfo->onLoad(stream)) { return false; diff --git a/host/render_thread_info.h b/host/render_thread_info.h index ef7afb6fe..88b38f432 100644 --- a/host/render_thread_info.h +++ b/host/render_thread_info.h @@ -50,7 +50,7 @@ struct RenderThreadInfo { static void forAllRenderThreadInfos(std::function); #if GFXSTREAM_ENABLE_HOST_GLES - void initGl(gfxstream::host::GlobalState* globalState); + void initGl(gl::EmulationGl* emulationGl); #endif // The unique id of owner guest process of this render thread diff --git a/host/testlibs/support/SampleApplication.cpp b/host/testlibs/support/SampleApplication.cpp index 7d4f991fe..e965e4776 100644 --- a/host/testlibs/support/SampleApplication.cpp +++ b/host/testlibs/support/SampleApplication.cpp @@ -265,7 +265,7 @@ SampleApplication::SampleApplication(int windowWidth, int windowHeight, int refr } mRenderThreadInfo.reset(new RenderThreadInfo()); - mRenderThreadInfo->initGl(mFb->getGlobalState()); + mRenderThreadInfo->initGl(mFb->getEmulationGl()); mColorBuffer = mFb->createColorBuffer(mWidth, mHeight, GfxstreamFormat::R8G8B8A8_UNORM); mContext = mFb->createEmulatedEglContext(0, 0, glVersion); From 30c044b29301aca3983eeae2bc3b14a94325a7c3 Mon Sep 17 00:00:00 2001 From: Jason Macnak Date: Wed, 29 Jul 2026 10:01:16 -0700 Subject: [PATCH 22/33] Move post worker files to address backwards-ref errors The GL file should be a part of host/gl and the base class should be in host/common. Bug: b/537737772 Test: bazel build \ --graphics_drivers=gles_angle_vulkan_swiftshader \ --linkopt="-Wl,--warn-backrefs" \ --linkopt="-Wl,--fatal-warnings" \ --linkopt="-Wl,--warn-backrefs-exclude=*llvm*" \ ... Low-Coverage-Reason: REFACTOR_ONLY Change-Id: Ib435963c2c5b526dee3a5bdb980440b7e90db807 --- host/Android.bp | 2 -- host/BUILD.bazel | 3 -- host/CMakeLists.txt | 2 -- host/common/Android.bp | 1 + host/common/BUILD.bazel | 1 + host/common/CMakeLists.txt | 1 + host/common/meson.build | 1 + host/{ => common}/post_worker.cpp | 52 ++++++++++++++----------------- host/frame_buffer.cpp | 21 ------------- host/gl/Android.bp | 1 + host/gl/BUILD.bazel | 2 ++ host/gl/CMakeLists.txt | 1 + host/gl/emulation_gl.cpp | 41 ++++++++++++++---------- host/gl/meson.build | 1 + host/{ => gl}/post_worker_gl.cpp | 13 +++----- host/{ => gl}/post_worker_gl.h | 8 ++--- host/meson.build | 2 -- 17 files changed, 66 insertions(+), 87 deletions(-) rename host/{ => common}/post_worker.cpp (81%) rename host/{ => gl}/post_worker_gl.cpp (97%) rename host/{ => gl}/post_worker_gl.h (92%) diff --git a/host/Android.bp b/host/Android.bp index 517a3872c..e93ba02b9 100644 --- a/host/Android.bp +++ b/host/Android.bp @@ -135,8 +135,6 @@ cc_defaults { "channel_stream.cpp", "color_buffer.cpp", "frame_buffer.cpp", - "post_worker.cpp", - "post_worker_gl.cpp", "read_buffer.cpp", "render_api.cpp", "render_channel_impl.cpp", diff --git a/host/BUILD.bazel b/host/BUILD.bazel index 5dc4ba160..5f2d3f89c 100644 --- a/host/BUILD.bazel +++ b/host/BUILD.bazel @@ -72,8 +72,6 @@ cc_library( "color_buffer.cpp", "color_buffer.h", "frame_buffer.cpp", - "post_worker.cpp", - "post_worker_gl.cpp", "read_buffer.cpp", "render_channel_impl.cpp", "render_control.cpp", @@ -95,7 +93,6 @@ cc_library( hdrs = [ "color_buffer.h", "frame_buffer.h", - "post_worker_gl.h", "read_buffer.h", "render_channel_impl.h", "render_control.h", diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index a708e16d0..47c9c9a47 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -83,8 +83,6 @@ set(stream-server-core-sources channel_stream.cpp color_buffer.cpp frame_buffer.cpp - post_worker.cpp - post_worker_gl.cpp read_buffer.cpp render_channel_impl.cpp render_control.cpp diff --git a/host/common/Android.bp b/host/common/Android.bp index 3bd200e1a..f0f6cfb9a 100644 --- a/host/common/Android.bp +++ b/host/common/Android.bp @@ -31,6 +31,7 @@ cc_library_static { "guest_operations.cpp", "hwc2.cpp", "mem_stream.cpp", + "post_worker.cpp", "renderer_operations.cpp", "stream_utils.cpp", "sync_device.cpp", diff --git a/host/common/BUILD.bazel b/host/common/BUILD.bazel index ce5cbf80b..49a65fa8b 100644 --- a/host/common/BUILD.bazel +++ b/host/common/BUILD.bazel @@ -20,6 +20,7 @@ cc_library( "guest_operations.cpp", "hwc2.cpp", "mem_stream.cpp", + "post_worker.cpp", "renderer_operations.cpp", "stream_utils.cpp", "sync_device.cpp", diff --git a/host/common/CMakeLists.txt b/host/common/CMakeLists.txt index a0d448868..dbcfc67f2 100644 --- a/host/common/CMakeLists.txt +++ b/host/common/CMakeLists.txt @@ -38,6 +38,7 @@ if (NOT TARGET gfxstream_host_common) guest_operations.cpp hwc2.cpp mem_stream.cpp + post_worker.cpp renderer_operations.cpp stream_utils.cpp sync_device.cpp diff --git a/host/common/meson.build b/host/common/meson.build index 7b995e692..597d649a3 100644 --- a/host/common/meson.build +++ b/host/common/meson.build @@ -15,6 +15,7 @@ files_lib_host_common = files( 'guest_operations.cpp', 'hwc2.cpp', 'mem_stream.cpp', + 'post_worker.cpp', 'renderer_operations.cpp', 'stream_utils.cpp', 'sync_device.cpp', diff --git a/host/post_worker.cpp b/host/common/post_worker.cpp similarity index 81% rename from host/post_worker.cpp rename to host/common/post_worker.cpp index 14d5740a4..38c59b84b 100644 --- a/host/post_worker.cpp +++ b/host/common/post_worker.cpp @@ -1,18 +1,18 @@ /* -* Copyright (C) 2017 The Android Open Source Project -* -* 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. -*/ + * Copyright (C) 2017 The Android Open Source Project + * + * 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. + */ #include "gfxstream/host/post_worker.h" #include @@ -35,8 +35,7 @@ PostWorker::PostWorker(bool mainThreadPostingOnly, gfxstream::host::GlobalState* m_mainThreadPostingOnly(mainThreadPostingOnly) {} std::shared_future PostWorker::composeImpl(const FlatComposeRequest& composeRequest) { - std::shared_future completedFuture = - std::async(std::launch::deferred, [] {}).share(); + std::shared_future completedFuture = std::async(std::launch::deferred, [] {}).share(); completedFuture.wait(); if (!isComposeTargetReady(composeRequest.targetHandle)) { @@ -92,11 +91,10 @@ PostWorker::~PostWorker() {} void PostWorker::post(IColorBuffer* cb, std::unique_ptr postCallback, const std::optional>& colorTransform) { auto packagedPostCallback = std::shared_ptr(std::move(postCallback)); - runTask( - std::packaged_task([cb, packagedPostCallback, this, colorTransform] { - auto completedFuture = postImpl(cb, colorTransform); - (*packagedPostCallback)(completedFuture); - })); + runTask(std::packaged_task([cb, packagedPostCallback, this, colorTransform] { + auto completedFuture = postImpl(cb, colorTransform); + (*packagedPostCallback)(completedFuture); + })); } void PostWorker::exit() { @@ -104,8 +102,7 @@ void PostWorker::exit() { } void PostWorker::viewport(int width, int height) { - runTask(std::packaged_task( - [width, height, this] { viewportImpl(width, height); })); + runTask(std::packaged_task([width, height, this] { viewportImpl(width, height); })); } void PostWorker::compose(std::unique_ptr composeRequest, @@ -115,13 +112,12 @@ void PostWorker::compose(std::unique_ptr composeRequest, auto packagedComposeCallback = std::shared_ptr(std::move(composeCallback)); auto packagedComposeRequest = std::shared_ptr(std::move(composeRequest)); - runTask( - std::packaged_task([packagedComposeCallback, packagedComposeRequest, this] { + runTask(std::packaged_task([packagedComposeCallback, packagedComposeRequest, this] { auto completedFuture = composeImpl(*packagedComposeRequest); m_composeTargetToComposeFuture.emplace(packagedComposeRequest->targetHandle, completedFuture); (*packagedComposeCallback)(completedFuture); - })); + })); } void PostWorker::clear() { @@ -157,8 +153,8 @@ void PostWorker::runTask(std::packaged_task task) { if (!get_gfxstream_window_operations().run_on_ui_thread) { GFXSTREAM_ERROR("m_runOnUiThread function ptr is NULL, going to crash"); } - get_gfxstream_window_operations() - .run_on_ui_thread(RunOnUiThreadTrampoline, taskPtr.release(), false); + get_gfxstream_window_operations().run_on_ui_thread(RunOnUiThreadTrampoline, + taskPtr.release(), false); } else { (*taskPtr)(); } diff --git a/host/frame_buffer.cpp b/host/frame_buffer.cpp index 6e44741da..6c1895ab7 100644 --- a/host/frame_buffer.cpp +++ b/host/frame_buffer.cpp @@ -303,27 +303,6 @@ static std::optional> GetColorTransform(uint32_t displayId } // namespace -std::optional GetGfxstreamFormat(const gfxstream::host::FeatureSet& features, - FrameworkFormat format) { - switch (format) { - case FRAMEWORK_FORMAT_NV12: - return GfxstreamFormat::NV12; - case FRAMEWORK_FORMAT_YV12: - return GfxstreamFormat::YV12; - case FRAMEWORK_FORMAT_P010: - return GfxstreamFormat::P010; - case FRAMEWORK_FORMAT_YUV_420_888: { - if (features.Yuv420888ToNv21.enabled()) { - return GfxstreamFormat::NV21; - } else { - return GfxstreamFormat::YV21; - } - } - default: - return std::nullopt; - } -} - static HandleType sNextHandle = 0; struct BufferRef { diff --git a/host/gl/Android.bp b/host/gl/Android.bp index 0bb04fae2..8af34fc87 100644 --- a/host/gl/Android.bp +++ b/host/gl/Android.bp @@ -34,6 +34,7 @@ cc_library_static { "emulation_gl.cpp", "gles_version_detector.cpp", "pixel_read_formats.cpp", + "post_worker_gl.cpp", "readback_worker_gl.cpp", "render_thread_info_gl.cpp", "texture_draw.cpp", diff --git a/host/gl/BUILD.bazel b/host/gl/BUILD.bazel index 496cdf105..ef06a2e8a 100644 --- a/host/gl/BUILD.bazel +++ b/host/gl/BUILD.bazel @@ -23,6 +23,7 @@ cc_library( "emulation_gl.cpp", "gles_version_detector.cpp", "pixel_read_formats.cpp", + "post_worker_gl.cpp", "readback_worker_gl.cpp", "render_thread_info_gl.cpp", "texture_draw.cpp", @@ -45,6 +46,7 @@ cc_library( "emulation_gl.h", "gles_version_detector.h", "pixel_read_formats.h", + "post_worker_gl.h", "readback_worker_gl.h", "render_thread_info_gl.h", "stale_ptr_registry.h", diff --git a/host/gl/CMakeLists.txt b/host/gl/CMakeLists.txt index 347529ee7..fbb7a3daf 100644 --- a/host/gl/CMakeLists.txt +++ b/host/gl/CMakeLists.txt @@ -38,6 +38,7 @@ add_library(gfxstream-gl-server emulation_gl.cpp gles_version_detector.cpp pixel_read_formats.cpp + post_worker_gl.cpp readback_worker_gl.cpp render_thread_info_gl.cpp texture_draw.cpp diff --git a/host/gl/emulation_gl.cpp b/host/gl/emulation_gl.cpp index 45287777e..401c16dd9 100644 --- a/host/gl/emulation_gl.cpp +++ b/host/gl/emulation_gl.cpp @@ -29,6 +29,8 @@ #include "gfxstream/common/logging.h" #include "gfxstream/host/color_buffer_interface.h" #include "gfxstream/host/driver_info.h" +#include "gfxstream/host/framework_formats.h" +#include "gfxstream/host/gfxstream_format.h" #include "gfxstream/host/global_state.h" #include "gfxstream/host/renderer_operations.h" #include "gfxstream/host/stream_utils.h" @@ -39,21 +41,31 @@ #include "render_thread_info_gl.h" #include "yuv_converter.h" -namespace gfxstream { -namespace host { -std::optional GetGfxstreamFormat(const FeatureSet& features, - FrameworkFormat format); -} -} // namespace gfxstream - namespace gfxstream { namespace host { namespace gl { namespace { -using gfxstream::host::GfxstreamFormat; -using gfxstream::host::loadCollection; -using gfxstream::host::saveCollection; +std::optional GetGfxstreamFormat(const FeatureSet& features, + FrameworkFormat format) { + switch (format) { + case FRAMEWORK_FORMAT_NV12: + return GfxstreamFormat::NV12; + case FRAMEWORK_FORMAT_YV12: + return GfxstreamFormat::YV12; + case FRAMEWORK_FORMAT_P010: + return GfxstreamFormat::P010; + case FRAMEWORK_FORMAT_YUV_420_888: { + if (features.Yuv420888ToNv21.enabled()) { + return GfxstreamFormat::NV21; + } else { + return GfxstreamFormat::YV21; + } + } + default: + return std::nullopt; + } +} template static void saveProcOwnedCollection(gfxstream::Stream* stream, const Collection& c) { @@ -1514,8 +1526,7 @@ bool EmulationGl::platformDestroySharedEglContext(void* underlyingContext) { void EmulationGl::createYUVTextures(uint32_t type, uint32_t count, int width, int height, uint32_t* output) { - auto formatOpt = - gfxstream::host::GetGfxstreamFormat(mFeatures, static_cast(type)); + auto formatOpt = GetGfxstreamFormat(mFeatures, static_cast(type)); if (!formatOpt) { GFXSTREAM_ERROR("Unsupported framework format %d", type); return; @@ -1551,8 +1562,7 @@ void EmulationGl::createYUVTextures(uint32_t type, uint32_t count, int width, in } void EmulationGl::destroyYUVTextures(uint32_t type, uint32_t count, uint32_t* textures) { - auto formatOpt = - gfxstream::host::GetGfxstreamFormat(mFeatures, static_cast(type)); + auto formatOpt = GetGfxstreamFormat(mFeatures, static_cast(type)); if (!formatOpt) { GFXSTREAM_ERROR("Unsupported framework format %d", type); return; @@ -1568,8 +1578,7 @@ void EmulationGl::destroyYUVTextures(uint32_t type, uint32_t count, uint32_t* te } void EmulationGl::updateYUVTextures(uint32_t type, uint32_t* textures, void* privData, void* func) { - auto formatOpt = - gfxstream::host::GetGfxstreamFormat(mFeatures, static_cast(type)); + auto formatOpt = GetGfxstreamFormat(mFeatures, static_cast(type)); if (!formatOpt) { GFXSTREAM_ERROR("Unsupported framework format %d", type); return; diff --git a/host/gl/meson.build b/host/gl/meson.build index 84a2225c1..440d8365c 100644 --- a/host/gl/meson.build +++ b/host/gl/meson.build @@ -29,6 +29,7 @@ files_lib_gl_server = files( 'emulation_gl.cpp', 'gles_version_detector.cpp', 'pixel_read_formats.cpp', + 'post_worker_gl.cpp', 'readback_worker_gl.cpp', 'render_thread_info_gl.cpp', 'texture_draw.cpp', diff --git a/host/post_worker_gl.cpp b/host/gl/post_worker_gl.cpp similarity index 97% rename from host/post_worker_gl.cpp rename to host/gl/post_worker_gl.cpp index f3c1e415e..711bff5d2 100644 --- a/host/post_worker_gl.cpp +++ b/host/gl/post_worker_gl.cpp @@ -15,13 +15,13 @@ */ #include "post_worker_gl.h" +#include "display_gl.h" +#include "display_surface_gl.h" #include "gfxstream/common/logging.h" #include "gfxstream/host/display_operations.h" #include "gfxstream/host/global_state.h" #include "gfxstream/host/renderer_operations.h" #include "gfxstream/host/window_operations.h" -#include "host/gl/display_gl.h" -#include "host/gl/display_surface_gl.h" namespace gfxstream { namespace host { @@ -141,7 +141,7 @@ std::shared_future PostWorkerGl::postImpl( const auto transform = getTransformFromRotation(m_globalState->getZrot()); postLayerOptions.transform = transform; - if ( transform == HWC_TRANSFORM_ROT_90 || transform == HWC_TRANSFORM_ROT_270) { + if (transform == HWC_TRANSFORM_ROT_90 || transform == HWC_TRANSFORM_ROT_270) { std::swap(currentDisplayW, currentDisplayH); } postLayerOptions.displayFrame = { @@ -225,12 +225,7 @@ DisplayGl::PostLayer PostWorkerGl::postWithOverlay( float dy = py * fy; DisplayGl::PostLayer::OverlayOptions overlayOptions = { - .rotation = static_cast(zRot), - .dx = dx, - .dy = dy, - .scaleX = 1.0f, - .scaleY = 1.0f - }; + .rotation = static_cast(zRot), .dx = dx, .dy = dy, .scaleX = 1.0f, .scaleY = 1.0f}; // Adjust offset and scale parameters if a display layout is given Rect scaledDisplayRect = {}; diff --git a/host/post_worker_gl.h b/host/gl/post_worker_gl.h similarity index 92% rename from host/post_worker_gl.h rename to host/gl/post_worker_gl.h index c1ac19109..88b59a805 100644 --- a/host/post_worker_gl.h +++ b/host/gl/post_worker_gl.h @@ -18,12 +18,12 @@ #include #include +#include "display_gl.h" +#include "emulation_gl.h" #include "gfxstream/host/color_buffer_interface.h" #include "gfxstream/host/display_surface_user.h" #include "gfxstream/host/global_state.h" #include "gfxstream/host/post_worker.h" -#include "host/gl/display_gl.h" -#include "host/gl/emulation_gl.h" namespace gfxstream { namespace host { @@ -35,8 +35,8 @@ class RecursiveScopedContextBind; class PostWorkerGl : public PostWorker, public DisplaySurfaceUser { public: - PostWorkerGl(bool mainThreadPostingOnly, GlobalState* globalState, - Compositor* compositor, gl::DisplayGl* displayGl, gl::EmulationGl* emulationGl); + PostWorkerGl(bool mainThreadPostingOnly, GlobalState* globalState, Compositor* compositor, + gl::DisplayGl* displayGl, gl::EmulationGl* emulationGl); protected: std::shared_future postImpl( diff --git a/host/meson.build b/host/meson.build index b9b3d9b04..e2ca23f56 100644 --- a/host/meson.build +++ b/host/meson.build @@ -62,7 +62,6 @@ files_lib_gfxstream_backend = files( 'channel_stream.cpp', 'color_buffer.cpp', 'frame_buffer.cpp', - 'post_worker.cpp', 'read_buffer.cpp', 'render_api.cpp', 'render_channel_impl.cpp', @@ -104,7 +103,6 @@ inc_gl_openglesdispatch = include_directories('gl/OpenGLESDispatch/include') if use_gles subdir('gl') - files_lib_gfxstream_backend += files('post_worker_gl.cpp') files_lib_gfxstream_backend += files('render_control.cpp') inc_gfxstream_backend += [ From 87c2b822d500e48806d00ed10fa027f41047ebc0 Mon Sep 17 00:00:00 2001 From: Jason Macnak Date: Mon, 3 Aug 2026 10:08:16 -0700 Subject: [PATCH 23/33] Pass IColorBuffer to EmulationGl for some GL funcs ... to try to minimize the usage of GlobalState. Bug: b/537737772 Test: bazel test //host/... Low-Coverage-Reason: REFACTOR_ONLY Change-Id: I2ad91bfb9b5f6bb0bf77644535efa19cd33d5c7f --- host/frame_buffer.cpp | 24 ++++++++------ host/gl/emulation_gl.cpp | 68 +++++++++++++++++++++++++--------------- host/gl/emulation_gl.h | 6 ++-- 3 files changed, 61 insertions(+), 37 deletions(-) diff --git a/host/frame_buffer.cpp b/host/frame_buffer.cpp index 6c1895ab7..3719dc8e3 100644 --- a/host/frame_buffer.cpp +++ b/host/frame_buffer.cpp @@ -4275,16 +4275,20 @@ ContextHelper* FrameBuffer::Impl::getPbufferSurfaceContextHelper() const { return displaySurfaceGl->getContextHelper(); } -bool FrameBuffer::Impl::bindColorBufferToTexture(HandleType p_colorbuffer) - NO_THREAD_SAFETY_ANALYSIS { +bool FrameBuffer::Impl::bindColorBufferToTexture(HandleType colorBufferHandle) { ENSURE_GL_EMULATION_VALUE(false); + + IColorBufferRef colorBuffer = findColorBuffer(colorBufferHandle); + AutoLock mutex(m_lock); - return m_emulationGl->bindColorBufferToTexture(p_colorbuffer); + return m_emulationGl->bindColorBufferToTexture(colorBuffer.get()); } -bool FrameBuffer::Impl::bindColorBufferToTexture2(HandleType p_colorbuffer) - NO_THREAD_SAFETY_ANALYSIS { +bool FrameBuffer::Impl::bindColorBufferToTexture2(HandleType colorBufferHandle) { ENSURE_GL_EMULATION_VALUE(false); + + IColorBufferRef colorBuffer = findColorBuffer(colorBufferHandle); + // This is only called when using multi window display // It will deadlock when posting from main thread. std::unique_ptr mutex; @@ -4292,14 +4296,16 @@ bool FrameBuffer::Impl::bindColorBufferToTexture2(HandleType p_colorbuffer) mutex = std::make_unique(m_lock); } - return m_emulationGl->bindColorBufferToTexture2(p_colorbuffer); + return m_emulationGl->bindColorBufferToTexture2(colorBuffer.get()); } -bool FrameBuffer::Impl::bindColorBufferToRenderbuffer(HandleType p_colorbuffer) - NO_THREAD_SAFETY_ANALYSIS { +bool FrameBuffer::Impl::bindColorBufferToRenderbuffer(HandleType colorBufferHandle) { ENSURE_GL_EMULATION_VALUE(false); + + IColorBufferRef colorBuffer = findColorBuffer(colorBufferHandle); + AutoLock mutex(m_lock); - return m_emulationGl->bindColorBufferToRenderbuffer(p_colorbuffer); + return m_emulationGl->bindColorBufferToRenderbuffer(colorBuffer.get()); } bool FrameBuffer::Impl::bindContext(HandleType p_context, HandleType p_drawSurface, diff --git a/host/gl/emulation_gl.cpp b/host/gl/emulation_gl.cpp index 401c16dd9..65f8a560d 100644 --- a/host/gl/emulation_gl.cpp +++ b/host/gl/emulation_gl.cpp @@ -1090,31 +1090,49 @@ EmulatedEglWindowSurfacePtr EmulationGl::getWindowSurface(HandleType surfaceHand return gfxstream::base::findOrDefault(mWindows, surfaceHandle).first; } -bool EmulationGl::bindColorBufferToTexture(HandleType colorBufferHandle) { - IColorBufferRef cb = mGlobalState->findColorBuffer(colorBufferHandle); - if (!cb) return false; - cb->touch(); - auto cbGl = cb->getColorBufferGl(); - if (!cbGl) return false; - return cbGl->bindToTexture(); -} - -bool EmulationGl::bindColorBufferToTexture2(HandleType colorBufferHandle) { - IColorBufferRef cb = mGlobalState->findColorBuffer(colorBufferHandle); - if (!cb) return false; - cb->touch(); - auto cbGl = cb->getColorBufferGl(); - if (!cbGl) return false; - return cbGl->bindToTexture2(); -} - -bool EmulationGl::bindColorBufferToRenderbuffer(HandleType colorBufferHandle) { - IColorBufferRef cb = mGlobalState->findColorBuffer(colorBufferHandle); - if (!cb) return false; - cb->touch(); - auto cbGl = cb->getColorBufferGl(); - if (!cbGl) return false; - return cbGl->bindToRenderbuffer(); +bool EmulationGl::bindColorBufferToTexture(IColorBuffer* colorBuffer) { + if (!colorBuffer) { + GFXSTREAM_ERROR("Failed to bind to texture: invalid color buffer."); + return false; + } + colorBuffer->touch(); + + auto colorBufferGl = colorBuffer->getColorBufferGl(); + if (!colorBufferGl) { + GFXSTREAM_ERROR("Failed to bind to texture: invalid color buffer gl."); + return false; + } + return colorBufferGl->bindToTexture(); +} + +bool EmulationGl::bindColorBufferToTexture2(IColorBuffer* colorBuffer) { + if (!colorBuffer) { + GFXSTREAM_ERROR("Failed to bind to texture: invalid color buffer."); + return false; + } + colorBuffer->touch(); + + auto colorBufferGl = colorBuffer->getColorBufferGl(); + if (!colorBufferGl) { + GFXSTREAM_ERROR("Failed to bind to texture: invalid color buffer gl."); + return false; + } + return colorBufferGl->bindToTexture2(); +} + +bool EmulationGl::bindColorBufferToRenderbuffer(IColorBuffer* colorBuffer) { + if (!colorBuffer) { + GFXSTREAM_ERROR("Failed to bind to renderbuffer: invalid color buffer."); + return false; + } + colorBuffer->touch(); + + auto colorBufferGl = colorBuffer->getColorBufferGl(); + if (!colorBufferGl) { + GFXSTREAM_ERROR("Failed to bind to renderbuffer: invalid color buffer gl."); + return false; + } + return colorBufferGl->bindToRenderbuffer(); } bool EmulationGl::bindContext(HandleType contextHandle, HandleType drawSurfaceHandle, diff --git a/host/gl/emulation_gl.h b/host/gl/emulation_gl.h index b7d88839e..4b2f9333b 100644 --- a/host/gl/emulation_gl.h +++ b/host/gl/emulation_gl.h @@ -159,9 +159,9 @@ class EmulationGl { std::unique_ptr createFakeWindowSurface(); - bool bindColorBufferToTexture(HandleType colorBufferHandle); - bool bindColorBufferToTexture2(HandleType colorBufferHandle); - bool bindColorBufferToRenderbuffer(HandleType colorBufferHandle); + bool bindColorBufferToTexture(IColorBuffer* colorBuffer); + bool bindColorBufferToTexture2(IColorBuffer* colorBuffer); + bool bindColorBufferToRenderbuffer(IColorBuffer* colorBuffer); bool bindContext(HandleType contextHandle, HandleType drawSurfaceHandle, HandleType readSurfaceHandle); bool bindColorBufferToWindowSurface(HandleType surfaceHandle, HandleType colorBufferHandle, From 2093a6b6778ef917e1dce5979cd163201ec077ba Mon Sep 17 00:00:00 2001 From: Jason Macnak Date: Mon, 3 Aug 2026 08:43:47 -0700 Subject: [PATCH 24/33] Remove unused gfx_stream_backend_init_override Bug: b/537737772 Test: bazel test //host/... Low-Coverage-Reason: REFACTOR_ONLY Change-Id: Ic20b3f118342b37e79f23d308466c71944e84f1e --- host/gfx_stream_backend_init_override.cpp | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 host/gfx_stream_backend_init_override.cpp diff --git a/host/gfx_stream_backend_init_override.cpp b/host/gfx_stream_backend_init_override.cpp deleted file mode 100644 index 9d8859d64..000000000 --- a/host/gfx_stream_backend_init_override.cpp +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (C) 2022 The Android Open Source Project -// -// 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. - -#include "render-utils/virtio-gpu-gfxstream-renderer.h" - -void gfxstream_backend_init_product_override() {} From 177847d2bb7b8136117636c6db02171425bf2238 Mon Sep 17 00:00:00 2001 From: Jason Macnak Date: Mon, 3 Aug 2026 10:40:02 -0700 Subject: [PATCH 25/33] Apply --warn-backrefs and --fatal-warnings in linkopts ... to help prevent in the future. This change also fixes some existing sign errors and applies `buildifier -r .`. Bug: b/537737772 Test: bazel test //host/... Low-Coverage-Reason: REFACTOR_ONLY Change-Id: I00dfa39f1db6e53f156e435aed3ded7f0869474a --- build_variables.bzl | 10 ++++++++++ host/BUILD.bazel | 8 +++++++- host/address_space/BUILD.bazel | 4 +++- host/common/BUILD.bazel | 3 ++- host/compressed_textures/BUILD.bazel | 4 +++- host/decoder_common/BUILD.bazel | 3 ++- host/features/BUILD.bazel | 4 +++- host/gl/BUILD.bazel | 3 ++- host/gl/OpenGLESDispatch/BUILD.bazel | 4 +++- host/gl/gles1_dec/BUILD.bazel | 3 ++- host/gl/gles2_dec/BUILD.bazel | 3 ++- host/gl/glestranslator/common/BUILD.bazel | 4 +++- host/gl/glestranslator/egl/BUILD.bazel | 4 +++- host/gl/glestranslator/gles_cm/BUILD.bazel | 3 ++- host/gl/glestranslator/gles_v2/BUILD.bazel | 3 ++- host/gl/glsnapshot/BUILD.bazel | 3 ++- host/iostream/BUILD.bazel | 3 ++- host/library/BUILD.bazel | 3 ++- host/native_window/BUILD.bazel | 3 ++- host/renderControl_dec/BUILD.bazel | 3 ++- host/renderdoc/BUILD.bazel | 4 +++- host/snapshot/BUILD.bazel | 3 ++- host/testlibs/oswindow/BUILD.bazel | 3 ++- host/testlibs/support/BUILD.bazel | 3 ++- host/tests/BUILD.bazel | 4 ++++ host/tests/GLSnapshotPrograms_unittest.cpp | 8 ++++---- host/tests/GLSnapshotRenderbuffers_unittest.cpp | 7 ++++--- host/tests/GLSnapshotTextures_unittest.cpp | 17 ++++++++--------- .../GLSnapshotVertexAttributes_unittest.cpp | 2 +- host/tracing/BUILD.bazel | 3 ++- host/vulkan/BUILD.bazel | 12 ++++++++++-- host/vulkan/cereal/BUILD.bazel | 4 +++- host/vulkan/emulated_textures/BUILD.bazel | 3 ++- 33 files changed, 106 insertions(+), 45 deletions(-) diff --git a/build_variables.bzl b/build_variables.bzl index 73f196c86..8c6ecdcc6 100644 --- a/build_variables.bzl +++ b/build_variables.bzl @@ -1,6 +1,7 @@ """ Common build configuration definitions. """ + GFXSTREAM_COMMON_COPTS = [ "-Wall", "-Wextra", @@ -26,6 +27,7 @@ GFXSTREAM_COMMON_COPTS = [ ], "//conditions:default": [], }) + GFXSTREAM_HOST_COPTS = GFXSTREAM_COMMON_COPTS + [ ] + select({ "@platforms//os:windows": [ @@ -35,6 +37,7 @@ GFXSTREAM_HOST_COPTS = GFXSTREAM_COMMON_COPTS + [ "-fno-exceptions", ], }) + GFXSTREAM_HOST_VK_DEFINES = [ "VK_GFXSTREAM_STRUCTURE_TYPE_EXT", "VK_GOOGLE_gfxstream", @@ -51,6 +54,7 @@ GFXSTREAM_HOST_VK_DEFINES = [ ], "//conditions:default": [], }) + GFXSTREAM_HOST_DEFINES = GFXSTREAM_HOST_VK_DEFINES + [ "BUILDING_EMUGL_COMMON_SHARED", "EMUGL_BUILD", @@ -78,3 +82,9 @@ GFXSTREAM_HOST_DEFINES = GFXSTREAM_HOST_VK_DEFINES + [ ], "//conditions:default": [], }) + +GFXSTREAM_HOST_LINKOPTS = [ + "-Wl,--warn-backrefs", + "-Wl,--warn-backrefs-exclude=*llvm*", + "-Wl,--fatal-warnings", +] diff --git a/host/BUILD.bazel b/host/BUILD.bazel index 5f2d3f89c..6adcb4092 100644 --- a/host/BUILD.bazel +++ b/host/BUILD.bazel @@ -1,7 +1,7 @@ load("@protobuf//bazel:cc_proto_library.bzl", "cc_proto_library") load("@protobuf//bazel:proto_library.bzl", "proto_library") load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -56,6 +56,7 @@ cc_library( defines = GFXSTREAM_HOST_DEFINES, features = ["-parse_headers"], includes = ["include"], + linkopts = GFXSTREAM_HOST_LINKOPTS, visibility = ["//visibility:public"], deps = [ "//host/features:gfxstream_host_features", @@ -123,6 +124,7 @@ cc_library( includes = [ ".", ], + linkopts = GFXSTREAM_HOST_LINKOPTS, linkstatic = True, visibility = ["//visibility:public"], deps = [ @@ -173,6 +175,7 @@ cc_library( "-Wno-return-type-c-linkage", ], defines = GFXSTREAM_HOST_DEFINES, + linkopts = GFXSTREAM_HOST_LINKOPTS, linkstatic = True, visibility = ["//visibility:public"], deps = [ @@ -197,6 +200,7 @@ cc_binary( ], copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, + linkopts = GFXSTREAM_HOST_LINKOPTS, linkshared = True, visibility = ["//visibility:public"], deps = [ @@ -219,6 +223,7 @@ cc_test( "frame_buffer_unittest.cpp", ], copts = GFXSTREAM_HOST_COPTS, + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ ":gfxstream_backend_static", "//common/base:gfxstream_common_base", @@ -239,6 +244,7 @@ cc_test( "vsync_thread_unittest.cpp", ], copts = GFXSTREAM_HOST_COPTS, + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ ":gfxstream_backend_static", "//host/testlibs/support:gfxstream_host_testing_support", diff --git a/host/address_space/BUILD.bazel b/host/address_space/BUILD.bazel index 6db554cfb..6b7a9ef48 100644 --- a/host/address_space/BUILD.bazel +++ b/host/address_space/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -17,6 +17,7 @@ cc_library( hdrs = glob(["include/**/*.h"]), copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, + linkopts = GFXSTREAM_HOST_LINKOPTS, strip_include_prefix = "include", deps = [ "//common/base:gfxstream_common_base", @@ -30,6 +31,7 @@ cc_test( srcs = [ "ring_buffer_unittest.cpp", ], + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ ":gfxstream_host_address_space", "//common/base:gfxstream_common_base", diff --git a/host/common/BUILD.bazel b/host/common/BUILD.bazel index 49a65fa8b..1df552727 100644 --- a/host/common/BUILD.bazel +++ b/host/common/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -31,6 +31,7 @@ cc_library( copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, includes = ["include"], + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ "//common/base:gfxstream_common_base", "//common/logging:gfxstream_common_logging", diff --git a/host/compressed_textures/BUILD.bazel b/host/compressed_textures/BUILD.bazel index 9a0e4e1f9..a2d295519 100644 --- a/host/compressed_textures/BUILD.bazel +++ b/host/compressed_textures/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -14,6 +14,7 @@ cc_library( hdrs = glob(["include/**/*.h"]), copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, + linkopts = GFXSTREAM_HOST_LINKOPTS, strip_include_prefix = "include", deps = [ "//common/etc:gfxstream_etc", @@ -26,6 +27,7 @@ cc_test( "astc_cpu_decompressor_unittest.cpp", ], copts = GFXSTREAM_HOST_COPTS, + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ ":gfxstream_host_compressed_textures", "@com_google_googletest//:gtest", diff --git a/host/decoder_common/BUILD.bazel b/host/decoder_common/BUILD.bazel index 585e759cf..b58dc67ba 100644 --- a/host/decoder_common/BUILD.bazel +++ b/host/decoder_common/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -27,6 +27,7 @@ cc_library( ".", "include", ], + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ "//common/base:gfxstream_common_base", "//common/logging:gfxstream_common_logging", diff --git a/host/features/BUILD.bazel b/host/features/BUILD.bazel index f0bbe8712..8618b5375 100644 --- a/host/features/BUILD.bazel +++ b/host/features/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -13,6 +13,7 @@ cc_library( copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, includes = ["include"], + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ "//common/logging:gfxstream_common_logging", "//common/utils:gfxstream_common_utils", @@ -25,6 +26,7 @@ cc_test( "features_unittest.cpp", ], copts = GFXSTREAM_HOST_COPTS, + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ ":gfxstream_host_features", "@com_google_googletest//:gtest", diff --git a/host/gl/BUILD.bazel b/host/gl/BUILD.bazel index ef06a2e8a..a9dfe430f 100644 --- a/host/gl/BUILD.bazel +++ b/host/gl/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -62,6 +62,7 @@ cc_library( includes = [ ".", ], + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ "//common/base:gfxstream_common_base", "//common/logging:gfxstream_common_logging", diff --git a/host/gl/OpenGLESDispatch/BUILD.bazel b/host/gl/OpenGLESDispatch/BUILD.bazel index 16f40cd0f..23cbf9f78 100644 --- a/host/gl/OpenGLESDispatch/BUILD.bazel +++ b/host/gl/OpenGLESDispatch/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -19,6 +19,7 @@ cc_library( copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, includes = ["include"], + linkopts = GFXSTREAM_HOST_LINKOPTS, textual_hdrs = [ "include/OpenGLESDispatch/gldefs.h", "include/OpenGLESDispatch/gles_common_for_gles1_static_translator_namespaced_header.h", @@ -78,6 +79,7 @@ cc_library( "-Wno-extern-c-compat", ], defines = GFXSTREAM_HOST_DEFINES, + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ ":gfxstream_host_openglesdispatch_headers", "//host/common:gfxstream_host_common", diff --git a/host/gl/gles1_dec/BUILD.bazel b/host/gl/gles1_dec/BUILD.bazel index 1f4168ded..6f5f0b105 100644 --- a/host/gl/gles1_dec/BUILD.bazel +++ b/host/gl/gles1_dec/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -16,6 +16,7 @@ cc_library( hdrs = glob(["*.h"]), copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ "//common/base:gfxstream_common_base", "//common/logging:gfxstream_common_logging", diff --git a/host/gl/gles2_dec/BUILD.bazel b/host/gl/gles2_dec/BUILD.bazel index 9af66cfa1..d9c131204 100644 --- a/host/gl/gles2_dec/BUILD.bazel +++ b/host/gl/gles2_dec/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -16,6 +16,7 @@ cc_library( hdrs = glob(["*.h"]), copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ "//common/base:gfxstream_common_base", "//common/logging:gfxstream_common_logging", diff --git a/host/gl/glestranslator/common/BUILD.bazel b/host/gl/glestranslator/common/BUILD.bazel index de7ad2bbf..29edabe53 100644 --- a/host/gl/glestranslator/common/BUILD.bazel +++ b/host/gl/glestranslator/common/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -12,6 +12,7 @@ cc_library( copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, includes = ["include"], + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ "//common/base:gfxstream_common_base", "//common/etc:gfxstream_etc", @@ -55,6 +56,7 @@ cc_library( "-Wno-extern-c-compat", ], defines = GFXSTREAM_HOST_DEFINES, + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ "//common/base:gfxstream_common_base", "//common/etc:gfxstream_etc", diff --git a/host/gl/glestranslator/egl/BUILD.bazel b/host/gl/glestranslator/egl/BUILD.bazel index 7b759c68d..c952cbc54 100644 --- a/host/gl/glestranslator/egl/BUILD.bazel +++ b/host/gl/glestranslator/egl/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library", "objc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -64,6 +64,7 @@ cc_library( copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, includes = ["glestranslator/egl"], + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ "//common/base:gfxstream_common_base", "//host:gfxstream_backend_headers", @@ -139,6 +140,7 @@ cc_library( "-Wno-return-type-c-linkage", ], defines = GFXSTREAM_HOST_DEFINES, + linkopts = GFXSTREAM_HOST_LINKOPTS, textual_hdrs = [ "client_api_exts.in", ], diff --git a/host/gl/glestranslator/gles_cm/BUILD.bazel b/host/gl/glestranslator/gles_cm/BUILD.bazel index cc8dd020d..6faeedfc0 100644 --- a/host/gl/glestranslator/gles_cm/BUILD.bazel +++ b/host/gl/glestranslator/gles_cm/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -19,6 +19,7 @@ cc_library( "-Wno-extern-c-compat", ], defines = GFXSTREAM_HOST_DEFINES, + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ "//common/base:gfxstream_common_base", "//common/logging:gfxstream_common_logging", diff --git a/host/gl/glestranslator/gles_v2/BUILD.bazel b/host/gl/glestranslator/gles_v2/BUILD.bazel index 16d96dc5a..640c820c6 100644 --- a/host/gl/glestranslator/gles_v2/BUILD.bazel +++ b/host/gl/glestranslator/gles_v2/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -30,6 +30,7 @@ cc_library( ], defines = GFXSTREAM_HOST_DEFINES, includes = ["."], + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ "//common/base:gfxstream_common_base", "//common/logging:gfxstream_common_logging", diff --git a/host/gl/glsnapshot/BUILD.bazel b/host/gl/glsnapshot/BUILD.bazel index b42d7d820..bba9735ab 100644 --- a/host/gl/glsnapshot/BUILD.bazel +++ b/host/gl/glsnapshot/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -15,6 +15,7 @@ cc_library( ], defines = GFXSTREAM_HOST_DEFINES, includes = ["."], + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ "//host/decoder_common:gfxstream_host_decoder_common", "//host/gl/OpenGLESDispatch:gfxstream_host_openglesdispatch", diff --git a/host/iostream/BUILD.bazel b/host/iostream/BUILD.bazel index 70a35e883..0da6533e2 100644 --- a/host/iostream/BUILD.bazel +++ b/host/iostream/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -12,6 +12,7 @@ cc_library( copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, includes = ["include"], + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ "//common/logging:gfxstream_common_logging", "//host:gfxstream_backend_headers", diff --git a/host/library/BUILD.bazel b/host/library/BUILD.bazel index 5b2b26117..fd464e155 100644 --- a/host/library/BUILD.bazel +++ b/host/library/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -13,6 +13,7 @@ cc_library( copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, includes = ["include"], + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ "//common/base:gfxstream_common_base", "//common/logging:gfxstream_common_logging", diff --git a/host/native_window/BUILD.bazel b/host/native_window/BUILD.bazel index 08120e950..62a08f204 100644 --- a/host/native_window/BUILD.bazel +++ b/host/native_window/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library", "objc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -55,6 +55,7 @@ cc_library( copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, includes = ["include"], + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = select({ "@platforms//os:macos": [ ":gfxstream_host_native_window-darwin", diff --git a/host/renderControl_dec/BUILD.bazel b/host/renderControl_dec/BUILD.bazel index 32cdb8509..4f506dfbf 100644 --- a/host/renderControl_dec/BUILD.bazel +++ b/host/renderControl_dec/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -22,6 +22,7 @@ cc_library( copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, includes = ["."], + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ "//common/logging:gfxstream_common_logging", "//host/decoder_common:gfxstream_host_decoder_common", diff --git a/host/renderdoc/BUILD.bazel b/host/renderdoc/BUILD.bazel index d7ae9c58d..56f86caa2 100644 --- a/host/renderdoc/BUILD.bazel +++ b/host/renderdoc/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -12,6 +12,7 @@ cc_library( copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, includes = ["include"], + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ "//common/logging:gfxstream_common_logging", "//host/library:gfxstream_host_library", @@ -26,6 +27,7 @@ cc_test( srcs = [ "renderdoc_unittest.cpp", ], + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ ":gfxstream_host_renderdoc", "//host/library:gfxstream_host_library", diff --git a/host/snapshot/BUILD.bazel b/host/snapshot/BUILD.bazel index d77cec667..444502b35 100644 --- a/host/snapshot/BUILD.bazel +++ b/host/snapshot/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -13,6 +13,7 @@ cc_library( ], copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, + linkopts = GFXSTREAM_HOST_LINKOPTS, strip_include_prefix = "include", deps = [ "//host:gfxstream_backend_headers", diff --git a/host/testlibs/oswindow/BUILD.bazel b/host/testlibs/oswindow/BUILD.bazel index a4297aa4e..3721b918c 100644 --- a/host/testlibs/oswindow/BUILD.bazel +++ b/host/testlibs/oswindow/BUILD.bazel @@ -13,7 +13,7 @@ # limitations under the License. load("@rules_cc//cc:defs.bzl", "cc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -54,6 +54,7 @@ cc_library( }), copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, + linkopts = GFXSTREAM_HOST_LINKOPTS, strip_include_prefix = "include", deps = [ "//common/logging:gfxstream_common_logging", diff --git a/host/testlibs/support/BUILD.bazel b/host/testlibs/support/BUILD.bazel index 59e1b03c7..98a53880f 100644 --- a/host/testlibs/support/BUILD.bazel +++ b/host/testlibs/support/BUILD.bazel @@ -13,7 +13,7 @@ # limitations under the License. load("@rules_cc//cc:defs.bzl", "cc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -36,6 +36,7 @@ cc_library( hdrs = glob(["include/**/*.h"]), copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, + linkopts = GFXSTREAM_HOST_LINKOPTS, strip_include_prefix = "include", deps = [ "//common/base:gfxstream_common_base", diff --git a/host/tests/BUILD.bazel b/host/tests/BUILD.bazel index acac2cb92..c80cae3ca 100644 --- a/host/tests/BUILD.bazel +++ b/host/tests/BUILD.bazel @@ -13,6 +13,7 @@ # limitations under the License. load("@rules_cc//cc:defs.bzl", "cc_test") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -38,6 +39,9 @@ cc_test( "GLSnapshotVertexAttributes_unittest.cpp", "GLSnapshot_unittest.cpp", ], + copts = GFXSTREAM_HOST_COPTS, + defines = GFXSTREAM_HOST_DEFINES, + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ "//host:gfxstream_backend_static", "//host/decoder_common:gfxstream_host_decoder_common", diff --git a/host/tests/GLSnapshotPrograms_unittest.cpp b/host/tests/GLSnapshotPrograms_unittest.cpp index 7bfc11d32..ad3c08aa9 100644 --- a/host/tests/GLSnapshotPrograms_unittest.cpp +++ b/host/tests/GLSnapshotPrograms_unittest.cpp @@ -114,7 +114,7 @@ class SnapshotGlProgramTest : public SnapshotPreserveTest { currentState.maxAttributeName); ASSERT_EQ(m_program_state.attributes.size(), currentState.attributes.size()); - for (int i = 0; i < currentState.attributes.size(); i++) { + for (size_t i = 0; i < currentState.attributes.size(); i++) { SCOPED_TRACE("active attribute i = " + std::to_string(i)); EXPECT_EQ(m_program_state.attributes[i].size, currentState.attributes[i].size); @@ -132,7 +132,7 @@ class SnapshotGlProgramTest : public SnapshotPreserveTest { EXPECT_EQ(m_program_state.maxUniformName, currentState.maxUniformName); ASSERT_EQ(m_program_state.uniforms.size(), currentState.uniforms.size()); - for (int i = 0; i < currentState.uniforms.size(); i++) { + for (size_t i = 0; i < currentState.uniforms.size(); i++) { SCOPED_TRACE("active uniform i = " + std::to_string(i)); EXPECT_EQ(m_program_state.uniforms[i].size, currentState.uniforms[i].size); @@ -225,7 +225,7 @@ class SnapshotGlProgramTest : public SnapshotPreserveTest { EXPECT_GE(ret.maxUniformName, 0); gl->glGetProgramiv(m_program_name, GL_ACTIVE_UNIFORMS, &ret.activeUniforms); - for (GLuint i = 0; i < ret.activeUniforms; i++) { + for (GLint i = 0; i < ret.activeUniforms; i++) { GlShaderVariable unif = {}; unif.name.resize(ret.maxUniformName); GLsizei unifLen; @@ -260,7 +260,7 @@ class SnapshotGlProgramTest : public SnapshotPreserveTest { EXPECT_GE(ret.maxAttributeName, 0); gl->glGetProgramiv(m_program_name, GL_ACTIVE_ATTRIBUTES, &ret.activeAttributes); - for (GLuint i = 0; i < ret.activeAttributes; i++) { + for (GLint i = 0; i < ret.activeAttributes; i++) { GlShaderVariable attr = {}; attr.name.resize(ret.maxAttributeName); GLsizei attrLen; diff --git a/host/tests/GLSnapshotRenderbuffers_unittest.cpp b/host/tests/GLSnapshotRenderbuffers_unittest.cpp index ae827af91..261017c8b 100644 --- a/host/tests/GLSnapshotRenderbuffers_unittest.cpp +++ b/host/tests/GLSnapshotRenderbuffers_unittest.cpp @@ -137,13 +137,14 @@ TEST_P(SnapshotGlRenderbufferFormatTest, SetFormat) { GLint maxSize; gl->glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &maxSize); m_state = GetParam(); - if (maxSize < m_state.width || maxSize < m_state.height) { + if (static_cast(maxSize) < m_state.width || + static_cast(maxSize) < m_state.height) { fprintf(stderr, "test dimensions exceed max renderbuffer size %d; " "using max size instead\n", maxSize); - m_state.width = maxSize; - m_state.height = maxSize; + m_state.width = static_cast(maxSize); + m_state.height = static_cast(maxSize); } gl->glRenderbufferStorage(GL_RENDERBUFFER, m_state.format.name, m_state.width, m_state.height); diff --git a/host/tests/GLSnapshotTextures_unittest.cpp b/host/tests/GLSnapshotTextures_unittest.cpp index 3194d704d..c007deef2 100644 --- a/host/tests/GLSnapshotTextures_unittest.cpp +++ b/host/tests/GLSnapshotTextures_unittest.cpp @@ -201,7 +201,7 @@ class SnapshotGlTextureUnitActiveTest : public SnapshotPreserveTest { &maxTextureUnits); EXPECT_EQ(GL_NO_ERROR, gl->glGetError()); - if (unit < maxTextureUnits) { + if (unit < static_cast(maxTextureUnits)) { m_active_texture_unit = unit; } else { fprintf(stderr, @@ -269,12 +269,12 @@ class SnapshotGlTextureUnitBindingsTest : public SnapshotPreserveTest { GLint maxTextureUnits; gl->glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits); - if (unit >= maxTextureUnits) { + if (unit >= static_cast(maxTextureUnits)) { fprintf(stderr, "Cannot bind to unit %d: max units is %d. Binding to %d " "instead.\n", unit, maxTextureUnits, maxTextureUnits - 1); - unit = maxTextureUnits - 1; + unit = static_cast(maxTextureUnits) - 1; } GLuint testTexture; @@ -330,9 +330,8 @@ class SnapshotGlTextureObjectTest : public SnapshotPreserveTest { EXPECT_TRUE(compareParameter(GL_TEXTURE_WRAP_S, m_state.wrapS)); EXPECT_TRUE(compareParameter(GL_TEXTURE_WRAP_T, m_state.wrapT)); - auto compareImageFunc = [this](GLenum imageTarget, - GlMipmapArray& levels) { - for (int i = 0; i < levels.size(); i++) { + auto compareImageFunc = [this](GLenum imageTarget, GlMipmapArray& levels) { + for (size_t i = 0; i < levels.size(); i++) { EXPECT_TRUE(compareVector( levels[i].bytes, getTextureImageData(gl, m_object_name, imageTarget, i, @@ -354,7 +353,7 @@ class SnapshotGlTextureObjectTest : public SnapshotPreserveTest { << " 'sides' of data."; break; } - for (int j = 0; j < m_state.imagesCubeMap.size(); j++) { + for (size_t j = 0; j < m_state.imagesCubeMap.size(); j++) { compareImageFunc(kGLES2TextureCubeMapSides[j], m_state.imagesCubeMap[j]); } @@ -382,7 +381,7 @@ class SnapshotGlTextureObjectTest : public SnapshotPreserveTest { gl->glTexParameteri(m_state.target, GL_TEXTURE_WRAP_T, m_state.wrapT); auto initImageFunc = [this](GLenum imageTarget, GlMipmapArray& levels) { - for (int i = 0; i < levels.size(); i++) { + for (size_t i = 0; i < levels.size(); i++) { levels[i].bytes.resize( levels[i].width * levels[i].height * glUtilsPixelBitSize( @@ -407,7 +406,7 @@ class SnapshotGlTextureObjectTest : public SnapshotPreserveTest { << " 'sides' of data."; break; } - for (int j = 0; j < m_state.imagesCubeMap.size(); j++) { + for (size_t j = 0; j < m_state.imagesCubeMap.size(); j++) { GLenum side = kGLES2TextureCubeMapSides[j]; initImageFunc(side, m_state.imagesCubeMap[j]); } diff --git a/host/tests/GLSnapshotVertexAttributes_unittest.cpp b/host/tests/GLSnapshotVertexAttributes_unittest.cpp index 98324467c..962210490 100644 --- a/host/tests/GLSnapshotVertexAttributes_unittest.cpp +++ b/host/tests/GLSnapshotVertexAttributes_unittest.cpp @@ -76,7 +76,7 @@ class SnapshotGlVertexAttributesTest GLint maxAttribs; gl->glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxAttribs); EXPECT_EQ(GL_NO_ERROR, gl->glGetError()); - if (index >= maxAttribs) { + if (index >= static_cast(maxAttribs)) { fprintf(stderr, "cannot select index %d: GL_MAX_VERTEX_ATTRIBS is %d.\n", index, maxAttribs); diff --git a/host/tracing/BUILD.bazel b/host/tracing/BUILD.bazel index cc5f4eff4..af6028616 100644 --- a/host/tracing/BUILD.bazel +++ b/host/tracing/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -13,5 +13,6 @@ cc_library( copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, includes = ["include"], + linkopts = GFXSTREAM_HOST_LINKOPTS, strip_include_prefix = "include", ) diff --git a/host/vulkan/BUILD.bazel b/host/vulkan/BUILD.bazel index 81835f357..dc2c8a7a2 100644 --- a/host/vulkan/BUILD.bazel +++ b/host/vulkan/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -11,6 +11,7 @@ cc_library( copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, includes = ["."], + linkopts = GFXSTREAM_HOST_LINKOPTS, textual_hdrs = [ "vk_android_native_buffer_gfxstream.h", "vk_android_native_buffer_structure_type.h", @@ -41,6 +42,7 @@ cc_library( copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, includes = ["."], + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ ":gfxstream_vulkan_headers", "//common/base:gfxstream_common_base", @@ -141,7 +143,7 @@ cc_library( "cereal", "cereal/common", ], - linkopts = select({ + linkopts = GFXSTREAM_HOST_LINKOPTS + select({ "@platforms//os:windows": [ "-DEFAULTLIB:Advapi32.lib", ], @@ -212,6 +214,7 @@ cc_test( "testdata/256x256_golden_transform_rot270.png", "testdata/256x256_golden_transform_rot90.png", ], + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ ":gfxstream_vulkan_server", "//common/base:gfxstream_common_base", @@ -231,6 +234,7 @@ cc_test( "display_vk_unittest.cpp", ], copts = GFXSTREAM_HOST_COPTS, + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ ":gfxstream_vulkan_server", "//common/base:gfxstream_common_base", @@ -247,6 +251,7 @@ cc_test( "vk_format_utils_unittest.cpp", ], copts = GFXSTREAM_HOST_COPTS, + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ ":gfxstream_vulkan_server", "//common/base:gfxstream_common_base", @@ -262,6 +267,7 @@ cc_test( "vk_common_operations_tests.cpp", ], copts = GFXSTREAM_HOST_COPTS, + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ ":gfxstream_vulkan_server", "//common/base:gfxstream_common_base", @@ -279,6 +285,7 @@ cc_test( "vk_emulated_physical_device_memory_tests.cpp", ], copts = GFXSTREAM_HOST_COPTS, + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ ":gfxstream_vulkan_server", "//common/base:gfxstream_common_base", @@ -295,6 +302,7 @@ cc_test( "vk_emulated_physical_device_queue_tests.cpp", ], copts = GFXSTREAM_HOST_COPTS, + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ ":gfxstream_vulkan_server", "//common/base:gfxstream_common_base", diff --git a/host/vulkan/cereal/BUILD.bazel b/host/vulkan/cereal/BUILD.bazel index c932112a7..378d8f71e 100644 --- a/host/vulkan/cereal/BUILD.bazel +++ b/host/vulkan/cereal/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -19,6 +19,7 @@ cc_library( copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, includes = ["common"], + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ "//common/base:gfxstream_common_base", "//common/logging:gfxstream_common_logging", @@ -51,6 +52,7 @@ cc_library( copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, includes = ["common"], + linkopts = GFXSTREAM_HOST_LINKOPTS, deps = [ "//common/base:gfxstream_common_base", "//common/logging:gfxstream_common_logging", diff --git a/host/vulkan/emulated_textures/BUILD.bazel b/host/vulkan/emulated_textures/BUILD.bazel index 63eb6ae4d..c6fc03635 100644 --- a/host/vulkan/emulated_textures/BUILD.bazel +++ b/host/vulkan/emulated_textures/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES") +load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") package( default_applicable_licenses = ["//:gfxstream_license"], @@ -21,6 +21,7 @@ cc_library( ], copts = GFXSTREAM_HOST_COPTS, defines = GFXSTREAM_HOST_DEFINES, + linkopts = GFXSTREAM_HOST_LINKOPTS, textual_hdrs = glob([ "**/*.inl", ]), From 29ccd1fd8c7e7960ebf0a70da202045f2781cf13 Mon Sep 17 00:00:00 2001 From: Jason Macnak Date: Mon, 3 Aug 2026 10:11:54 -0700 Subject: [PATCH 26/33] Add "shallow" suffix to image create info field ... to help clarify that the pNext chain will not be there. Bug: b/537737772 Test: bazel test //host/... Low-Coverage-Reason: REFACTOR_ONLY Change-Id: I1ec55bdeac9a19065eaf6751423e03a06d599376 --- host/vulkan/color_buffer_vk.h | 2 +- host/vulkan/compositor_vk.cpp | 22 ++++++++++++---------- host/vulkan/compositor_vk_unittest.cpp | 2 +- host/vulkan/display_vk.cpp | 15 ++++++++------- host/vulkan/display_vk_unittest.cpp | 2 +- host/vulkan/vk_common_operations.cpp | 4 ++-- 6 files changed, 25 insertions(+), 22 deletions(-) diff --git a/host/vulkan/color_buffer_vk.h b/host/vulkan/color_buffer_vk.h index a4b3c3527..e649d4fd8 100644 --- a/host/vulkan/color_buffer_vk.h +++ b/host/vulkan/color_buffer_vk.h @@ -46,7 +46,7 @@ struct ColorBufferVkImageInfo { uint32_t height = 0; VkImage image = VK_NULL_HANDLE; VkImageView imageView = VK_NULL_HANDLE; - VkImageCreateInfo imageCreateInfo = {}; + VkImageCreateInfo imageCreateInfoShallow = {}; GfxstreamFormat imageFormat = GfxstreamFormat::UNKNOWN; VkImageLayout preBorrowLayout = VK_IMAGE_LAYOUT_UNDEFINED; uint32_t preBorrowQueueFamilyIndex = 0; diff --git a/host/vulkan/compositor_vk.cpp b/host/vulkan/compositor_vk.cpp index 01d82d025..d95a146c4 100644 --- a/host/vulkan/compositor_vk.cpp +++ b/host/vulkan/compositor_vk.cpp @@ -1165,9 +1165,10 @@ CompositorVk::RenderTarget* CompositorVk::getOrCreateRenderTargetInfo( } VkRenderPass renderPass = renderPassIt->second; - auto* renderTarget = new RenderTarget(m_vk, m_vkDevice, imageInfo.image, imageInfo.imageView, - imageInfo.imageCreateInfo.extent.width, - imageInfo.imageCreateInfo.extent.height, renderPass); + auto* renderTarget = + new RenderTarget(m_vk, m_vkDevice, imageInfo.image, imageInfo.imageView, + imageInfo.imageCreateInfoShallow.extent.width, + imageInfo.imageCreateInfoShallow.extent.height, renderPass); m_renderTargetCache.set(imageInfo.id, std::unique_ptr(renderTarget)); @@ -1221,7 +1222,7 @@ void CompositorVk::buildCompositionVk(const CompositionRequestVk& compositionReq sourceImageHeight = targetHeight; } else if (layer.source) { sourceImage = layer.source; - if (!canCompositeFrom(sourceImage->imageCreateInfo)) { + if (!canCompositeFrom(sourceImage->imageCreateInfoShallow)) { continue; } @@ -1535,8 +1536,8 @@ CompositorVk::CompositionFinishedWaitable CompositorVk::compose( }, .extent = { - .width = compositionVk.targetImage->imageCreateInfo.extent.width, - .height = compositionVk.targetImage->imageCreateInfo.extent.height, + .width = compositionVk.targetImage->imageCreateInfoShallow.extent.width, + .height = compositionVk.targetImage->imageCreateInfoShallow.extent.height, }, }, .clearValueCount = 1, @@ -1557,15 +1558,16 @@ CompositorVk::CompositionFinishedWaitable CompositorVk::compose( }, .extent = { - .width = compositionVk.targetImage->imageCreateInfo.extent.width, - .height = compositionVk.targetImage->imageCreateInfo.extent.height, + .width = compositionVk.targetImage->imageCreateInfoShallow.extent.width, + .height = compositionVk.targetImage->imageCreateInfoShallow.extent.height, }, }; const VkViewport viewport = { .x = 0.0f, .y = 0.0f, - .width = static_cast(compositionVk.targetImage->imageCreateInfo.extent.width), - .height = static_cast(compositionVk.targetImage->imageCreateInfo.extent.height), + .width = static_cast(compositionVk.targetImage->imageCreateInfoShallow.extent.width), + .height = + static_cast(compositionVk.targetImage->imageCreateInfoShallow.extent.height), .minDepth = 0.0f, .maxDepth = 1.0f, }; diff --git a/host/vulkan/compositor_vk_unittest.cpp b/host/vulkan/compositor_vk_unittest.cpp index f5d01ceee..6b004a0f6 100644 --- a/host/vulkan/compositor_vk_unittest.cpp +++ b/host/vulkan/compositor_vk_unittest.cpp @@ -292,7 +292,7 @@ class CompositorVkTest : public ::testing::Test { ret->width = image->m_width; ret->height = image->m_height; ret->image = image->m_vkImage; - ret->imageCreateInfo = image->m_vkImageCreateInfo; + ret->imageCreateInfoShallow = image->m_vkImageCreateInfo; ret->imageView = image->m_vkImageView; ret->imageFormat = SourceOrTargetImage::k_format; ret->preBorrowLayout = SourceOrTargetImage::k_vkImageLayout; diff --git a/host/vulkan/display_vk.cpp b/host/vulkan/display_vk.cpp index c964d525b..4c4375575 100644 --- a/host/vulkan/display_vk.cpp +++ b/host/vulkan/display_vk.cpp @@ -411,7 +411,7 @@ DisplayVk::PostResult DisplayVk::postImpl(const Post& postCmd) { if (layer.rotationDegrees == 0 && !layer.colorTransform.has_value() && hwc_rect_get_width(&layer.displayFrame) == 0 && !postCmd.colorTransform.has_value()) { const auto* sourceImageInfoVk = layer.info; - if (canPost(sourceImageInfoVk->imageCreateInfo)) { + if (canPost(sourceImageInfoVk->imageCreateInfoShallow)) { useBlit = true; } } @@ -586,10 +586,11 @@ DisplayVk::PostResult DisplayVk::postImpl(const Post& postCmd) { .mipLevel = 0, .baseArrayLayer = 0, .layerCount = 1}, - .srcOffsets = {{0, 0, 0}, - {static_cast(sourceImageInfoVk->imageCreateInfo.extent.width), - static_cast(sourceImageInfoVk->imageCreateInfo.extent.height), - 1}}, + .srcOffsets = + {{0, 0, 0}, + {static_cast(sourceImageInfoVk->imageCreateInfoShallow.extent.width), + static_cast(sourceImageInfoVk->imageCreateInfoShallow.extent.height), + 1}}, .dstSubresource = {.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .mipLevel = 0, .baseArrayLayer = 0, @@ -598,8 +599,8 @@ DisplayVk::PostResult DisplayVk::postImpl(const Post& postCmd) { {static_cast(swapchainImageExtent.width), static_cast(swapchainImageExtent.height), 1}}, }; - VkFormat displayBufferFormat = sourceImageInfoVk->imageCreateInfo.format; - VkImageTiling displayBufferTiling = sourceImageInfoVk->imageCreateInfo.tiling; + VkFormat displayBufferFormat = sourceImageInfoVk->imageCreateInfoShallow.format; + VkImageTiling displayBufferTiling = sourceImageInfoVk->imageCreateInfoShallow.tiling; VkFilter filter = VK_FILTER_NEAREST; VkFormatFeatureFlags displayBufferFormatFeatures = diff --git a/host/vulkan/display_vk_unittest.cpp b/host/vulkan/display_vk_unittest.cpp index 24797e7e3..1df7e84f4 100644 --- a/host/vulkan/display_vk_unittest.cpp +++ b/host/vulkan/display_vk_unittest.cpp @@ -91,7 +91,7 @@ class DisplayVkTest : public ::testing::Test { info->width = texture->m_vkImageCreateInfo.extent.width; info->height = texture->m_vkImageCreateInfo.extent.height; info->image = texture->m_vkImage; - info->imageCreateInfo = texture->m_vkImageCreateInfo; + info->imageCreateInfoShallow = texture->m_vkImageCreateInfo; info->preBorrowLayout = RenderTexture::k_vkImageLayout; info->preBorrowQueueFamilyIndex = m_compositorQueueFamilyIndex; info->postBorrowLayout = RenderTexture::k_vkImageLayout; diff --git a/host/vulkan/vk_common_operations.cpp b/host/vulkan/vk_common_operations.cpp index fc7ce841f..4b0cfa0f7 100644 --- a/host/vulkan/vk_common_operations.cpp +++ b/host/vulkan/vk_common_operations.cpp @@ -5140,7 +5140,7 @@ std::unique_ptr VkEmulation::prepareColorBufferForCompos compositorInfo->height = colorBufferInfo->imageCreateInfoShallow.extent.height; compositorInfo->image = colorBufferInfo->image; compositorInfo->imageView = colorBufferInfo->imageView; - compositorInfo->imageCreateInfo = colorBufferInfo->imageCreateInfoShallow; + compositorInfo->imageCreateInfoShallow = colorBufferInfo->imageCreateInfoShallow; compositorInfo->imageFormat = colorBufferInfo->format; compositorInfo->preBorrowLayout = colorBufferInfo->currentLayout; compositorInfo->preBorrowQueueFamilyIndex = colorBufferInfo->currentQueueFamilyIndex; @@ -5182,7 +5182,7 @@ std::unique_ptr VkEmulation::prepareColorBufferForDispla compositorInfo->height = colorBufferInfo->imageCreateInfoShallow.extent.height; compositorInfo->image = colorBufferInfo->image; compositorInfo->imageView = colorBufferInfo->imageView; - compositorInfo->imageCreateInfo = colorBufferInfo->imageCreateInfoShallow; + compositorInfo->imageCreateInfoShallow = colorBufferInfo->imageCreateInfoShallow; compositorInfo->imageFormat = colorBufferInfo->format; compositorInfo->preBorrowLayout = colorBufferInfo->currentLayout; compositorInfo->preBorrowQueueFamilyIndex = mQueueFamilyIndex; From 3c61690109db21ebf834d0a2b4eb68ed502bc857 Mon Sep 17 00:00:00 2001 From: Jason Macnak Date: Tue, 4 Aug 2026 12:19:51 -0700 Subject: [PATCH 27/33] Move lazy snapshot to host common Bug: b/537737772 Test: bazel test //host/... Low-Coverage-Reason: REFACTOR_ONLY Change-Id: Id024ca1b67ea1f93f459dce5c7f6f246aef54da6 --- host/Android.bp | 3 -- host/BUILD.bazel | 1 - host/CMakeLists.txt | 3 -- host/buffer.h | 2 +- host/color_buffer.h | 2 +- .../gfxstream/host/lazy_snapshot_object.h} | 0 host/gl/glestranslator/common/Android.bp | 2 -- host/gl/glestranslator/common/BUILD.bazel | 2 +- host/gl/glestranslator/common/CMakeLists.txt | 1 - .../common/include/common/saveable_texture.h | 2 +- host/gl/glestranslator/common/meson.build | 1 - host/gl/glestranslator/egl/meson.build | 9 +++--- host/gl/glestranslator/gles_cm/CMakeLists.txt | 1 - host/gl/glestranslator/gles_cm/meson.build | 5 ++-- host/gl/glestranslator/gles_v2/meson.build | 5 ++-- host/gl/meson.build | 1 - host/meson.build | 2 -- host/snapshot/Android.bp | 29 ------------------- host/snapshot/BUILD.bazel | 21 -------------- host/snapshot/CMakeLists.txt | 25 ---------------- host/snapshot/meson.build | 4 --- host/testlibs/support/Android.bp | 1 - host/vulkan/Android.bp | 1 - host/vulkan/CMakeLists.txt | 1 - host/vulkan/meson.build | 1 - 25 files changed, 12 insertions(+), 113 deletions(-) rename host/{snapshot/include/snapshot/LazySnapshotObj.h => common/include/gfxstream/host/lazy_snapshot_object.h} (100%) delete mode 100644 host/snapshot/Android.bp delete mode 100644 host/snapshot/BUILD.bazel delete mode 100644 host/snapshot/CMakeLists.txt delete mode 100644 host/snapshot/meson.build diff --git a/host/Android.bp b/host/Android.bp index e93ba02b9..2a4a3595d 100644 --- a/host/Android.bp +++ b/host/Android.bp @@ -68,7 +68,6 @@ gfxstream_backend_static_deps = [ "libgfxstream_host_openglesdispatch", "libgfxstream_host_rendercontrol_dec", "libgfxstream_host_renderdoc", - "libgfxstream_host_snapshot", "libgfxstream_host_tracing", "libgfxstream_host_vulkan_cereal", "libgfxstream_host_vulkan_emulatedtextures", @@ -116,7 +115,6 @@ cc_defaults { "libgfxstream_host_decoder_common", "libgfxstream_host_features", "libgfxstream_host_renderdoc", - "libgfxstream_host_snapshot", "libgfxstream_host_tracing", "libgfxstream_host_gles2_dec", "libgfxstream_host_glsnapshot", @@ -196,7 +194,6 @@ cc_test_host { "libgfxstream_common_image", "libgfxstream_common_logging", "libgfxstream_common_testenv", - "libgfxstream_host_snapshot", "libgfxstream_host_test_support", "libgfxstream_host_vulkan_server", "libgfxstream_host_address_space", diff --git a/host/BUILD.bazel b/host/BUILD.bazel index 6adcb4092..16cd20819 100644 --- a/host/BUILD.bazel +++ b/host/BUILD.bazel @@ -150,7 +150,6 @@ cc_library( "//host/native_window:gfxstream_host_native_window", "//host/renderControl_dec", "//host/renderdoc:gfxstream_host_renderdoc", - "//host/snapshot:gfxstream_host_snapshot", "//host/tracing:gfxstream_host_tracing", "//host/vulkan:gfxstream_vulkan_server", "//third_party/drm:gfxstream_drm_headers", diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index 47c9c9a47..6b61ae52d 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -47,7 +47,6 @@ add_subdirectory(common) add_subdirectory(features) add_subdirectory(iostream) add_subdirectory(library) -add_subdirectory(snapshot) add_subdirectory(tracing) add_subdirectory(decoder_common) add_subdirectory(compressed_textures) @@ -63,7 +62,6 @@ target_link_libraries( INTERFACE gfxstream_features.headers gfxstream_host_decoder_common - gfxstream_host_snapshot.headers gfxstream_host_renderdoc ) target_include_directories( @@ -127,7 +125,6 @@ target_link_libraries( gfxstream_host_iostream gfxstream_host_library gfxstream_host_renderdoc - gfxstream_host_snapshot.headers gfxstream_host_tracing gfxstream_opengl_headers gfxstream_openglesdispatch diff --git a/host/buffer.h b/host/buffer.h index 8dd9d9cb4..bcab55e08 100644 --- a/host/buffer.h +++ b/host/buffer.h @@ -18,8 +18,8 @@ #include "gfxstream/host/external_object_manager.h" #include "gfxstream/host/handle.h" +#include "gfxstream/host/lazy_snapshot_object.h" #include "render-utils/stream.h" -#include "snapshot/LazySnapshotObj.h" namespace gfxstream { namespace host { diff --git a/host/color_buffer.h b/host/color_buffer.h index 7698f22aa..f83062007 100644 --- a/host/color_buffer.h +++ b/host/color_buffer.h @@ -26,7 +26,7 @@ #include "gfxstream/host/handle.h" #include "render-utils/Renderer.h" #include "render-utils/stream.h" -#include "snapshot/LazySnapshotObj.h" +#include "gfxstream/host/lazy_snapshot_object.h" namespace gfxstream { namespace host { diff --git a/host/snapshot/include/snapshot/LazySnapshotObj.h b/host/common/include/gfxstream/host/lazy_snapshot_object.h similarity index 100% rename from host/snapshot/include/snapshot/LazySnapshotObj.h rename to host/common/include/gfxstream/host/lazy_snapshot_object.h diff --git a/host/gl/glestranslator/common/Android.bp b/host/gl/glestranslator/common/Android.bp index 3862d6380..dfec95508 100644 --- a/host/gl/glestranslator/common/Android.bp +++ b/host/gl/glestranslator/common/Android.bp @@ -40,11 +40,9 @@ cc_library_static { "libgfxstream_host_compressedtextures", "libgfxstream_host_library", "libgfxstream_common_logging", - "libgfxstream_host_snapshot", ], export_static_lib_headers: [ "libgfxstream_etc", - "libgfxstream_host_snapshot", ], srcs: [ "rgtc.cpp", diff --git a/host/gl/glestranslator/common/BUILD.bazel b/host/gl/glestranslator/common/BUILD.bazel index 29edabe53..f88e89f67 100644 --- a/host/gl/glestranslator/common/BUILD.bazel +++ b/host/gl/glestranslator/common/BUILD.bazel @@ -18,9 +18,9 @@ cc_library( "//common/etc:gfxstream_etc", "//common/logging:gfxstream_common_logging", "//host:gfxstream_backend_headers", + "//host/common:gfxstream_host_common", "//host/decoder_common:gfxstream_host_decoder_common", "//host/gl/OpenGLESDispatch:gfxstream_host_openglesdispatch_headers", - "//host/snapshot:gfxstream_host_snapshot", "//third_party/opengl:gfxstream_egl_headers", "//third_party/opengl:gfxstream_gles2_headers", "//third_party/opengl:gfxstream_gles3_headers", diff --git a/host/gl/glestranslator/common/CMakeLists.txt b/host/gl/glestranslator/common/CMakeLists.txt index 76e5bd889..d72eb787e 100644 --- a/host/gl/glestranslator/common/CMakeLists.txt +++ b/host/gl/glestranslator/common/CMakeLists.txt @@ -51,7 +51,6 @@ target_link_libraries( gfxstream_host_common gfxstream_host_compressed_textures gfxstream_host_library - gfxstream_host_snapshot.headers gfxstream_opengl_headers gfxstream_openglesdispatch PRIVATE diff --git a/host/gl/glestranslator/common/include/common/saveable_texture.h b/host/gl/glestranslator/common/include/common/saveable_texture.h index 03da73678..be1a23dfc 100644 --- a/host/gl/glestranslator/common/include/common/saveable_texture.h +++ b/host/gl/glestranslator/common/include/common/saveable_texture.h @@ -22,7 +22,7 @@ #include #include "render-utils/stream.h" -#include "snapshot/LazySnapshotObj.h" +#include "gfxstream/host/lazy_snapshot_object.h" #include "common/named_object.h" #include "common/texture_data.h" #include "common/translator_ifaces.h" diff --git a/host/gl/glestranslator/common/meson.build b/host/gl/glestranslator/common/meson.build index 0eb196992..c838d6e86 100644 --- a/host/gl/glestranslator/common/meson.build +++ b/host/gl/glestranslator/common/meson.build @@ -39,7 +39,6 @@ lib_gl_common = static_library( inc_host_decoder_common, inc_host_library, inc_common_logging, - inc_host_snapshot, inc_include, inc_stream_servers, ], diff --git a/host/gl/glestranslator/egl/meson.build b/host/gl/glestranslator/egl/meson.build index 683d36f2a..aa89d41b2 100644 --- a/host/gl/glestranslator/egl/meson.build +++ b/host/gl/glestranslator/egl/meson.build @@ -57,29 +57,28 @@ lib_egl_translator = static_library( objcpp_args: egl_cpp_args + gfxstream_host_args, dependencies: egl_deps, include_directories: [ - inc_host_decoder_common, inc_common_base, + inc_common_logging, inc_common_utils, inc_etc, inc_gfxstream_server, inc_gl_common, inc_gl_openglesdispatch, inc_host_common, + inc_host_decoder_common, inc_host_library, - inc_common_logging, - inc_host_snapshot, inc_include, inc_opengl_headers, inc_stream_servers, inc_x11_headers, ], link_with: [ - lib_host_decoder_common, lib_common_base, + lib_common_logging, lib_common_utils, lib_gl_common, lib_host_common, + lib_host_decoder_common, lib_host_library, - lib_common_logging, ], ) diff --git a/host/gl/glestranslator/gles_cm/CMakeLists.txt b/host/gl/glestranslator/gles_cm/CMakeLists.txt index af021062a..19e81a74b 100644 --- a/host/gl/glestranslator/gles_cm/CMakeLists.txt +++ b/host/gl/glestranslator/gles_cm/CMakeLists.txt @@ -36,7 +36,6 @@ target_link_libraries( gfxstream_common_logging gfxstream_host_common gfxstream_host_decoder_common - gfxstream_host_snapshot.headers gfxstream_opengl_headers ) target_include_directories( diff --git a/host/gl/glestranslator/gles_cm/meson.build b/host/gl/glestranslator/gles_cm/meson.build index b7e882ce9..55a993746 100644 --- a/host/gl/glestranslator/gles_cm/meson.build +++ b/host/gl/glestranslator/gles_cm/meson.build @@ -15,20 +15,19 @@ lib_glescm_translator = static_library( cpp_args: gfxstream_host_args, include_directories: [ inc_common_base, + inc_common_logging, inc_etc, inc_gfxstream_server, inc_gl_common, inc_gl_openglesdispatch, inc_glm, inc_host_common, - inc_common_logging, - inc_host_snapshot, inc_include, inc_opengl_headers, ], link_with: [ lib_common_base, - lib_host_common, lib_common_logging, + lib_host_common, ], ) diff --git a/host/gl/glestranslator/gles_v2/meson.build b/host/gl/glestranslator/gles_v2/meson.build index 454d18b86..6292e02b7 100644 --- a/host/gl/glestranslator/gles_v2/meson.build +++ b/host/gl/glestranslator/gles_v2/meson.build @@ -19,22 +19,21 @@ lib_glesv2_translator = static_library( cpp_args: gfxstream_host_args, include_directories: [ inc_common_base, + inc_common_logging, inc_etc, inc_gfxstream_server, inc_gl_common, inc_gl_openglesdispatch, inc_host_common, inc_host_decoder_common, - inc_common_logging, - inc_host_snapshot, inc_include, inc_opengl_headers, inc_stream_servers, ], link_with: [ lib_common_base, + lib_common_logging, lib_host_common, lib_host_decoder_common, - lib_common_logging, ], ) diff --git a/host/gl/meson.build b/host/gl/meson.build index 440d8365c..d3aad7c3b 100644 --- a/host/gl/meson.build +++ b/host/gl/meson.build @@ -57,7 +57,6 @@ lib_gl_server = static_library( inc_host_iostream, inc_host_library, inc_host_renderdoc, - inc_host_snapshot, inc_include, inc_opengl_headers, inc_renderdoc_external, diff --git a/host/meson.build b/host/meson.build index e2ca23f56..1e8875a3f 100644 --- a/host/meson.build +++ b/host/meson.build @@ -16,7 +16,6 @@ subdir('iostream') subdir('library') subdir('tracing') subdir('renderdoc') -subdir('snapshot') subdir('decoder_common') subdir('address_space') subdir('common') @@ -37,7 +36,6 @@ inc_gfxstream_backend = [ inc_host_library, inc_host_native_window, inc_host_renderdoc, - inc_host_snapshot, inc_host_tracing, inc_include, inc_opengl_headers, diff --git a/host/snapshot/Android.bp b/host/snapshot/Android.bp deleted file mode 100644 index c4f737627..000000000 --- a/host/snapshot/Android.bp +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2025 The Android Open Source Project -// -// 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 expresso or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package { - default_applicable_licenses: ["hardware_google_gfxstream_license"], -} - -cc_library_static { - name: "libgfxstream_host_snapshot", - defaults: ["gfxstream_host_cc_defaults"], - header_libs: [ - "libgfxstream_backend_headers", - ], - export_header_lib_headers: [ - "libgfxstream_backend_headers", - ], - export_include_dirs: ["include"], -} diff --git a/host/snapshot/BUILD.bazel b/host/snapshot/BUILD.bazel deleted file mode 100644 index 444502b35..000000000 --- a/host/snapshot/BUILD.bazel +++ /dev/null @@ -1,21 +0,0 @@ -load("@rules_cc//cc:defs.bzl", "cc_library") -load("//:build_variables.bzl", "GFXSTREAM_HOST_COPTS", "GFXSTREAM_HOST_DEFINES", "GFXSTREAM_HOST_LINKOPTS") - -package( - default_applicable_licenses = ["//:gfxstream_license"], - default_visibility = ["//:gfxstream"], -) - -cc_library( - name = "gfxstream_host_snapshot", - hdrs = [ - "include/snapshot/LazySnapshotObj.h", - ], - copts = GFXSTREAM_HOST_COPTS, - defines = GFXSTREAM_HOST_DEFINES, - linkopts = GFXSTREAM_HOST_LINKOPTS, - strip_include_prefix = "include", - deps = [ - "//host:gfxstream_backend_headers", - ], -) diff --git a/host/snapshot/CMakeLists.txt b/host/snapshot/CMakeLists.txt deleted file mode 100644 index b963fb2c7..000000000 --- a/host/snapshot/CMakeLists.txt +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2025 The Android Open Source Project -# -# 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. - -add_library( - gfxstream_host_snapshot.headers - INTERFACE) -target_include_directories( - gfxstream_host_snapshot.headers - INTERFACE - include) -target_link_libraries( - gfxstream_host_snapshot.headers - INTERFACE - gfxstream_backend_headers) diff --git a/host/snapshot/meson.build b/host/snapshot/meson.build deleted file mode 100644 index b320ced48..000000000 --- a/host/snapshot/meson.build +++ /dev/null @@ -1,4 +0,0 @@ -# Copyright 2025 Android Open Source Project -# SPDX-License-Identifier: Apache-2.0 - -inc_host_snapshot = include_directories('include') diff --git a/host/testlibs/support/Android.bp b/host/testlibs/support/Android.bp index 2a3b54922..f7cf45d3a 100644 --- a/host/testlibs/support/Android.bp +++ b/host/testlibs/support/Android.bp @@ -46,7 +46,6 @@ cc_test_library { "libgfxstream_common_logging", "libgfxstream_host_decoder_common", "libgfxstream_host_iostream", - "libgfxstream_host_snapshot", "libgfxstream_oswindow_test_support", "libgmock", ], diff --git a/host/vulkan/Android.bp b/host/vulkan/Android.bp index 592445041..7cf425717 100644 --- a/host/vulkan/Android.bp +++ b/host/vulkan/Android.bp @@ -47,7 +47,6 @@ cc_library_static { "libgfxstream_host_library", "libgfxstream_host_openglesdispatch", "libgfxstream_host_renderdoc", - "libgfxstream_host_snapshot", "libgfxstream_host_vulkan_cereal", "libgfxstream_host_vulkan_emulatedtextures", "libgfxstream_host_native_window", diff --git a/host/vulkan/CMakeLists.txt b/host/vulkan/CMakeLists.txt index 884c8ef1c..bb73f00c7 100644 --- a/host/vulkan/CMakeLists.txt +++ b/host/vulkan/CMakeLists.txt @@ -66,7 +66,6 @@ target_link_libraries(gfxstream-vulkan-server PUBLIC gfxstream_host_iostream gfxstream_host_library gfxstream_host_renderdoc - gfxstream_host_snapshot.headers gfxstream_host_tracing gfxstream_openglesdispatch.headers gfxstream_vulkan_headers diff --git a/host/vulkan/meson.build b/host/vulkan/meson.build index 7461480c5..2ea154a65 100644 --- a/host/vulkan/meson.build +++ b/host/vulkan/meson.build @@ -87,7 +87,6 @@ lib_vulkan_server = static_library( inc_host_library, inc_host_native_window, inc_host_renderdoc, - inc_host_snapshot, inc_host_tracing, inc_include, inc_opengl_headers, From 74b7ecc6e2da2600fe82e4279ac9a989b0c70a6b Mon Sep 17 00:00:00 2001 From: Jason Macnak Date: Mon, 3 Aug 2026 10:21:56 -0700 Subject: [PATCH 28/33] Use std::string_view in GlobalState Bug: b/537737772 Test: bazel test //host/... Low-Coverage-Reason: REFACTOR_ONLY Change-Id: I6314cb82ec48553f507cca60df57c9c4a6ee546b --- .../include/gfxstream/host/global_state.h | 6 ++--- host/frame_buffer.cpp | 25 ++++++++++--------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/host/common/include/gfxstream/host/global_state.h b/host/common/include/gfxstream/host/global_state.h index 0bdc1c0c7..81f87bd2d 100644 --- a/host/common/include/gfxstream/host/global_state.h +++ b/host/common/include/gfxstream/host/global_state.h @@ -15,7 +15,7 @@ #pragma once #include -#include +#include #include "gfxstream/CancelableFuture.h" #include "gfxstream/host/color_buffer_interface.h" @@ -62,9 +62,9 @@ class GlobalState { size_t bytesSize) = 0; virtual CancelableFuture scheduleAsyncWork(std::function work, - std::string description) = 0; + std::string_view description) = 0; - virtual void registerVulkanInstance(uint64_t id, const char* appName) const {} + virtual void registerVulkanInstance(uint64_t id, std::string_view appName) const {} virtual void unregisterVulkanInstance(uint64_t id) const {} }; diff --git a/host/frame_buffer.cpp b/host/frame_buffer.cpp index 3719dc8e3..59f6b8de4 100644 --- a/host/frame_buffer.cpp +++ b/host/frame_buffer.cpp @@ -18,14 +18,14 @@ #include #include -#include - -#include - - #if defined(__linux__) #include #endif +#include + +#include +#include +#include #if GFXSTREAM_ENABLE_HOST_GLES #include "host/gl/gles_version_detector.h" @@ -498,7 +498,7 @@ class FrameBuffer::Impl : public gfxstream::base::EventNotificationSupport work, - std::string description) override; + std::string_view description) override; const ProcessResources* getProcessResources(uint64_t puid); @@ -3626,7 +3626,7 @@ void FrameBuffer::Impl::flushColorBufferFromBytes(uint32_t colorBufferHandle, co } CancelableFuture FrameBuffer::Impl::scheduleAsyncWork(std::function work, - std::string description) { + std::string_view description) { auto promise = std::make_shared(); auto future = promise->GetFuture(); SyncThread::get()->triggerGeneral( @@ -3634,7 +3634,7 @@ CancelableFuture FrameBuffer::Impl::scheduleAsyncWork(std::function work work(); promise->MarkComplete(); }, - description); + std::string(description)); return future; } @@ -3954,7 +3954,7 @@ void FrameBuffer::Impl::setDisplayLayout(int screenWidth, int screenHeight, } #ifdef CONFIG_AEMU -void FrameBuffer::Impl::registerVulkanInstance(uint64_t id, const char* appName) const { +void FrameBuffer::Impl::registerVulkanInstance(uint64_t id, std::string_view appName) const { auto* tInfo = RenderThreadInfo::get(); std::string process_name; if (tInfo && tInfo->m_processName.has_value()) { @@ -3975,8 +3975,9 @@ void FrameBuffer::Impl::unregisterVulkanInstance(uint64_t id) const { get_gfxstream_vm_operations().unregister_vulkan_instance(id); } #else -void FrameBuffer::Impl::registerVulkanInstance(uint64_t id, const char* appName) const {} -void FrameBuffer::Impl::unregisterVulkanInstance(uint64_t id) const {} +void FrameBuffer::Impl::registerVulkanInstance(uint64_t /*id*/, + std::string_view /*appName*/) const {} +void FrameBuffer::Impl::unregisterVulkanInstance(uint64_t /*id*/) const {} #endif void FrameBuffer::Impl::createTrivialContext(HandleType shared, HandleType* contextOut, From c39616b8e12842f4d773a2ff4453ca83b50a6e37 Mon Sep 17 00:00:00 2001 From: Jason Macnak Date: Tue, 4 Aug 2026 12:25:51 -0700 Subject: [PATCH 29/33] Add meson dep to host/common Bug: b/537737772 Test: bazel test //host/... Low-Coverage-Reason: REFACTOR_ONLY Change-Id: Ic9c15e2135fee89d49b983adfdf816a73de40179 --- host/common/meson.build | 2 ++ 1 file changed, 2 insertions(+) diff --git a/host/common/meson.build b/host/common/meson.build index 597d649a3..d83d432c6 100644 --- a/host/common/meson.build +++ b/host/common/meson.build @@ -29,6 +29,7 @@ lib_host_common = static_library( include_directories: [ inc_common_base, inc_common_logging, + inc_common_utils, inc_gfxstream_server, inc_host_address_space, inc_host_common, @@ -36,6 +37,7 @@ lib_host_common = static_library( link_with: [ lib_common_base, lib_common_logging, + lib_common_utils, lib_host_address_space, ], ) \ No newline at end of file From b0fe335ca9c571a2dea349b47fad0e5f41c874ca Mon Sep 17 00:00:00 2001 From: Jason Macnak Date: Wed, 5 Aug 2026 13:00:50 -0700 Subject: [PATCH 30/33] Fixup for native window meson build --- host/native_window/CMakeLists.txt | 1 - host/native_window/meson.build | 28 +++++++++++++++++++--------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/host/native_window/CMakeLists.txt b/host/native_window/CMakeLists.txt index 3ddaa5e11..c31cab603 100644 --- a/host/native_window/CMakeLists.txt +++ b/host/native_window/CMakeLists.txt @@ -18,7 +18,6 @@ endif() add_library( gfxstream_host_native_window STATIC - native_sub_window_stub.cpp ${gfxstream_host_native_window_platform_sources}) target_include_directories( diff --git a/host/native_window/meson.build b/host/native_window/meson.build index c5da6236a..fe6a556c7 100644 --- a/host/native_window/meson.build +++ b/host/native_window/meson.build @@ -3,14 +3,28 @@ inc_host_native_window = include_directories('include') -files_lib_host_native_window = files('native_sub_window_stub.cpp') +files_lib_host_native_window = files() -if host_machine.system() == 'darwin' +includes_lib_host_native_window = [ + inc_common_base, + inc_host_common, + inc_host_decoder_common, + inc_host_include, + inc_host_native_window, + inc_opengl_headers, +] + +if not use_gles + files_lib_host_native_window += files('native_sub_window_stub.cpp') +elif host_machine.system() == 'darwin' files_lib_host_native_window += files('native_sub_window_cocoa.mm') + includes_lib_host_native_window += [inc_opengl_headers] elif host_machine.system() == 'windows' files_lib_host_native_window += files('native_sub_window_win32.cpp') + includes_lib_host_native_window += [inc_opengl_headers] elif host_machine.system() == 'linux' and use_gles files_lib_host_native_window += files('native_sub_window_x11.cpp') + includes_lib_host_native_window += [inc_opengl_headers] elif host_machine.system() == 'qnx' files_lib_host_native_window += files( 'native_sub_window_qnx.cpp', @@ -20,11 +34,7 @@ endif lib_host_native_window = static_library( 'host_native_window', files_lib_host_native_window, - include_directories: [ - inc_common_base, - inc_host_common, - inc_host_decoder_common, - inc_host_include, - inc_host_native_window, - ], + include_directories: includes_lib_host_native_window, + cpp_args: gfxstream_host_args, + objcpp_args: gfxstream_host_args, ) From b41a1ff2cdb8be4cc0cbc052d09e8bfd39fbcd46 Mon Sep 17 00:00:00 2001 From: Jason Macnak Date: Wed, 5 Aug 2026 13:06:00 -0700 Subject: [PATCH 31/33] Fixup for macos build --- host/gl/emulation_gl.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/host/gl/emulation_gl.cpp b/host/gl/emulation_gl.cpp index 65f8a560d..d6c04efe2 100644 --- a/host/gl/emulation_gl.cpp +++ b/host/gl/emulation_gl.cpp @@ -25,6 +25,7 @@ #include "OpenGLESDispatch/OpenGLDispatchLoader.h" #include "common/gles_context.h" #include "display_surface_gl.h" +#include "glestranslator/egl/egl_global_info.h" #include "gfxstream/ThreadAnnotations.h" #include "gfxstream/common/logging.h" #include "gfxstream/host/color_buffer_interface.h" From 9de0d342ab37768b1ada0631162dcc656dec7300 Mon Sep 17 00:00:00 2001 From: Jason Macnak Date: Wed, 5 Aug 2026 13:34:15 -0700 Subject: [PATCH 32/33] Make warn-backrefs linux only --- build_variables.bzl | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/build_variables.bzl b/build_variables.bzl index 8c6ecdcc6..b567c66e8 100644 --- a/build_variables.bzl +++ b/build_variables.bzl @@ -83,8 +83,11 @@ GFXSTREAM_HOST_DEFINES = GFXSTREAM_HOST_VK_DEFINES + [ "//conditions:default": [], }) -GFXSTREAM_HOST_LINKOPTS = [ - "-Wl,--warn-backrefs", - "-Wl,--warn-backrefs-exclude=*llvm*", - "-Wl,--fatal-warnings", -] +GFXSTREAM_HOST_LINKOPTS = select({ + "@platforms//os:linux": [ + "-Wl,--warn-backrefs", + "-Wl,--warn-backrefs-exclude=*llvm*", + "-Wl,--fatal-warnings", + ], + "//conditions:default": [], +}) From 4865d73d5a8f68d17ab5d4512f20be057ae7ca7f Mon Sep 17 00:00:00 2001 From: Jason Macnak Date: Wed, 5 Aug 2026 15:11:55 -0700 Subject: [PATCH 33/33] Drop old test debugging statement --- tests/end2end/gfxstream_end2end_gralloc_tests.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/end2end/gfxstream_end2end_gralloc_tests.cpp b/tests/end2end/gfxstream_end2end_gralloc_tests.cpp index e120536b0..c4d70062f 100644 --- a/tests/end2end/gfxstream_end2end_gralloc_tests.cpp +++ b/tests/end2end/gfxstream_end2end_gralloc_tests.cpp @@ -35,8 +35,6 @@ TEST_P(GfxstreamEnd2EndGrallocTests, Allocate_YV12) { } TEST_P(GfxstreamEnd2EndGrallocTests, Allocate_YCbCr888420) { - ASSERT_THAT(false, Eq(true)); - auto ahb = GFXSTREAM_ASSERT(ScopedAHardwareBuffer::Allocate( *mGralloc, 32, 32, GFXSTREAM_AHB_FORMAT_Y8Cb8Cr8_420)); }