diff options
30 files changed, 537 insertions, 168 deletions
diff --git a/include/ftl/ignore.h b/include/ftl/ignore.h new file mode 100644 index 0000000000..1468fa2498 --- /dev/null +++ b/include/ftl/ignore.h @@ -0,0 +1,42 @@ +/* + * 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. + */ + +#pragma once + +namespace android::ftl { + +// An alternative to `std::ignore` that makes it easy to ignore multiple values. +// +// Examples: +// +// void ftl_ignore_multiple(int arg1, const char* arg2, std::string arg3) { +// // When invoked, all the arguments are ignored. +// ftl::ignore(arg1, arg2, arg3); +// } +// +// void ftl_ignore_single(int arg) { +// // It can be used like std::ignore to ignore a single value +// ftl::ignore = arg; +// } +// +inline constexpr struct { + // NOLINTNEXTLINE(misc-unconventional-assign-operator, readability-named-parameter) + constexpr auto operator=(auto&&) const -> decltype(*this) { return *this; } + // NOLINTNEXTLINE(readability-named-parameter) + constexpr void operator()(auto&&...) const {} +} ignore; + +} // namespace android::ftl
\ No newline at end of file diff --git a/libs/binder/aidl/android/content/pm/OWNERS b/libs/binder/aidl/android/content/pm/OWNERS index 31005184bf..2617a16f69 100644 --- a/libs/binder/aidl/android/content/pm/OWNERS +++ b/libs/binder/aidl/android/content/pm/OWNERS @@ -1,5 +1,4 @@ +michaelwr@google.com narayan@google.com patb@google.com -svetoslavganov@google.com -toddke@google.com -patb@google.com
\ No newline at end of file +schfan@google.com diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp index 08ce855c2b..5244442ff3 100644 --- a/libs/ftl/Android.bp +++ b/libs/ftl/Android.bp @@ -26,6 +26,7 @@ cc_test { "function_test.cpp", "future_test.cpp", "hash_test.cpp", + "ignore_test.cpp", "match_test.cpp", "mixins_test.cpp", "non_null_test.cpp", diff --git a/libs/ftl/ignore_test.cpp b/libs/ftl/ignore_test.cpp new file mode 100644 index 0000000000..5d5c67b8b1 --- /dev/null +++ b/libs/ftl/ignore_test.cpp @@ -0,0 +1,47 @@ +/* + * 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. + */ + +#include <string> + +#include <ftl/ignore.h> +#include <gtest/gtest.h> + +namespace android::test { +namespace { + +// Keep in sync with the example usage in the header file. + +void ftl_ignore_multiple(int arg1, const char* arg2, std::string arg3) { + // When invoked, all the arguments are ignored. + ftl::ignore(arg1, arg2, arg3); +} + +void ftl_ignore_single(int arg) { + // It can be used like std::ignore to ignore a single value + ftl::ignore = arg; +} + +} // namespace + +TEST(Ignore, Example) { + // The real example test is that there are no compiler warnings for unused arguments above. + + // Use the example functions to avoid a compiler warning about unused functions. + ftl_ignore_multiple(0, "a", "b"); + ftl_ignore_single(0); +} + +} // namespace android::test diff --git a/libs/graphicsenv/FeatureOverrides.cpp b/libs/graphicsenv/FeatureOverrides.cpp index 51afe285fb..9e7a4cf4a1 100644 --- a/libs/graphicsenv/FeatureOverrides.cpp +++ b/libs/graphicsenv/FeatureOverrides.cpp @@ -35,6 +35,18 @@ status_t FeatureConfig::writeToParcel(Parcel* parcel) const { if (status != OK) { return status; } + // Number of GPU vendor IDs. + status = parcel->writeVectorSize(mGpuVendorIDs); + if (status != OK) { + return status; + } + // GPU vendor IDs. + for (const auto& vendorID : mGpuVendorIDs) { + status = parcel->writeUint32(vendorID); + if (status != OK) { + return status; + } + } return OK; } @@ -50,6 +62,21 @@ status_t FeatureConfig::readFromParcel(const Parcel* parcel) { if (status != OK) { return status; } + // Number of GPU vendor IDs. + int numGpuVendorIDs; + status = parcel->readInt32(&numGpuVendorIDs); + if (status != OK) { + return status; + } + // GPU vendor IDs. + for (int i = 0; i < numGpuVendorIDs; i++) { + uint32_t gpuVendorIdUint; + status = parcel->readUint32(&gpuVendorIdUint); + if (status != OK) { + return status; + } + mGpuVendorIDs.emplace_back(gpuVendorIdUint); + } return OK; } @@ -58,6 +85,10 @@ std::string FeatureConfig::toString() const { std::string result; StringAppendF(&result, "Feature: %s\n", mFeatureName.c_str()); StringAppendF(&result, " Status: %s\n", mEnabled ? "enabled" : "disabled"); + for (const auto& vendorID : mGpuVendorIDs) { + // vkjson outputs decimal, so print both formats. + StringAppendF(&result, " GPU Vendor ID: 0x%04X (%d)\n", vendorID, vendorID); + } return result; } @@ -121,7 +152,12 @@ status_t FeatureOverrides::readFromParcel(const Parcel* parcel) { } // Number of package feature overrides. - int numPkgOverrides = parcel->readInt32(); + int numPkgOverrides; + status = parcel->readInt32(&numPkgOverrides); + if (status != OK) { + return status; + } + // Package feature overrides. for (int i = 0; i < numPkgOverrides; i++) { // Package name. std::string name; @@ -131,7 +167,11 @@ status_t FeatureOverrides::readFromParcel(const Parcel* parcel) { } std::vector<FeatureConfig> cfgs; // Number of package feature configs. - int numCfgs = parcel->readInt32(); + int numCfgs; + status = parcel->readInt32(&numCfgs); + if (status != OK) { + return status; + } // Package feature configs. for (int j = 0; j < numCfgs; j++) { FeatureConfig cfg; diff --git a/libs/graphicsenv/include/graphicsenv/FeatureOverrides.h b/libs/graphicsenv/include/graphicsenv/FeatureOverrides.h index 450eed2151..5dc613b901 100644 --- a/libs/graphicsenv/include/graphicsenv/FeatureOverrides.h +++ b/libs/graphicsenv/include/graphicsenv/FeatureOverrides.h @@ -35,6 +35,7 @@ public: std::string mFeatureName; bool mEnabled; + std::vector<uint32_t> mGpuVendorIDs; }; /* diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 310f781876..340b84cfcf 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -197,15 +197,15 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, bool updateDestinati mUpdateDestinationFrame(updateDestinationFrame) { createBufferQueue(&mProducer, &mConsumer); #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) - mBufferItemConsumer = new BLASTBufferItemConsumer(mProducer, mConsumer, - GraphicBuffer::USAGE_HW_COMPOSER | - GraphicBuffer::USAGE_HW_TEXTURE, - 1, false, this); + mBufferItemConsumer = sp<BLASTBufferItemConsumer>::make(mProducer, mConsumer, + GraphicBuffer::USAGE_HW_COMPOSER | + GraphicBuffer::USAGE_HW_TEXTURE, + 1, false, this); #else - mBufferItemConsumer = new BLASTBufferItemConsumer(mConsumer, - GraphicBuffer::USAGE_HW_COMPOSER | - GraphicBuffer::USAGE_HW_TEXTURE, - 1, false, this); + mBufferItemConsumer = sp<BLASTBufferItemConsumer>::make(mConsumer, + GraphicBuffer::USAGE_HW_COMPOSER | + GraphicBuffer::USAGE_HW_TEXTURE, + 1, false, this); #endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) // since the adapter is in the client process, set dequeue timeout // explicitly so that dequeueBuffer will block @@ -1120,10 +1120,10 @@ ANDROID_SINGLETON_STATIC_INSTANCE(AsyncWorker); class AsyncProducerListener : public BnProducerListener { private: const sp<IProducerListener> mListener; - -public: AsyncProducerListener(const sp<IProducerListener>& listener) : mListener(listener) {} + friend class sp<AsyncProducerListener>; +public: void onBufferReleased() override { AsyncWorker::getInstance().post([listener = mListener]() { listener->onBufferReleased(); }); } @@ -1177,7 +1177,7 @@ public: return BufferQueueProducer::connect(listener, api, producerControlledByApp, output); } - return BufferQueueProducer::connect(new AsyncProducerListener(listener), api, + return BufferQueueProducer::connect(sp<AsyncProducerListener>::make(listener), api, producerControlledByApp, output); } diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp index 8566419435..1585aae45c 100644 --- a/libs/gui/BufferItemConsumer.cpp +++ b/libs/gui/BufferItemConsumer.cpp @@ -24,6 +24,7 @@ #include <com_android_graphics_libgui_flags.h> #include <gui/BufferItem.h> #include <gui/BufferItemConsumer.h> +#include <gui/Surface.h> #include <ui/BufferQueueDefs.h> #include <ui/GraphicBuffer.h> @@ -35,6 +36,30 @@ namespace android { +std::tuple<sp<BufferItemConsumer>, sp<Surface>> BufferItemConsumer::create( + uint64_t consumerUsage, int bufferCount, bool controlledByApp, + bool isConsumerSurfaceFlinger) { +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + sp<BufferItemConsumer> bufferItemConsumer = + sp<BufferItemConsumer>::make(consumerUsage, bufferCount, controlledByApp, + isConsumerSurfaceFlinger); + return {bufferItemConsumer, bufferItemConsumer->getSurface()}; +#else + sp<IGraphicBufferProducer> igbp; + sp<IGraphicBufferConsumer> igbc; + BufferQueue::createBufferQueue(&igbp, &igbc, isConsumerSurfaceFlinger); + sp<BufferItemConsumer> bufferItemConsumer = + sp<BufferItemConsumer>::make(igbc, consumerUsage, bufferCount, controlledByApp); + return {bufferItemConsumer, sp<Surface>::make(igbp, controlledByApp)}; +#endif +} + +sp<BufferItemConsumer> BufferItemConsumer::create(const sp<IGraphicBufferConsumer>& consumer, + uint64_t consumerUsage, int bufferCount, + bool controlledByApp) { + return sp<BufferItemConsumer>::make(consumer, consumerUsage, bufferCount, controlledByApp); +} + #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) BufferItemConsumer::BufferItemConsumer(uint64_t consumerUsage, int bufferCount, bool controlledByApp, bool isConsumerSurfaceFlinger) diff --git a/libs/gui/Choreographer.cpp b/libs/gui/Choreographer.cpp index fb3e0f1d36..b9e6c06425 100644 --- a/libs/gui/Choreographer.cpp +++ b/libs/gui/Choreographer.cpp @@ -100,7 +100,7 @@ sp<Choreographer> Choreographer::getForThread() { return nullptr; } } - return gChoreographer.get(); + return gChoreographer; } Choreographer::Choreographer(const sp<Looper>& looper, const sp<IBinder>& layerHandle) diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp index 67de742161..0266a3f2e0 100644 --- a/libs/gui/ConsumerBase.cpp +++ b/libs/gui/ConsumerBase.cpp @@ -480,7 +480,6 @@ status_t ConsumerBase::setMaxAcquiredBufferCount(int maxAcquiredBuffers) { return mConsumer->setMaxAcquiredBufferCount(maxAcquiredBuffers); } -#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) status_t ConsumerBase::setConsumerIsProtected(bool isProtected) { Mutex::Autolock lock(mMutex); if (mAbandoned) { @@ -489,7 +488,6 @@ status_t ConsumerBase::setConsumerIsProtected(bool isProtected) { } return mConsumer->setConsumerIsProtected(isProtected); } -#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) sp<NativeHandle> ConsumerBase::getSidebandStream() const { Mutex::Autolock _l(mMutex); diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index cdc2150a26..db1b9fb8eb 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -46,21 +46,6 @@ class BufferItemConsumer; class BLASTBufferItemConsumer : public BufferItemConsumer { public: -#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) - BLASTBufferItemConsumer(const sp<IGraphicBufferProducer>& producer, - const sp<IGraphicBufferConsumer>& consumer, uint64_t consumerUsage, - int bufferCount, bool controlledByApp, wp<BLASTBufferQueue> bbq) - : BufferItemConsumer(producer, consumer, consumerUsage, bufferCount, controlledByApp), -#else - BLASTBufferItemConsumer(const sp<IGraphicBufferConsumer>& consumer, uint64_t consumerUsage, - int bufferCount, bool controlledByApp, wp<BLASTBufferQueue> bbq) - : BufferItemConsumer(consumer, consumerUsage, bufferCount, controlledByApp), -#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) - mBLASTBufferQueue(std::move(bbq)), - mCurrentlyConnected(false), - mPreviouslyConnected(false) { - } - void onDisconnect() override EXCLUDES(mMutex); void addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps, FrameEventHistoryDelta* outDelta) override EXCLUDES(mMutex); @@ -81,6 +66,23 @@ protected: #endif private: +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + BLASTBufferItemConsumer(const sp<IGraphicBufferProducer>& producer, + const sp<IGraphicBufferConsumer>& consumer, uint64_t consumerUsage, + int bufferCount, bool controlledByApp, wp<BLASTBufferQueue> bbq) + : BufferItemConsumer(producer, consumer, consumerUsage, bufferCount, controlledByApp), +#else + BLASTBufferItemConsumer(const sp<IGraphicBufferConsumer>& consumer, uint64_t consumerUsage, + int bufferCount, bool controlledByApp, wp<BLASTBufferQueue> bbq) + : BufferItemConsumer(consumer, consumerUsage, bufferCount, controlledByApp), +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + mBLASTBufferQueue(std::move(bbq)), + mCurrentlyConnected(false), + mPreviouslyConnected(false) { + } + + friend class sp<BLASTBufferItemConsumer>; + const wp<BLASTBufferQueue> mBLASTBufferQueue; uint64_t mCurrentFrameNumber GUARDED_BY(mMutex) = 0; @@ -94,8 +96,6 @@ private: class BLASTBufferQueue : public ConsumerBase::FrameAvailableListener { public: - BLASTBufferQueue(const std::string& name, bool updateDestinationFrame = true); - sp<IGraphicBufferProducer> getIGraphicBufferProducer() const { return mProducer; } @@ -158,8 +158,13 @@ public: void onFirstRef() override; private: + // Not public to ensure construction via sp<>::make(). + BLASTBufferQueue(const std::string& name, bool updateDestinationFrame = true); + + friend class sp<BLASTBufferQueue>; friend class BLASTBufferQueueHelper; friend class BBQBufferQueueProducer; + friend class TestBLASTBufferQueue; #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) friend class BBQBufferQueueCore; #endif diff --git a/libs/gui/include/gui/BufferItemConsumer.h b/libs/gui/include/gui/BufferItemConsumer.h index 6810edaf7c..0bfa7b222e 100644 --- a/libs/gui/include/gui/BufferItemConsumer.h +++ b/libs/gui/include/gui/BufferItemConsumer.h @@ -47,6 +47,16 @@ class BufferItemConsumer: public ConsumerBase enum { INVALID_BUFFER_SLOT = BufferQueue::INVALID_BUFFER_SLOT }; enum { NO_BUFFER_AVAILABLE = BufferQueue::NO_BUFFER_AVAILABLE }; + static std::tuple<sp<BufferItemConsumer>, sp<Surface>> create( + uint64_t consumerUsage, int bufferCount = DEFAULT_MAX_BUFFERS, + bool controlledByApp = false, bool isConsumerSurfaceFlinger = false); + + static sp<BufferItemConsumer> create(const sp<IGraphicBufferConsumer>& consumer, + uint64_t consumerUsage, + int bufferCount = DEFAULT_MAX_BUFFERS, + bool controlledByApp = false) + __attribute((deprecated("Prefer ctors that create their own surface and consumer."))); + // Create a new buffer item consumer. The consumerUsage parameter determines // the consumer usage flags passed to the graphics allocator. The // bufferCount parameter specifies how many buffers can be locked for user diff --git a/libs/gui/include/gui/ConsumerBase.h b/libs/gui/include/gui/ConsumerBase.h index 2e347c94f5..477d98df10 100644 --- a/libs/gui/include/gui/ConsumerBase.h +++ b/libs/gui/include/gui/ConsumerBase.h @@ -123,9 +123,7 @@ public: // See IGraphicBufferConsumer::setMaxAcquiredBufferCount status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers); -#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) status_t setConsumerIsProtected(bool isProtected); -#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) // See IGraphicBufferConsumer::getSidebandStream sp<NativeHandle> getSidebandStream() const; diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index e6ee89f9b2..b861c6d4b7 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -114,8 +114,8 @@ private: class BLASTBufferQueueHelper { public: BLASTBufferQueueHelper(const sp<SurfaceControl>& sc, int width, int height) { - mBlastBufferQueueAdapter = new TestBLASTBufferQueue("TestBLASTBufferQueue", sc, width, - height, PIXEL_FORMAT_RGBA_8888); + mBlastBufferQueueAdapter = sp<TestBLASTBufferQueue>::make("TestBLASTBufferQueue", sc, width, + height, PIXEL_FORMAT_RGBA_8888); } void update(const sp<SurfaceControl>& sc, int width, int height) { diff --git a/libs/gui/tests/BufferItemConsumer_test.cpp b/libs/gui/tests/BufferItemConsumer_test.cpp index 6453885804..b980f882ff 100644 --- a/libs/gui/tests/BufferItemConsumer_test.cpp +++ b/libs/gui/tests/BufferItemConsumer_test.cpp @@ -62,14 +62,15 @@ class BufferItemConsumerTest : public ::testing::Test { void SetUp() override { mBuffers.resize(BufferQueueDefs::NUM_BUFFER_SLOTS); - mBIC = new BufferItemConsumer(kUsage, kMaxLockedBuffers, true); + sp<Surface> surface; + std::tie(mBIC, surface) = BufferItemConsumer::create(kUsage, kMaxLockedBuffers, true); String8 name("BufferItemConsumer_Under_Test"); mBIC->setName(name); mBFL = new BufferFreedListener(this); mBIC->setBufferFreedListener(mBFL); sp<IProducerListener> producerListener = new TrackingProducerListener(this); - mProducer = mBIC->getSurface()->getIGraphicBufferProducer(); + mProducer = surface->getIGraphicBufferProducer(); IGraphicBufferProducer::QueueBufferOutput bufferOutput; ASSERT_EQ(NO_ERROR, mProducer->connect(producerListener, NATIVE_WINDOW_API_CPU, diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 98d13290a0..9ef3c84ae7 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -294,9 +294,7 @@ TEST_F(SurfaceTest, LayerCountIsOne) { TEST_F(SurfaceTest, QueryConsumerUsage) { const int TEST_USAGE_FLAGS = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER; - sp<BufferItemConsumer> c = new BufferItemConsumer(TEST_USAGE_FLAGS); - - sp<Surface> s = c->getSurface(); + auto [c, s] = BufferItemConsumer::create(TEST_USAGE_FLAGS); sp<ANativeWindow> anw(s); int flags = -1; @@ -2377,8 +2375,7 @@ TEST_F(SurfaceTest, QueueAcquireReleaseDequeue_CalledInStack_DoesNotDeadlock) { sp<IGraphicBufferConsumer> bqConsumer; BufferQueue::createBufferQueue(&bqProducer, &bqConsumer); - sp<BufferItemConsumer> consumer = sp<BufferItemConsumer>::make(bqConsumer, 3); - sp<Surface> surface = sp<Surface>::make(bqProducer); + auto [consumer, surface] = BufferItemConsumer::create(3); sp<ImmediateReleaseConsumerListener> consumerListener = sp<ImmediateReleaseConsumerListener>::make(consumer); consumer->setFrameAvailableListener(consumerListener); diff --git a/libs/math/OWNERS b/libs/math/OWNERS index 82ae422893..08f0c5f0dc 100644 --- a/libs/math/OWNERS +++ b/libs/math/OWNERS @@ -1,5 +1,4 @@ mathias@google.com -randolphs@google.com romainguy@google.com sumir@google.com jreck@google.com diff --git a/libs/nativewindow/tests/ANativeWindowTest.cpp b/libs/nativewindow/tests/ANativeWindowTest.cpp index 937ff02241..51d0c8195a 100644 --- a/libs/nativewindow/tests/ANativeWindowTest.cpp +++ b/libs/nativewindow/tests/ANativeWindowTest.cpp @@ -50,14 +50,9 @@ protected: const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); ALOGV("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); -#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) - mItemConsumer = new BufferItemConsumer(GRALLOC_USAGE_SW_READ_OFTEN); - mWindow = new TestableSurface(mItemConsumer->getSurface()->getIGraphicBufferProducer()); -#else - BufferQueue::createBufferQueue(&mProducer, &mConsumer); - mItemConsumer = new BufferItemConsumer(mConsumer, GRALLOC_USAGE_SW_READ_OFTEN); - mWindow = new TestableSurface(mProducer); -#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + sp<Surface> surface; + std::tie(mItemConsumer, surface) = BufferItemConsumer::create(GRALLOC_USAGE_SW_READ_OFTEN); + mWindow = new TestableSurface(surface->getIGraphicBufferProducer()); const int success = native_window_api_connect(mWindow.get(), NATIVE_WINDOW_API_CPU); EXPECT_EQ(0, success); } diff --git a/services/stats/OWNERS b/services/stats/OWNERS index a599619ec2..791b711de8 100644 --- a/services/stats/OWNERS +++ b/services/stats/OWNERS @@ -1,6 +1,5 @@ jeffreyhuang@google.com joeo@google.com -jtnguyen@google.com muhammadq@google.com ruchirr@google.com singhtejinder@google.com diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp index ff360b754c..b9c79df9b7 100644 --- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp +++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp @@ -206,7 +206,11 @@ bool VSyncPredictor::addVsyncTimestamp(nsecs_t timestamp) { // Normalizing to the oldest timestamp cuts down on error in calculating the intercept. const auto oldestTS = *std::min_element(mTimestamps.begin(), mTimestamps.end()); auto it = mRateMap.find(idealPeriod()); - auto const currentPeriod = it->second.slope; + // Calculated slope over the period of time can become outdated as the new timestamps are + // stored. Using idealPeriod instead provides a rate which is valid at all the times. + auto const currentPeriod = FlagManager::getInstance().vsync_predictor_recovery() + ? idealPeriod() + : it->second.slope; // The mean of the ordinals must be precise for the intercept calculation, so scale them up for // fixed-point arithmetic. diff --git a/services/surfaceflinger/ScreenCaptureOutput.cpp b/services/surfaceflinger/ScreenCaptureOutput.cpp index 712390574f..af6d4d30e4 100644 --- a/services/surfaceflinger/ScreenCaptureOutput.cpp +++ b/services/surfaceflinger/ScreenCaptureOutput.cpp @@ -209,6 +209,7 @@ ScreenCaptureOutput::generateClientCompositionRequests( } compositionengine::LayerFE::LayerSettings fillLayer; + fillLayer.name = "ScreenCaptureFillLayer"; fillLayer.source.buffer.buffer = nullptr; fillLayer.source.solidColor = half3(0.0f, 0.0f, 0.0f); fillLayer.geometry.boundaries = diff --git a/services/surfaceflinger/common/FlagManager.cpp b/services/surfaceflinger/common/FlagManager.cpp index f9aba9fe10..abde524214 100644 --- a/services/surfaceflinger/common/FlagManager.cpp +++ b/services/surfaceflinger/common/FlagManager.cpp @@ -128,6 +128,7 @@ void FlagManager::dump(std::string& result) const { DUMP_ACONFIG_FLAG(graphite_renderengine_preview_rollout); DUMP_ACONFIG_FLAG(increase_missed_frame_jank_threshold); DUMP_ACONFIG_FLAG(refresh_rate_overlay_on_external_display); + DUMP_ACONFIG_FLAG(vsync_predictor_recovery); /// Trunk stable readonly flags /// /// IMPORTANT - please keep alphabetize to reduce merge conflicts @@ -304,6 +305,7 @@ FLAG_MANAGER_ACONFIG_FLAG(adpf_gpu_sf, "") FLAG_MANAGER_ACONFIG_FLAG(adpf_native_session_manager, ""); FLAG_MANAGER_ACONFIG_FLAG(graphite_renderengine_preview_rollout, ""); FLAG_MANAGER_ACONFIG_FLAG(increase_missed_frame_jank_threshold, ""); +FLAG_MANAGER_ACONFIG_FLAG(vsync_predictor_recovery, ""); /// Trunk stable server (R/W) flags from outside SurfaceFlinger /// FLAG_MANAGER_ACONFIG_FLAG_IMPORTED(adpf_use_fmq_channel, "", android::os) diff --git a/services/surfaceflinger/common/include/common/FlagManager.h b/services/surfaceflinger/common/include/common/FlagManager.h index de3f359d7e..6295c5b17f 100644 --- a/services/surfaceflinger/common/include/common/FlagManager.h +++ b/services/surfaceflinger/common/include/common/FlagManager.h @@ -63,6 +63,7 @@ public: bool graphite_renderengine_preview_rollout() const; bool increase_missed_frame_jank_threshold() const; bool refresh_rate_overlay_on_external_display() const; + bool vsync_predictor_recovery() const; /// Trunk stable readonly flags /// /// IMPORTANT - please keep alphabetize to reduce merge conflicts diff --git a/services/surfaceflinger/surfaceflinger_flags_new.aconfig b/services/surfaceflinger/surfaceflinger_flags_new.aconfig index fa1da45e41..d8f51fe7e4 100644 --- a/services/surfaceflinger/surfaceflinger_flags_new.aconfig +++ b/services/surfaceflinger/surfaceflinger_flags_new.aconfig @@ -321,6 +321,16 @@ flag { } # vrr_bugfix_dropped_frame flag { + name: "vsync_predictor_recovery" + namespace: "core_graphics" + description: "Recover the vsync predictor from bad vsync model" + bug: "385059265" + metadata { + purpose: PURPOSE_BUGFIX + } + } # vsync_predictor_recovery + +flag { name: "window_blur_kawase2" namespace: "core_graphics" description: "Flag for using Kawase2 algorithm for window blur" diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp index 918107d270..a221d5e79b 100644 --- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp @@ -304,6 +304,53 @@ TEST_F(VSyncPredictorTest, againstOutliersDiscontinuous_500hzLowVariance) { EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError)); } +TEST_F(VSyncPredictorTest, recoverAfterDriftedVSyncAreReplacedWithCorrectVSync) { + SET_FLAG_FOR_TEST(flags::vsync_predictor_recovery, true); + auto constexpr idealPeriodNs = 4166666; + auto constexpr minFrameIntervalNs = 8333333; + auto constexpr idealPeriod = Fps::fromPeriodNsecs(idealPeriodNs); + auto constexpr minFrameRate = Fps::fromPeriodNsecs(minFrameIntervalNs); + hal::VrrConfig vrrConfig{.minFrameIntervalNs = minFrameIntervalNs}; + ftl::NonNull<DisplayModePtr> mode = + ftl::as_non_null(createVrrDisplayMode(DisplayModeId(0), idealPeriod, vrrConfig)); + VSyncPredictor vrrTracker{std::make_unique<ClockWrapper>(mClock), mode, kHistorySize, + kMinimumSamplesForPrediction, kOutlierTolerancePercent}; + vrrTracker.setRenderRate(minFrameRate, /*applyImmediately*/ true); + // Curated list of VSyncs that causes the VSync drift. + std::vector<nsecs_t> const simulatedVsyncs{74473665741, 74481774375, 74489911818, 74497993491, + 74506000833, 74510002150, 74513904390, 74517748707, + 74521550947, 74525383187, 74529165427, 74533067667, + 74536751484, 74540653724, 74544282649, 74548084889, + 74551917129, 74555699369, 74559601609, 74563601611, + 74567503851, 74571358168, 74575260408, 74578889333, + 74582691573, 74586523813, 74590306053, 74593589870, + 74597492110, 74601121035, 74604923275, 74608755515, + 74612537755, 74616166680, 74619795605, 74623424530, + 74627043455, 74630645695, 74634245935, 74637778175, + 74641291992, 74644794232, 74648275157, 74651575397, + 74654807637, 74658007877, 74661176117, 74664345357}; + for (auto const& timestamp : simulatedVsyncs) { + vrrTracker.addVsyncTimestamp(timestamp); + } + auto slope = vrrTracker.getVSyncPredictionModel().slope; + // Without using the idealPeriod for the calculation of the VSync predictor mode the + // the slope would be 3343031 + EXPECT_THAT(slope, IsCloseTo(4347805, mMaxRoundingError)); + EXPECT_FALSE(vrrTracker.needsMoreSamples()); + + auto lastVsync = 74664345357; + // Add valid VSyncs to replace the drifted VSyncs + for (int i = 0; i <= kHistorySize; i++) { + lastVsync += minFrameIntervalNs; + EXPECT_TRUE(vrrTracker.addVsyncTimestamp(lastVsync)); + } + EXPECT_FALSE(vrrTracker.needsMoreSamples()); + slope = vrrTracker.getVSyncPredictionModel().slope; + // Corrected slop is closer to the idealPeriod + // when valid vsync are inserted otherwise this would still be 3349673 + EXPECT_THAT(slope, IsCloseTo(idealPeriodNs, mMaxRoundingError)); +} + TEST_F(VSyncPredictorTest, handlesVsyncChange) { auto const fastPeriod = 100; auto const fastTimeBase = 100; @@ -397,8 +444,8 @@ TEST_F(VSyncPredictorTest, idealModelPredictionsBeforeRegressionModelIsBuilt) { } } -// See b/145667109, and comment in prod code under test. -TEST_F(VSyncPredictorTest, doesNotPredictBeforeTimePointWithHigherIntercept) { +TEST_F(VSyncPredictorTest, doesNotPredictBeforeTimePointWithHigherIntercept_withPredictorRecovery) { + SET_FLAG_FOR_TEST(flags::vsync_predictor_recovery, true); std::vector<nsecs_t> const simulatedVsyncs{ 158929578733000, 158929306806205, // oldest TS in ringbuffer @@ -409,6 +456,34 @@ TEST_F(VSyncPredictorTest, doesNotPredictBeforeTimePointWithHigherIntercept) { 158929706370359, }; auto const idealPeriod = 11111111; + auto const expectedPeriod = 11079563; + auto const expectedIntercept = 1335662; + + tracker.setDisplayModePtr(displayMode(idealPeriod)); + for (auto const& timestamp : simulatedVsyncs) { + tracker.addVsyncTimestamp(timestamp); + } + + auto [slope, intercept] = tracker.getVSyncPredictionModel(); + EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError)); + EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError)); + + // (timePoint - oldestTS) % expectedPeriod works out to be: 894272 + // (timePoint - oldestTS) / expectedPeriod works out to be: 38.08 + auto const timePoint = 158929728723871; + auto const prediction = tracker.nextAnticipatedVSyncTimeFrom(timePoint); + EXPECT_THAT(prediction, Ge(timePoint)); +} + +// See b/145667109, and comment in prod code under test. +TEST_F(VSyncPredictorTest, doesNotPredictBeforeTimePointWithHigherIntercept) { + SET_FLAG_FOR_TEST(flags::vsync_predictor_recovery, false); + std::vector<nsecs_t> const simulatedVsyncs{ + 158929578733000, + 158929306806205, // oldest TS in ringbuffer + 158929650879052, 158929661969209, 158929684198847, 158929695268171, 158929706370359, + }; + auto const idealPeriod = 11111111; auto const expectedPeriod = 11113919; auto const expectedIntercept = -1195945; @@ -421,9 +496,9 @@ TEST_F(VSyncPredictorTest, doesNotPredictBeforeTimePointWithHigherIntercept) { EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError)); EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError)); - // (timePoint - oldestTS) % expectedPeriod works out to be: 395334 - // (timePoint - oldestTS) / expectedPeriod works out to be: 38.96 - // so failure to account for the offset will floor the ordinal to 38, which was in the past. + // (timePoint - oldestTS) % expectedPeriod works out to be: 10702663 + // (timePoint - oldestTS) / expectedPeriod works out to be: 37.96 + // so failure to account for the offset will floor the ordinal to 37, which was in the past. auto const timePoint = 158929728723871; auto const prediction = tracker.nextAnticipatedVSyncTimeFrom(timePoint); EXPECT_THAT(prediction, Ge(timePoint)); diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp index 879d2d0fa7..be8fb3ea1d 100644 --- a/vulkan/libvulkan/Android.bp +++ b/vulkan/libvulkan/Android.bp @@ -22,6 +22,13 @@ package { default_applicable_licenses: ["frameworks_native_license"], } +// Expose internal header files to test testing binary +cc_library_headers { + name: "libvulkanprivate_headers-testing", + export_include_dirs: ["."], + visibility: ["//frameworks/native/vulkan/tests"], +} + ndk_library { name: "libvulkan", symbol_file: "libvulkan.map.txt", diff --git a/vulkan/libvulkan/TEST_MAPPING b/vulkan/libvulkan/TEST_MAPPING new file mode 100644 index 0000000000..16e342b7c0 --- /dev/null +++ b/vulkan/libvulkan/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "presubmit": [ + { + "name": "libvulkan_test" + } + ] +} diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index 09b0a145af..5e2b55ef75 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -1413,115 +1413,138 @@ static void DestroySwapchainInternal(VkDevice device, allocator->pfnFree(allocator->pUserData, swapchain); } -static VkResult getProducerUsage(const VkDevice& device, - const VkSwapchainCreateInfoKHR* create_info, - const VkSwapchainImageUsageFlagsANDROID swapchain_image_usage, - bool create_protected_swapchain, - uint64_t* producer_usage) { - // Get the physical device to query the appropriate producer usage - const VkPhysicalDevice& pdev = GetData(device).driver_physical_device; - const InstanceData& instance_data = GetData(pdev); - const InstanceDriverTable& instance_dispatch = instance_data.driver; - if (instance_dispatch.GetPhysicalDeviceImageFormatProperties2 || - instance_dispatch.GetPhysicalDeviceImageFormatProperties2KHR) { - // Look through the create_info pNext chain passed to createSwapchainKHR - // for an image compression control struct. - // if one is found AND the appropriate extensions are enabled, create a - // VkImageCompressionControlEXT structure to pass on to - // GetPhysicalDeviceImageFormatProperties2 - void* compression_control_pNext = nullptr; - VkImageCompressionControlEXT image_compression = {}; - const VkSwapchainCreateInfoKHR* create_infos = create_info; - while (create_infos->pNext) { - create_infos = reinterpret_cast<const VkSwapchainCreateInfoKHR*>(create_infos->pNext); - switch (create_infos->sType) { - case VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT: { - const VkImageCompressionControlEXT* compression_infos = - reinterpret_cast<const VkImageCompressionControlEXT*>(create_infos); - image_compression = *compression_infos; - image_compression.pNext = nullptr; - compression_control_pNext = &image_compression; - } break; - default: - // Ignore all other info structs - break; - } +static VkResult getProducerUsageGPDIFP2( + const VkPhysicalDevice& pdev, + const VkSwapchainCreateInfoKHR* create_info, + const VkSwapchainImageUsageFlagsANDROID swapchain_image_usage, + bool create_protected_swapchain, + uint64_t* producer_usage) { + // Look through the create_info pNext chain passed to createSwapchainKHR + // for an image compression control struct. + // if one is found AND the appropriate extensions are enabled, create a + // VkImageCompressionControlEXT structure to pass on to + // GetPhysicalDeviceImageFormatProperties2 + void* compression_control_pNext = nullptr; + VkImageCompressionControlEXT image_compression = {}; + const VkSwapchainCreateInfoKHR* create_infos = create_info; + while (create_infos->pNext) { + create_infos = reinterpret_cast<const VkSwapchainCreateInfoKHR*>( + create_infos->pNext); + switch (create_infos->sType) { + case VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT: { + const VkImageCompressionControlEXT* compression_infos = + reinterpret_cast<const VkImageCompressionControlEXT*>( + create_infos); + image_compression = *compression_infos; + image_compression.pNext = nullptr; + compression_control_pNext = &image_compression; + } break; + default: + // Ignore all other info structs + break; } + } - // call GetPhysicalDeviceImageFormatProperties2KHR - VkPhysicalDeviceExternalImageFormatInfo external_image_format_info = { - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO, - .pNext = compression_control_pNext, - .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID, - }; + // call GetPhysicalDeviceImageFormatProperties2KHR + VkPhysicalDeviceExternalImageFormatInfo external_image_format_info = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO, + .pNext = compression_control_pNext, + .handleType = + VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID, + }; - // AHB does not have an sRGB format so we can't pass it to GPDIFP - // We need to convert the format to unorm if it is srgb - VkFormat format = create_info->imageFormat; - if (format == VK_FORMAT_R8G8B8A8_SRGB) { - format = VK_FORMAT_R8G8B8A8_UNORM; - } + // AHB does not have an sRGB format so we can't pass it to GPDIFP + // We need to convert the format to unorm if it is srgb + VkFormat format = create_info->imageFormat; + if (format == VK_FORMAT_R8G8B8A8_SRGB) { + format = VK_FORMAT_R8G8B8A8_UNORM; + } - VkPhysicalDeviceImageFormatInfo2 image_format_info = { - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, - .pNext = &external_image_format_info, - .format = format, - .type = VK_IMAGE_TYPE_2D, - .tiling = VK_IMAGE_TILING_OPTIMAL, - .usage = create_info->imageUsage, - .flags = create_protected_swapchain ? VK_IMAGE_CREATE_PROTECTED_BIT : 0u, - }; + VkPhysicalDeviceImageFormatInfo2 image_format_info = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, + .pNext = &external_image_format_info, + .format = format, + .type = VK_IMAGE_TYPE_2D, + .tiling = VK_IMAGE_TILING_OPTIMAL, + .usage = create_info->imageUsage, + .flags = + create_protected_swapchain ? VK_IMAGE_CREATE_PROTECTED_BIT : 0u, + }; - // If supporting mutable format swapchain add the mutable format flag - if (create_info->flags & VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR) { - image_format_info.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; - image_format_info.flags |= VK_IMAGE_CREATE_EXTENDED_USAGE_BIT_KHR; - } + // If supporting mutable format swapchain add the mutable format flag + if (create_info->flags & VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR) { + image_format_info.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; + image_format_info.flags |= VK_IMAGE_CREATE_EXTENDED_USAGE_BIT_KHR; + } - VkAndroidHardwareBufferUsageANDROID ahb_usage; - ahb_usage.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID; - ahb_usage.pNext = nullptr; + VkAndroidHardwareBufferUsageANDROID ahb_usage; + ahb_usage.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID; + ahb_usage.pNext = nullptr; - VkImageFormatProperties2 image_format_properties; - image_format_properties.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2; - image_format_properties.pNext = &ahb_usage; + VkImageFormatProperties2 image_format_properties; + image_format_properties.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2; + image_format_properties.pNext = &ahb_usage; - VkResult result = GetPhysicalDeviceImageFormatProperties2( - pdev, &image_format_info, &image_format_properties); - if (result != VK_SUCCESS) { - ALOGE( - "VkGetPhysicalDeviceImageFormatProperties2 for AHB usage " - "failed: %d", - result); - return VK_ERROR_SURFACE_LOST_KHR; - } + VkResult result = GetPhysicalDeviceImageFormatProperties2( + pdev, &image_format_info, &image_format_properties); + if (result != VK_SUCCESS) { + ALOGE( + "VkGetPhysicalDeviceImageFormatProperties2 for AHB usage " + "failed: %d", + result); + return VK_ERROR_SURFACE_LOST_KHR; + } + // Determine if USAGE_FRONT_BUFFER is needed. + // GPDIFP2 has no means of using VkSwapchainImageUsageFlagsANDROID when + // querying for producer_usage. So androidHardwareBufferUsage will not + // contain USAGE_FRONT_BUFFER. We need to manually check for usage here. + if (!(swapchain_image_usage & + VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID)) { + *producer_usage = ahb_usage.androidHardwareBufferUsage; + return VK_SUCCESS; + } - // Determine if USAGE_FRONT_BUFFER is needed. - // GPDIFP2 has no means of using VkSwapchainImageUsageFlagsANDROID when - // querying for producer_usage. So androidHardwareBufferUsage will not - // contain USAGE_FRONT_BUFFER. We need to manually check for usage here. - if (!(swapchain_image_usage & VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID)) { - *producer_usage = ahb_usage.androidHardwareBufferUsage; - return VK_SUCCESS; - } + // Check if USAGE_FRONT_BUFFER is supported for this swapchain + AHardwareBuffer_Desc ahb_desc = { + .width = create_info->imageExtent.width, + .height = create_info->imageExtent.height, + .layers = create_info->imageArrayLayers, + .format = create_info->imageFormat, + .usage = ahb_usage.androidHardwareBufferUsage | + AHARDWAREBUFFER_USAGE_FRONT_BUFFER, + .stride = 0, // stride is always ignored when calling isSupported() + }; - // Check if USAGE_FRONT_BUFFER is supported for this swapchain - AHardwareBuffer_Desc ahb_desc = { - .width = create_info->imageExtent.width, - .height = create_info->imageExtent.height, - .layers = create_info->imageArrayLayers, - .format = create_info->imageFormat, - .usage = ahb_usage.androidHardwareBufferUsage | AHARDWAREBUFFER_USAGE_FRONT_BUFFER, - .stride = 0, // stride is always ignored when calling isSupported() - }; + // If FRONT_BUFFER is not supported in the GPDIFP2 path + // then we need to fallback to GetSwapchainGrallocUsageXAndroid + if (AHardwareBuffer_isSupported(&ahb_desc)) { + *producer_usage = ahb_usage.androidHardwareBufferUsage; + *producer_usage |= AHARDWAREBUFFER_USAGE_FRONT_BUFFER; + return VK_SUCCESS; + } + + return VK_ERROR_FORMAT_NOT_SUPPORTED; +} + +static VkResult getProducerUsage(const VkDevice& device, + const VkSwapchainCreateInfoKHR* create_info, + const VkSwapchainImageUsageFlagsANDROID swapchain_image_usage, + bool create_protected_swapchain, + uint64_t* producer_usage) { + // Get the physical device to query the appropriate producer usage + const VkPhysicalDevice& pdev = GetData(device).driver_physical_device; + const InstanceData& instance_data = GetData(pdev); + const InstanceDriverTable& instance_dispatch = instance_data.driver; - // If FRONT_BUFFER is not supported, - // then we need to call GetSwapchainGrallocUsageXAndroid below - if (AHardwareBuffer_isSupported(&ahb_desc)) { - *producer_usage = ahb_usage.androidHardwareBufferUsage; - *producer_usage |= AHARDWAREBUFFER_USAGE_FRONT_BUFFER; + if (instance_dispatch.GetPhysicalDeviceImageFormatProperties2 || + instance_dispatch.GetPhysicalDeviceImageFormatProperties2KHR) { + VkResult result = + getProducerUsageGPDIFP2(pdev, create_info, swapchain_image_usage, + create_protected_swapchain, producer_usage); + if (result == VK_SUCCESS) { return VK_SUCCESS; } + // Fall through to gralloc path on error } uint64_t native_usage = 0; diff --git a/vulkan/tests/Android.bp b/vulkan/tests/Android.bp index 551d9b753c..db218c18ee 100644 --- a/vulkan/tests/Android.bp +++ b/vulkan/tests/Android.bp @@ -27,6 +27,7 @@ cc_test { header_libs: [ "hwvulkan_headers", + "libvulkanprivate_headers-testing", "vulkan_headers", ], diff --git a/vulkan/tests/libvulkan_test.cpp b/vulkan/tests/libvulkan_test.cpp index 128d640eeb..7c9ef7d095 100644 --- a/vulkan/tests/libvulkan_test.cpp +++ b/vulkan/tests/libvulkan_test.cpp @@ -15,6 +15,7 @@ */ #include <android/log.h> +#include <driver.h> #include <gmock/gmock.h> #include <gtest/gtest.h> #include <media/NdkImageReader.h> @@ -29,6 +30,8 @@ namespace android { +namespace libvulkantest { + class AImageReaderVulkanSwapchainTest : public ::testing::Test { public: AImageReaderVulkanSwapchainTest() {} @@ -271,17 +274,20 @@ class AImageReaderVulkanSwapchainTest : public ::testing::Test { VkResult res = vkCreateSwapchainKHR(mDevice, &swapchainInfo, nullptr, &mSwapchain); - VK_CHECK(res); - LOGI("Swapchain created successfully"); + if (res == VK_SUCCESS) { + LOGI("Swapchain created successfully"); - uint32_t swapchainImageCount = 0; - vkGetSwapchainImagesKHR(mDevice, mSwapchain, &swapchainImageCount, - nullptr); - std::vector<VkImage> swapchainImages(swapchainImageCount); - vkGetSwapchainImagesKHR(mDevice, mSwapchain, &swapchainImageCount, - swapchainImages.data()); + uint32_t swapchainImageCount = 0; + vkGetSwapchainImagesKHR(mDevice, mSwapchain, &swapchainImageCount, + nullptr); + std::vector<VkImage> swapchainImages(swapchainImageCount); + vkGetSwapchainImagesKHR(mDevice, mSwapchain, &swapchainImageCount, + swapchainImages.data()); - LOGI("Swapchain has %u images", swapchainImageCount); + LOGI("Swapchain has %u images", swapchainImageCount); + } else { + LOGI("Swapchain creation failed"); + } } // Image available callback (AImageReader) @@ -357,4 +363,79 @@ TEST_F(AImageReaderVulkanSwapchainTest, TestHelperMethods) { cleanUpSwapchainForTest(); } +// Passing state in these tests requires global state. Wrap each test in an +// anonymous namespace to prevent conflicting names. +namespace { + +VKAPI_ATTR VkResult VKAPI_CALL hookedGetPhysicalDeviceImageFormatProperties2KHR( + VkPhysicalDevice, + const VkPhysicalDeviceImageFormatInfo2*, + VkImageFormatProperties2*) { + return VK_ERROR_SURFACE_LOST_KHR; +} + +static PFN_vkGetSwapchainGrallocUsage2ANDROID + pfnNextGetSwapchainGrallocUsage2ANDROID = nullptr; + +static bool g_grallocCalled = false; + +VKAPI_ATTR VkResult VKAPI_CALL hookGetSwapchainGrallocUsage2ANDROID( + VkDevice device, + VkFormat format, + VkImageUsageFlags imageUsage, + VkSwapchainImageUsageFlagsANDROID swapchainImageUsage, + uint64_t* grallocConsumerUsage, + uint64_t* grallocProducerUsage) { + g_grallocCalled = true; + if (pfnNextGetSwapchainGrallocUsage2ANDROID) { + return pfnNextGetSwapchainGrallocUsage2ANDROID( + device, format, imageUsage, swapchainImageUsage, + grallocConsumerUsage, grallocProducerUsage); + } + + return VK_ERROR_INITIALIZATION_FAILED; +} + +TEST_F(AImageReaderVulkanSwapchainTest, getProducerUsageFallbackTest1) { + // BUG: 379230826 + // Verify that getProducerUsage falls back to + // GetSwapchainGrallocUsage*ANDROID if GPDIFP2 fails + std::vector<const char*> instanceLayers = {}; + std::vector<const char*> deviceLayers = {}; + createVulkanInstance(instanceLayers); + + createAImageReader(640, 480, AIMAGE_FORMAT_PRIVATE, 3); + getANativeWindowFromReader(); + createVulkanSurface(); + pickPhysicalDeviceAndQueueFamily(); + + createDeviceAndGetQueue(deviceLayers); + auto& pdev = vulkan::driver::GetData(mDevice).driver_physical_device; + auto& pdevDispatchTable = vulkan::driver::GetData(pdev).driver; + auto& deviceDispatchTable = vulkan::driver::GetData(mDevice).driver; + + ASSERT_NE(deviceDispatchTable.GetSwapchainGrallocUsage2ANDROID, nullptr); + + pdevDispatchTable.GetPhysicalDeviceImageFormatProperties2 = + hookedGetPhysicalDeviceImageFormatProperties2KHR; + deviceDispatchTable.GetSwapchainGrallocUsage2ANDROID = + hookGetSwapchainGrallocUsage2ANDROID; + + ASSERT_FALSE(g_grallocCalled); + + createSwapchain(); + + ASSERT_TRUE(g_grallocCalled); + + ASSERT_NE(mVkInstance, (VkInstance)VK_NULL_HANDLE); + ASSERT_NE(mPhysicalDev, (VkPhysicalDevice)VK_NULL_HANDLE); + ASSERT_NE(mDevice, (VkDevice)VK_NULL_HANDLE); + ASSERT_NE(mSurface, (VkSurfaceKHR)VK_NULL_HANDLE); + cleanUpSwapchainForTest(); +} + +} // namespace + +} // namespace libvulkantest + } // namespace android |