Add allocator-v2 extended options to BufferQueue
Bug: 268382490
Test: libgui_test
Change-Id: If43b31eede87cddfcbfe4b24b53c1bafb453ebf2
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index fb69fda..69345a9 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -423,6 +423,11 @@
sp<IConsumerListener> listener;
bool callOnFrameDequeued = false;
uint64_t bufferId = 0; // Only used if callOnFrameDequeued == true
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_EXTENDEDALLOCATE)
+ std::vector<gui::AdditionalOptions> allocOptions;
+ uint32_t allocOptionsGenId = 0;
+#endif
+
{ // Autolock scope
std::unique_lock<std::mutex> lock(mCore->mMutex);
@@ -486,11 +491,17 @@
}
const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);
- if (mCore->mSharedBufferSlot == found &&
- buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage)) {
- BQ_LOGE("dequeueBuffer: cannot re-allocate a shared"
- "buffer");
+ bool needsReallocation = buffer == nullptr ||
+ buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage);
+
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_EXTENDEDALLOCATE)
+ needsReallocation |= mSlots[found].mAdditionalOptionsGenerationId !=
+ mCore->mAdditionalOptionsGenerationId;
+#endif
+
+ if (mCore->mSharedBufferSlot == found && needsReallocation) {
+ BQ_LOGE("dequeueBuffer: cannot re-allocate a shared buffer");
return BAD_VALUE;
}
@@ -505,9 +516,7 @@
mSlots[found].mBufferState.dequeue();
- if ((buffer == nullptr) ||
- buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage))
- {
+ if (needsReallocation) {
if (CC_UNLIKELY(ATRACE_ENABLED())) {
if (buffer == nullptr) {
ATRACE_FORMAT_INSTANT("%s buffer reallocation: null", mConsumerName.c_str());
@@ -530,6 +539,10 @@
mSlots[found].mFence = Fence::NO_FENCE;
mCore->mBufferAge = 0;
mCore->mIsAllocating = true;
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_EXTENDEDALLOCATE)
+ allocOptions = mCore->mAdditionalOptions;
+ allocOptionsGenId = mCore->mAdditionalOptionsGenerationId;
+#endif
returnFlags |= BUFFER_NEEDS_REALLOCATION;
} else {
@@ -575,9 +588,29 @@
if (returnFlags & BUFFER_NEEDS_REALLOCATION) {
BQ_LOGV("dequeueBuffer: allocating a new buffer for slot %d", *outSlot);
+
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_EXTENDEDALLOCATE)
+ std::vector<GraphicBufferAllocator::AdditionalOptions> tempOptions;
+ tempOptions.reserve(allocOptions.size());
+ for (const auto& it : allocOptions) {
+ tempOptions.emplace_back(it.name.c_str(), it.value);
+ }
+ const GraphicBufferAllocator::AllocationRequest allocRequest = {
+ .importBuffer = true,
+ .width = width,
+ .height = height,
+ .format = format,
+ .layerCount = BQ_LAYER_COUNT,
+ .usage = usage,
+ .requestorName = {mConsumerName.c_str(), mConsumerName.size()},
+ .extras = std::move(tempOptions),
+ };
+ sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(allocRequest);
+#else
sp<GraphicBuffer> graphicBuffer =
new GraphicBuffer(width, height, format, BQ_LAYER_COUNT, usage,
{mConsumerName.c_str(), mConsumerName.size()});
+#endif
status_t error = graphicBuffer->initCheck();
@@ -587,6 +620,9 @@
if (error == NO_ERROR && !mCore->mIsAbandoned) {
graphicBuffer->setGenerationNumber(mCore->mGenerationNumber);
mSlots[*outSlot].mGraphicBuffer = graphicBuffer;
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_EXTENDEDALLOCATE)
+ mSlots[*outSlot].mAdditionalOptionsGenerationId = allocOptionsGenId;
+#endif
callOnFrameDequeued = true;
bufferId = mSlots[*outSlot].mGraphicBuffer->getId();
}
@@ -1342,6 +1378,9 @@
}
mCore->mAllowAllocation = true;
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_EXTENDEDALLOCATE)
+ mCore->mAdditionalOptions.clear();
+#endif
VALIDATE_CONSISTENCY();
return status;
}
@@ -1410,6 +1449,9 @@
mCore->mSidebandStream.clear();
mCore->mDequeueCondition.notify_all();
mCore->mAutoPrerotation = false;
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_EXTENDEDALLOCATE)
+ mCore->mAdditionalOptions.clear();
+#endif
listener = mCore->mConsumerListener;
} else if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
BQ_LOGE("disconnect: not connected (req=%d)", api);
@@ -1462,6 +1504,10 @@
PixelFormat allocFormat = PIXEL_FORMAT_UNKNOWN;
uint64_t allocUsage = 0;
std::string allocName;
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_EXTENDEDALLOCATE)
+ std::vector<gui::AdditionalOptions> allocOptions;
+ uint32_t allocOptionsGenId = 0;
+#endif
{ // Autolock scope
std::unique_lock<std::mutex> lock(mCore->mMutex);
mCore->waitWhileAllocatingLocked(lock);
@@ -1490,14 +1536,42 @@
allocUsage = usage | mCore->mConsumerUsageBits;
allocName.assign(mCore->mConsumerName.c_str(), mCore->mConsumerName.size());
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_EXTENDEDALLOCATE)
+ allocOptions = mCore->mAdditionalOptions;
+ allocOptionsGenId = mCore->mAdditionalOptionsGenerationId;
+#endif
+
mCore->mIsAllocating = true;
+
} // Autolock scope
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_EXTENDEDALLOCATE)
+ std::vector<GraphicBufferAllocator::AdditionalOptions> tempOptions;
+ tempOptions.reserve(allocOptions.size());
+ for (const auto& it : allocOptions) {
+ tempOptions.emplace_back(it.name.c_str(), it.value);
+ }
+ const GraphicBufferAllocator::AllocationRequest allocRequest = {
+ .importBuffer = true,
+ .width = allocWidth,
+ .height = allocHeight,
+ .format = allocFormat,
+ .layerCount = BQ_LAYER_COUNT,
+ .usage = allocUsage,
+ .requestorName = allocName,
+ .extras = std::move(tempOptions),
+ };
+#endif
+
Vector<sp<GraphicBuffer>> buffers;
for (size_t i = 0; i < newBufferCount; ++i) {
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_EXTENDEDALLOCATE)
+ sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(allocRequest);
+#else
sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
allocWidth, allocHeight, allocFormat, BQ_LAYER_COUNT,
allocUsage, allocName);
+#endif
status_t result = graphicBuffer->initCheck();
@@ -1524,8 +1598,12 @@
PixelFormat checkFormat = format != 0 ?
format : mCore->mDefaultBufferFormat;
uint64_t checkUsage = usage | mCore->mConsumerUsageBits;
+ bool allocOptionsChanged = false;
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_EXTENDEDALLOCATE)
+ allocOptionsChanged = allocOptionsGenId != mCore->mAdditionalOptionsGenerationId;
+#endif
if (checkWidth != allocWidth || checkHeight != allocHeight ||
- checkFormat != allocFormat || checkUsage != allocUsage) {
+ checkFormat != allocFormat || checkUsage != allocUsage || allocOptionsChanged) {
// Something changed while we released the lock. Retry.
BQ_LOGV("allocateBuffers: size/format/usage changed while allocating. Retrying.");
mCore->mIsAllocating = false;
@@ -1543,6 +1621,9 @@
mCore->clearBufferSlotLocked(*slot); // Clean up the slot first
mSlots[*slot].mGraphicBuffer = buffers[i];
mSlots[*slot].mFence = Fence::NO_FENCE;
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_EXTENDEDALLOCATE)
+ mSlots[*slot].mAdditionalOptionsGenerationId = allocOptionsGenId;
+#endif
// freeBufferLocked puts this slot on the free slots list. Since
// we then attached a buffer, move the slot to free buffer list.
@@ -1778,4 +1859,29 @@
}
#endif
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_EXTENDEDALLOCATE)
+status_t BufferQueueProducer::setAdditionalOptions(
+ const std::vector<gui::AdditionalOptions>& options) {
+ ATRACE_CALL();
+ BQ_LOGV("setAdditionalOptions, size = %zu", options.size());
+
+ if (!GraphicBufferAllocator::get().supportsAdditionalOptions()) {
+ return INVALID_OPERATION;
+ }
+
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
+
+ if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
+ BQ_LOGE("setAdditionalOptions: BufferQueue not connected, cannot set additional options");
+ return NO_INIT;
+ }
+
+ if (mCore->mAdditionalOptions != options) {
+ mCore->mAdditionalOptions = options;
+ mCore->mAdditionalOptionsGenerationId++;
+ }
+ return NO_ERROR;
+}
+#endif
+
} // namespace android
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index e81c098..0914480 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -80,6 +80,7 @@
QUERY_MULTIPLE,
GET_LAST_QUEUED_BUFFER2,
SET_FRAME_RATE,
+ SET_ADDITIONAL_OPTIONS,
};
class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
@@ -778,6 +779,25 @@
return result;
}
#endif
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_EXTENDEDALLOCATE)
+ virtual status_t setAdditionalOptions(const std::vector<gui::AdditionalOptions>& options) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
+ if (options.size() > 100) {
+ return BAD_VALUE;
+ }
+ data.writeInt32(options.size());
+ for (const auto& it : options) {
+ data.writeCString(it.name.c_str());
+ data.writeInt64(it.value);
+ }
+ status_t result = remote()->transact(SET_ADDITIONAL_OPTIONS, data, &reply);
+ if (result == NO_ERROR) {
+ result = reply.readInt32();
+ }
+ return result;
+ }
+#endif
};
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -981,6 +1001,13 @@
}
#endif
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_EXTENDEDALLOCATE)
+status_t IGraphicBufferProducer::setAdditionalOptions(const std::vector<gui::AdditionalOptions>&) {
+ // No-op for IGBP other than BufferQueue.
+ return INVALID_OPERATION;
+}
+#endif
+
status_t IGraphicBufferProducer::exportToParcel(Parcel* parcel) {
status_t res = OK;
res = parcel->writeUint32(USE_BUFFER_QUEUE);
@@ -1533,6 +1560,28 @@
return NO_ERROR;
}
#endif
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_EXTENDEDALLOCATE)
+ case SET_ADDITIONAL_OPTIONS: {
+ CHECK_INTERFACE(IGraphicBuffer, data, reply);
+ int optionCount = data.readInt32();
+ if (optionCount < 0 || optionCount > 100) {
+ return BAD_VALUE;
+ }
+ std::vector<gui::AdditionalOptions> opts;
+ opts.reserve(optionCount);
+ for (int i = 0; i < optionCount; i++) {
+ const char* name = data.readCString();
+ int64_t value = 0;
+ if (name == nullptr || data.readInt64(&value) != NO_ERROR) {
+ return BAD_VALUE;
+ }
+ opts.emplace_back(name, value);
+ }
+ status_t result = setAdditionalOptions(opts);
+ reply->writeInt32(result);
+ return NO_ERROR;
+ }
+#endif
}
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 086544e..87fd448 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -1475,6 +1475,9 @@
case NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO:
res = dispatchSetFrameTimelineInfo(args);
break;
+ case NATIVE_WINDOW_SET_BUFFERS_ADDITIONAL_OPTIONS:
+ res = dispatchSetAdditionalOptions(args);
+ break;
default:
res = NAME_NOT_FOUND;
break;
@@ -1833,6 +1836,24 @@
return setFrameTimelineInfo(nativeWindowFtlInfo.frameNumber, ftlInfo);
}
+int Surface::dispatchSetAdditionalOptions(va_list args) {
+ ATRACE_CALL();
+
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_EXTENDEDALLOCATE)
+ const AHardwareBufferLongOptions* opts = va_arg(args, const AHardwareBufferLongOptions*);
+ const size_t optsSize = va_arg(args, size_t);
+ std::vector<gui::AdditionalOptions> convertedOpts;
+ convertedOpts.reserve(optsSize);
+ for (size_t i = 0; i < optsSize; i++) {
+ convertedOpts.emplace_back(opts[i].name, opts[i].value);
+ }
+ return setAdditionalOptions(convertedOpts);
+#else
+ (void)args;
+ return INVALID_OPERATION;
+#endif
+}
+
bool Surface::transformToDisplayInverse() const {
return (mTransform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) ==
NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY;
@@ -2619,6 +2640,17 @@
return BAD_VALUE;
}
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_EXTENDEDALLOCATE)
+status_t Surface::setAdditionalOptions(const std::vector<gui::AdditionalOptions>& options) {
+ if (!GraphicBufferAllocator::get().supportsAdditionalOptions()) {
+ return INVALID_OPERATION;
+ }
+
+ Mutex::Autolock lock(mMutex);
+ return mGraphicBufferProducer->setAdditionalOptions(options);
+}
+#endif
+
sp<IBinder> Surface::getSurfaceControlHandle() const {
Mutex::Autolock lock(mMutex);
return mSurfaceControlHandle;
diff --git a/libs/gui/include/gui/AdditionalOptions.h b/libs/gui/include/gui/AdditionalOptions.h
new file mode 100644
index 0000000..87cb913
--- /dev/null
+++ b/libs/gui/include/gui/AdditionalOptions.h
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <string>
+
+namespace android::gui {
+// Additional options to pass to AHardwareBuffer_allocateWithOptions.
+// See also allocator-v2's BufferDescriptorInfo.aidl
+struct AdditionalOptions {
+ std::string name;
+ int64_t value;
+
+ bool operator==(const AdditionalOptions& other) const {
+ return value == other.value && name == other.name;
+ }
+};
+} // namespace android::gui
diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h
index 22c2be7..bb52c8e 100644
--- a/libs/gui/include/gui/BufferQueueCore.h
+++ b/libs/gui/include/gui/BufferQueueCore.h
@@ -17,6 +17,9 @@
#ifndef ANDROID_GUI_BUFFERQUEUECORE_H
#define ANDROID_GUI_BUFFERQUEUECORE_H
+#include <com_android_graphics_libgui_flags.h>
+
+#include <gui/AdditionalOptions.h>
#include <gui/BufferItem.h>
#include <gui/BufferQueueDefs.h>
#include <gui/BufferSlot.h>
@@ -357,6 +360,14 @@
// This allows the consumer to acquire an additional buffer if that buffer is not droppable and
// will eventually be released or acquired by the consumer.
bool mAllowExtraAcquire = false;
+
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_EXTENDEDALLOCATE)
+ // Additional options to pass when allocating GraphicBuffers.
+ // GenerationID changes when the options change, indicating reallocation is required
+ uint32_t mAdditionalOptionsGenerationId = 0;
+ std::vector<gui::AdditionalOptions> mAdditionalOptions;
+#endif
+
}; // class BufferQueueCore
} // namespace android
diff --git a/libs/gui/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h
index de47483..37a9607 100644
--- a/libs/gui/include/gui/BufferQueueProducer.h
+++ b/libs/gui/include/gui/BufferQueueProducer.h
@@ -17,6 +17,7 @@
#ifndef ANDROID_GUI_BUFFERQUEUEPRODUCER_H
#define ANDROID_GUI_BUFFERQUEUEPRODUCER_H
+#include <gui/AdditionalOptions.h>
#include <gui/BufferQueueDefs.h>
#include <gui/IGraphicBufferProducer.h>
@@ -208,6 +209,10 @@
int8_t changeFrameRateStrategy) override;
#endif
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_EXTENDEDALLOCATE)
+ status_t setAdditionalOptions(const std::vector<gui::AdditionalOptions>& options) override;
+#endif
+
protected:
// see IGraphicsBufferProducer::setMaxDequeuedBufferCount, but with the ability to retrieve the
// total maximum buffer count for the buffer queue (dequeued AND acquired)
diff --git a/libs/gui/include/gui/BufferSlot.h b/libs/gui/include/gui/BufferSlot.h
index 57704b1..5b32710 100644
--- a/libs/gui/include/gui/BufferSlot.h
+++ b/libs/gui/include/gui/BufferSlot.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_GUI_BUFFERSLOT_H
#define ANDROID_GUI_BUFFERSLOT_H
+#include <com_android_graphics_libgui_flags.h>
+
#include <ui/Fence.h>
#include <ui/GraphicBuffer.h>
@@ -230,6 +232,11 @@
// producer. If so, it needs to set the BUFFER_NEEDS_REALLOCATION flag when
// dequeued to prevent the producer from using a stale cached buffer.
bool mNeedsReallocation;
+
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_EXTENDEDALLOCATE)
+ // The generation id of the additional options that mGraphicBuffer was allocated with
+ uint32_t mAdditionalOptionsGenerationId = 0;
+#endif
};
} // namespace android
diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h
index 7639e70..8fca946 100644
--- a/libs/gui/include/gui/IGraphicBufferProducer.h
+++ b/libs/gui/include/gui/IGraphicBufferProducer.h
@@ -31,6 +31,7 @@
#include <ui/Rect.h>
#include <ui/Region.h>
+#include <gui/AdditionalOptions.h>
#include <gui/FrameTimestamps.h>
#include <gui/HdrMetadata.h>
@@ -684,6 +685,10 @@
int8_t changeFrameRateStrategy);
#endif
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_EXTENDEDALLOCATE)
+ virtual status_t setAdditionalOptions(const std::vector<gui::AdditionalOptions>& options);
+#endif
+
struct RequestBufferOutput : public Flattenable<RequestBufferOutput> {
RequestBufferOutput() = default;
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 39a59e4..bdcaaf2 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -215,6 +215,16 @@
int8_t changeFrameRateStrategy);
virtual status_t setFrameTimelineInfo(uint64_t frameNumber, const FrameTimelineInfo& info);
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_EXTENDEDALLOCATE)
+ /**
+ * Set additional options to be passed when allocating a buffer. Only valid if IAllocator-V2
+ * or newer is available, otherwise will return INVALID_OPERATION. Only allowed to be called
+ * after connect and options are cleared when disconnect happens. Returns NO_INIT if not
+ * connected
+ */
+ status_t setAdditionalOptions(const std::vector<gui::AdditionalOptions>& options);
+#endif
+
protected:
virtual ~Surface();
@@ -302,6 +312,7 @@
int dispatchGetLastQueuedBuffer(va_list args);
int dispatchGetLastQueuedBuffer2(va_list args);
int dispatchSetFrameTimelineInfo(va_list args);
+ int dispatchSetAdditionalOptions(va_list args);
std::mutex mNameMutex;
std::string mName;
diff --git a/libs/gui/libgui_flags.aconfig b/libs/gui/libgui_flags.aconfig
index 3864699..a902a8c 100644
--- a/libs/gui/libgui_flags.aconfig
+++ b/libs/gui/libgui_flags.aconfig
@@ -16,3 +16,11 @@
bug: "310927247"
is_fixed_read_only: true
}
+
+flag {
+ name: "bq_extendedallocate"
+ namespace: "core_graphics"
+ description: "Add BQ support for allocate with extended options"
+ bug: "268382490"
+ is_fixed_read_only: true
+}
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index 2faa330..ea8acbb 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -24,6 +24,7 @@
"-Wextra",
"-Wthread-safety",
"-DCOM_ANDROID_GRAPHICS_LIBGUI_FLAGS_BQ_SETFRAMERATE=true",
+ "-DCOM_ANDROID_GRAPHICS_LIBGUI_FLAGS_BQ_EXTENDEDALLOCATE=true",
],
srcs: [
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index 1ec6f91..272c5ed 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -28,6 +28,8 @@
#include <ui/GraphicBuffer.h>
+#include <android-base/properties.h>
+
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
@@ -47,6 +49,10 @@
using namespace std::chrono_literals;
+static bool IsCuttlefish() {
+ return ::android::base::GetProperty("ro.product.board", "") == "cutf";
+}
+
namespace android {
using namespace com::android::graphics::libgui;
@@ -1439,4 +1445,55 @@
EXPECT_EQ(nullptr, bufferConsumer.get());
}
+TEST_F(BufferQueueTest, TestAdditionalOptions) {
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+
+ sp<BufferItemConsumer> bufferConsumer =
+ sp<BufferItemConsumer>::make(consumer, GRALLOC_USAGE_SW_READ_OFTEN, 2);
+ ASSERT_NE(nullptr, bufferConsumer.get());
+ sp<Surface> surface = sp<Surface>::make(producer);
+ native_window_set_buffers_format(surface.get(), PIXEL_FORMAT_RGBA_8888);
+ native_window_set_buffers_dimensions(surface.get(), 100, 100);
+
+ std::array<AHardwareBufferLongOptions, 1> extras = {{
+ {.name = "android.hardware.graphics.common.Dataspace", ADATASPACE_DISPLAY_P3},
+ }};
+
+ ASSERT_EQ(NO_INIT,
+ native_window_set_buffers_additional_options(surface.get(), extras.data(),
+ extras.size()));
+
+ if (!IsCuttlefish()) {
+ GTEST_SKIP() << "Not cuttlefish";
+ }
+
+ ASSERT_EQ(OK, native_window_api_connect(surface.get(), NATIVE_WINDOW_API_CPU));
+ ASSERT_EQ(OK,
+ native_window_set_buffers_additional_options(surface.get(), extras.data(),
+ extras.size()));
+
+ ANativeWindowBuffer* windowBuffer = nullptr;
+ int fence = -1;
+ ASSERT_EQ(OK, ANativeWindow_dequeueBuffer(surface.get(), &windowBuffer, &fence));
+
+ AHardwareBuffer* buffer = ANativeWindowBuffer_getHardwareBuffer(windowBuffer);
+ ASSERT_TRUE(buffer);
+ ADataSpace dataSpace = AHardwareBuffer_getDataSpace(buffer);
+ EXPECT_EQ(ADATASPACE_DISPLAY_P3, dataSpace);
+
+ ANativeWindow_cancelBuffer(surface.get(), windowBuffer, -1);
+
+ // Check that reconnecting properly clears the options
+ ASSERT_EQ(OK, native_window_api_disconnect(surface.get(), NATIVE_WINDOW_API_CPU));
+ ASSERT_EQ(OK, native_window_api_connect(surface.get(), NATIVE_WINDOW_API_CPU));
+
+ ASSERT_EQ(OK, ANativeWindow_dequeueBuffer(surface.get(), &windowBuffer, &fence));
+ buffer = ANativeWindowBuffer_getHardwareBuffer(windowBuffer);
+ ASSERT_TRUE(buffer);
+ dataSpace = AHardwareBuffer_getDataSpace(buffer);
+ EXPECT_EQ(ADATASPACE_UNKNOWN, dataSpace);
+}
+
} // namespace android
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index 969a5cf..33c303a 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -41,6 +41,8 @@
#include <system/graphics.h>
#include <unistd.h>
+#include <vndk/hardware_buffer.h>
+
// system/window.h is a superset of the vndk and apex apis
#include <apex/window.h>
#include <vndk/window.h>
@@ -257,6 +259,7 @@
NATIVE_WINDOW_SET_QUERY_INTERCEPTOR = 47, /* private */
NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO = 48, /* private */
NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER2 = 49, /* private */
+ NATIVE_WINDOW_SET_BUFFERS_ADDITIONAL_OPTIONS = 50,
// clang-format on
};
@@ -1182,6 +1185,26 @@
return window->perform(window, NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO, frameTimelineInfo);
}
+/**
+ * native_window_set_buffers_additional_options(..., ExtendableType* additionalOptions, size_t size)
+ * All buffers dequeued after this call will have the additionalOptions specified.
+ *
+ * This must only be called after api_connect, otherwise NO_INIT is returned. The options are
+ * cleared in api_disconnect & api_connect
+ *
+ * If IAllocator is not v2 or newer this method returns INVALID_OPERATION
+ *
+ * \return NO_ERROR on success.
+ * \return NO_INIT if no api is connected
+ * \return INVALID_OPERATION if additional option support is not available
+ */
+static inline int native_window_set_buffers_additional_options(
+ struct ANativeWindow* window, const AHardwareBufferLongOptions* additionalOptions,
+ size_t additionalOptionsSize) {
+ return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_ADDITIONAL_OPTIONS, additionalOptions,
+ additionalOptionsSize);
+}
+
// ------------------------------------------------------------------------------------------------
// Candidates for APEX visibility
// These functions are planned to be made stable for APEX modules, but have not
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index 98082fb..1ebe597 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -291,5 +291,9 @@
return NO_ERROR;
}
+bool GraphicBufferAllocator::supportsAdditionalOptions() const {
+ return mAllocator->supportsAdditionalOptions();
+}
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/ui/include/ui/Gralloc.h b/libs/ui/include/ui/Gralloc.h
index e6015e0..4167dcb 100644
--- a/libs/ui/include/ui/Gralloc.h
+++ b/libs/ui/include/ui/Gralloc.h
@@ -226,6 +226,8 @@
const GraphicBufferAllocator::AllocationRequest&) const {
return GraphicBufferAllocator::AllocationResult(UNKNOWN_TRANSACTION);
}
+
+ virtual bool supportsAdditionalOptions() const { return false; }
};
} // namespace android
diff --git a/libs/ui/include/ui/Gralloc5.h b/libs/ui/include/ui/Gralloc5.h
index f9e8f5e..5aa5019 100644
--- a/libs/ui/include/ui/Gralloc5.h
+++ b/libs/ui/include/ui/Gralloc5.h
@@ -178,6 +178,8 @@
[[nodiscard]] GraphicBufferAllocator::AllocationResult allocate(
const GraphicBufferAllocator::AllocationRequest&) const override;
+ bool supportsAdditionalOptions() const override { return true; }
+
private:
const Gralloc5Mapper &mMapper;
std::shared_ptr<aidl::android::hardware::graphics::allocator::IAllocator> mAllocator;
diff --git a/libs/ui/include/ui/GraphicBufferAllocator.h b/libs/ui/include/ui/GraphicBufferAllocator.h
index 8f461e1..bbb2d77 100644
--- a/libs/ui/include/ui/GraphicBufferAllocator.h
+++ b/libs/ui/include/ui/GraphicBufferAllocator.h
@@ -107,6 +107,8 @@
void dump(std::string& res, bool less = true) const;
static void dumpToSystemLog(bool less = true);
+ bool supportsAdditionalOptions() const;
+
protected:
struct alloc_rec_t {
uint32_t width;