Merge "Fix HdrCapabilities flattening" into oc-mr1-dev
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index a711813..8a79ee1 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -311,6 +311,7 @@
return -1;
}
+#if APPLY_HARD_QUOTAS
if ((dq.dqb_bhardlimit == 0) || (dq.dqb_ihardlimit == 0)) {
auto path = create_data_path(uuid ? uuid->c_str() : nullptr);
struct statvfs stat;
@@ -335,6 +336,10 @@
// Hard quota already set; assume it's reasonable
return 0;
}
+#else
+ // Hard quotas disabled
+ return 0;
+#endif
}
binder::Status InstalldNativeService::createAppData(const std::unique_ptr<std::string>& uuid,
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 2b2725f..9ab56dd 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -1137,10 +1137,9 @@
// (re)Creates the app image if needed.
Dex2oatFileWrapper maybe_open_app_image(const char* out_oat_path, bool profile_guided,
bool is_public, int uid, bool is_secondary_dex) {
- // Use app images only if it is enabled (by a set image format) and we are compiling
- // profile-guided (so the app image doesn't conservatively contain all classes).
- // Note that we don't create an image for secondary dex files.
- if (is_secondary_dex || !profile_guided) {
+
+ // We don't create an image for secondary dex files.
+ if (is_secondary_dex) {
return Dex2oatFileWrapper();
}
@@ -1149,6 +1148,14 @@
// Happens when the out_oat_path has an unknown extension.
return Dex2oatFileWrapper();
}
+
+ // Use app images only if it is enabled (by a set image format) and we are compiling
+ // profile-guided (so the app image doesn't conservatively contain all classes).
+ if (!profile_guided) {
+ // In case there is a stale image, remove it now. Ignore any error.
+ unlink(image_path.c_str());
+ return Dex2oatFileWrapper();
+ }
char app_image_format[kPropertyValueMax];
bool have_app_image_format =
get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0;
diff --git a/cmds/installd/tests/installd_cache_test.cpp b/cmds/installd/tests/installd_cache_test.cpp
index aed068c..2d58515 100644
--- a/cmds/installd/tests/installd_cache_test.cpp
+++ b/cmds/installd/tests/installd_cache_test.cpp
@@ -99,7 +99,7 @@
static int64_t free() {
struct statvfs buf;
if (!statvfs("/data/local/tmp", &buf)) {
- return buf.f_bavail * buf.f_frsize;
+ return static_cast<int64_t>(buf.f_bavail) * buf.f_frsize;
} else {
PLOG(ERROR) << "Failed to statvfs";
return -1;
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 0faddf0..d277bd3 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -656,7 +656,7 @@
int64_t data_disk_free(const std::string& data_path) {
struct statvfs sfs;
if (statvfs(data_path.c_str(), &sfs) == 0) {
- return sfs.f_bavail * sfs.f_frsize;
+ return static_cast<int64_t>(sfs.f_bavail) * sfs.f_frsize;
} else {
PLOG(ERROR) << "Couldn't statvfs " << data_path;
return -1;
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index 070da84..da3a293 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -36,6 +36,8 @@
#define BYPASS_QUOTA 0
#define BYPASS_SDCARDFS 0
+#define APPLY_HARD_QUOTAS 1
+
namespace android {
namespace installd {
diff --git a/headers/media_plugin/media/openmax/OMX_VideoExt.h b/headers/media_plugin/media/openmax/OMX_VideoExt.h
index 79ddb76..1a5ad17 100644
--- a/headers/media_plugin/media/openmax/OMX_VideoExt.h
+++ b/headers/media_plugin/media/openmax/OMX_VideoExt.h
@@ -58,6 +58,12 @@
OMX_NALUFORMATSTYPE eNaluFormat;
} OMX_NALSTREAMFORMATTYPE;
+/** AVC additional profiles */
+typedef enum OMX_VIDEO_AVCPROFILETYPEEXT {
+ OMX_VIDEO_AVCProfileConstrainedBaseline = 0x10000, /**< Constrained baseline profile */
+ OMX_VIDEO_AVCProfileConstrainedHigh = 0x80000, /**< Constrained high profile */
+} OMX_VIDEO_AVCPROFILETYPEEXT;
+
/** VP8 profiles */
typedef enum OMX_VIDEO_VP8PROFILETYPE {
OMX_VIDEO_VP8ProfileMain = 0x01,
@@ -164,20 +170,20 @@
/** VP9 levels */
typedef enum OMX_VIDEO_VP9LEVELTYPE {
- OMX_VIDEO_VP9Level1 = 0x0,
- OMX_VIDEO_VP9Level11 = 0x1,
- OMX_VIDEO_VP9Level2 = 0x2,
- OMX_VIDEO_VP9Level21 = 0x4,
- OMX_VIDEO_VP9Level3 = 0x8,
- OMX_VIDEO_VP9Level31 = 0x10,
- OMX_VIDEO_VP9Level4 = 0x20,
- OMX_VIDEO_VP9Level41 = 0x40,
- OMX_VIDEO_VP9Level5 = 0x80,
- OMX_VIDEO_VP9Level51 = 0x100,
- OMX_VIDEO_VP9Level52 = 0x200,
- OMX_VIDEO_VP9Level6 = 0x400,
- OMX_VIDEO_VP9Level61 = 0x800,
- OMX_VIDEO_VP9Level62 = 0x1000,
+ OMX_VIDEO_VP9Level1 = 0x1,
+ OMX_VIDEO_VP9Level11 = 0x2,
+ OMX_VIDEO_VP9Level2 = 0x4,
+ OMX_VIDEO_VP9Level21 = 0x8,
+ OMX_VIDEO_VP9Level3 = 0x10,
+ OMX_VIDEO_VP9Level31 = 0x20,
+ OMX_VIDEO_VP9Level4 = 0x40,
+ OMX_VIDEO_VP9Level41 = 0x80,
+ OMX_VIDEO_VP9Level5 = 0x100,
+ OMX_VIDEO_VP9Level51 = 0x200,
+ OMX_VIDEO_VP9Level52 = 0x400,
+ OMX_VIDEO_VP9Level6 = 0x800,
+ OMX_VIDEO_VP9Level61 = 0x1000,
+ OMX_VIDEO_VP9Level62 = 0x2000,
OMX_VIDEO_VP9LevelUnknown = 0x6EFFFFFF,
OMX_VIDEO_VP9LevelMax = 0x7FFFFFFF
} OMX_VIDEO_VP9LEVELTYPE;
diff --git a/include/android/sharedmem_jni.h b/include/android/sharedmem_jni.h
new file mode 100644
index 0000000..38980f3
--- /dev/null
+++ b/include/android/sharedmem_jni.h
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+/**
+ * @addtogroup Memory
+ * @{
+ */
+
+/**
+ * @file sharedmem_jni.h
+ */
+
+#ifndef ANDROID_SHARED_MEMORY_JNI_H
+#define ANDROID_SHARED_MEMORY_JNI_H
+
+#include <jni.h>
+#include <android/sharedmem.h>
+#include <stddef.h>
+
+/******************************************************************
+ *
+ * IMPORTANT NOTICE:
+ *
+ * This file is part of Android's set of stable system headers
+ * exposed by the Android NDK (Native Development Kit).
+ *
+ * Third-party source AND binary code relies on the definitions
+ * here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES.
+ *
+ * - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES)
+ * - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS
+ * - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY
+ * - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
+ */
+
+/**
+ * Structures and functions for a shared memory buffer that can be shared across process.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if __ANDROID_API__ >= __ANDROID_API_O_MR1__
+
+/**
+ * Returns a dup'd FD from the given Java android.os.SharedMemory object. The returned file
+ * descriptor has all the same properties & capabilities as the FD returned from
+ * ASharedMemory_create(), however the protection flags will be the same as those of the
+ * android.os.SharedMemory object.
+ *
+ * Use close() to release the shared memory region.
+ *
+ * \param env The JNIEnv* pointer
+ * \param sharedMemory The Java android.os.SharedMemory object
+ * \return file descriptor that denotes the shared memory; -1 if the shared memory object is
+ * already closed or if the JNIEnv or jobject is NULL.
+ */
+int ASharedMemory_dupFromJava(JNIEnv* env, jobject sharedMemory);
+
+#endif
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif // ANDROID_SHARED_MEMORY_JNI_H
+
+/** @} */
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 757291c..a04869a 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -681,10 +681,10 @@
const flat_binder_object *fb = reply.readObject(false);
ASSERT_TRUE(fb != NULL);
- EXPECT_EQ(fb->type, BINDER_TYPE_HANDLE);
- EXPECT_EQ(ProcessState::self()->getStrongProxyForHandle(fb->handle), m_server);
- EXPECT_EQ(fb->cookie, (binder_uintptr_t)0);
- EXPECT_EQ(fb->binder >> 32, (binder_uintptr_t)0);
+ EXPECT_EQ(BINDER_TYPE_HANDLE, fb->type);
+ EXPECT_EQ(m_server, ProcessState::self()->getStrongProxyForHandle(fb->handle));
+ EXPECT_EQ((binder_uintptr_t)0, fb->cookie);
+ EXPECT_EQ((uint64_t)0, (uint64_t)fb->binder >> 32);
}
TEST_F(BinderLibTest, FreedBinder) {
diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp
index d9d50db..da42956 100644
--- a/libs/gui/BufferItemConsumer.cpp
+++ b/libs/gui/BufferItemConsumer.cpp
@@ -19,6 +19,8 @@
//#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include <utils/Log.h>
+#include <inttypes.h>
+
#include <gui/BufferItem.h>
#include <gui/BufferItemConsumer.h>
@@ -31,13 +33,13 @@
namespace android {
BufferItemConsumer::BufferItemConsumer(
- const sp<IGraphicBufferConsumer>& consumer, uint32_t consumerUsage,
+ const sp<IGraphicBufferConsumer>& consumer, uint64_t consumerUsage,
int bufferCount, bool controlledByApp) :
ConsumerBase(consumer, controlledByApp)
{
status_t err = mConsumer->setConsumerUsageBits(consumerUsage);
LOG_ALWAYS_FATAL_IF(err != OK,
- "Failed to set consumer usage bits to %#x", consumerUsage);
+ "Failed to set consumer usage bits to %#" PRIx64, consumerUsage);
if (bufferCount != DEFAULT_MAX_BUFFERS) {
err = mConsumer->setMaxAcquiredBufferCount(bufferCount);
LOG_ALWAYS_FATAL_IF(err != OK,
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 3424012..625dc5b 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -1102,6 +1102,7 @@
value = (mCore->mQueue.size() > 1);
break;
case NATIVE_WINDOW_CONSUMER_USAGE_BITS:
+ // deprecated; higher 32 bits are truncated
value = static_cast<int32_t>(mCore->mConsumerUsageBits);
break;
case NATIVE_WINDOW_DEFAULT_DATASPACE:
@@ -1547,4 +1548,12 @@
return NO_ERROR;
}
+status_t BufferQueueProducer::getConsumerUsage(uint64_t* outUsage) const {
+ BQ_LOGV("getConsumerUsage");
+
+ Mutex::Autolock lock(mCore->mMutex);
+ *outUsage = mCore->mConsumerUsageBits;
+ return NO_ERROR;
+}
+
} // namespace android
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 34c9d78..14d9937 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -43,7 +43,7 @@
#include <utils/String8.h>
#include <utils/Trace.h>
-EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
+extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
#define CROP_EXT_STR "EGL_ANDROID_image_crop"
#define PROT_CONTENT_EXT_STR "EGL_EXT_protected_content"
#define EGL_PROTECTED_CONTENT_EXT 0x32C0
@@ -1115,7 +1115,7 @@
return mConsumer->setDefaultBufferDataSpace(defaultDataSpace);
}
-status_t GLConsumer::setConsumerUsageBits(uint32_t usage) {
+status_t GLConsumer::setConsumerUsageBits(uint64_t usage) {
Mutex::Autolock lock(mMutex);
if (mAbandoned) {
GLC_LOGE("setConsumerUsageBits: GLConsumer is abandoned!");
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 8406a52..71e22ce 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -62,7 +62,8 @@
SET_DEQUEUE_TIMEOUT,
GET_LAST_QUEUED_BUFFER,
GET_FRAME_TIMESTAMPS,
- GET_UNIQUE_ID
+ GET_UNIQUE_ID,
+ GET_CONSUMER_USAGE,
};
class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
@@ -504,6 +505,25 @@
}
return actualResult;
}
+
+ virtual status_t getConsumerUsage(uint64_t* outUsage) const {
+ Parcel data, reply;
+ data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
+ status_t result = remote()->transact(GET_CONSUMER_USAGE, data, &reply);
+ if (result != NO_ERROR) {
+ ALOGE("getConsumerUsage failed to transact: %d", result);
+ }
+ status_t actualResult = NO_ERROR;
+ result = reply.readInt32(&actualResult);
+ if (result != NO_ERROR) {
+ return result;
+ }
+ result = reply.readUint64(outUsage);
+ if (result != NO_ERROR) {
+ return result;
+ }
+ return actualResult;
+ }
};
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -622,6 +642,10 @@
status_t getUniqueId(uint64_t* outId) const override {
return mBase->getUniqueId(outId);
}
+
+ status_t getConsumerUsage(uint64_t* outUsage) const override {
+ return mBase->getConsumerUsage(outUsage);
+ }
};
IMPLEMENT_HYBRID_META_INTERFACE(GraphicBufferProducer, HGraphicBufferProducer,
@@ -889,6 +913,20 @@
}
return NO_ERROR;
}
+ case GET_CONSUMER_USAGE: {
+ CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
+ uint64_t outUsage = 0;
+ status_t actualResult = getConsumerUsage(&outUsage);
+ status_t result = reply->writeInt32(actualResult);
+ if (result != NO_ERROR) {
+ return result;
+ }
+ result = reply->writeUint64(outUsage);
+ if (result != NO_ERROR) {
+ return result;
+ }
+ return NO_ERROR;
+ }
}
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 78eb69d..5b1c599 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -974,6 +974,9 @@
case NATIVE_WINDOW_SET_USAGE64:
res = dispatchSetUsage64(args);
break;
+ case NATIVE_WINDOW_GET_CONSUMER_USAGE64:
+ res = dispatchGetConsumerUsage64(args);
+ break;
default:
res = NAME_NOT_FOUND;
break;
@@ -1152,6 +1155,11 @@
return getHdrSupport(outSupport);
}
+int Surface::dispatchGetConsumerUsage64(va_list args) {
+ uint64_t* usage = va_arg(args, uint64_t*);
+ return getConsumerUsage(usage);
+}
+
int Surface::connect(int api) {
static sp<IProducerListener> listener = new DummyProducerListener();
return connect(api, listener);
@@ -1721,6 +1729,11 @@
return mGraphicBufferProducer->getUniqueId(outId);
}
+int Surface::getConsumerUsage(uint64_t* outUsage) const {
+ Mutex::Autolock lock(mMutex);
+ return mGraphicBufferProducer->getConsumerUsage(outUsage);
+}
+
nsecs_t Surface::getLastDequeueStartTime() const {
Mutex::Autolock lock(mMutex);
return mLastDequeueStartTime;
diff --git a/libs/gui/SyncFeatures.cpp b/libs/gui/SyncFeatures.cpp
index 187b211..afa15c5 100644
--- a/libs/gui/SyncFeatures.cpp
+++ b/libs/gui/SyncFeatures.cpp
@@ -27,7 +27,7 @@
#include <private/gui/SyncFeatures.h>
-EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
+extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
namespace android {
diff --git a/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp b/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
index 4a023a6..3b89291 100644
--- a/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
+++ b/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
@@ -21,6 +21,8 @@
#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
#include <gui/bufferqueue/1.0/B2HProducerListener.h>
+#include <system/window.h>
+
namespace android {
namespace hardware {
namespace graphics {
@@ -1232,6 +1234,18 @@
return transStatus == NO_ERROR ? fnStatus : transStatus;
}
+status_t H2BGraphicBufferProducer::getConsumerUsage(uint64_t* outUsage) const {
+ ALOGW("getConsumerUsage is not fully supported");
+ int result;
+ status_t transStatus = toStatusT(mBase->query(
+ NATIVE_WINDOW_CONSUMER_USAGE_BITS,
+ [&result, outUsage] (int32_t tResult, int32_t tValue) {
+ result = static_cast<int>(tResult);
+ *outUsage = static_cast<uint64_t>(tValue);
+ }));
+ return transStatus == NO_ERROR ? result : static_cast<int>(transStatus);
+}
+
} // namespace utils
} // namespace V1_0
} // namespace bufferqueue
diff --git a/libs/gui/include/gui/BufferItemConsumer.h b/libs/gui/include/gui/BufferItemConsumer.h
index 217fe6a..d9c5775 100644
--- a/libs/gui/include/gui/BufferItemConsumer.h
+++ b/libs/gui/include/gui/BufferItemConsumer.h
@@ -52,7 +52,7 @@
// controlledByApp tells whether this consumer is controlled by the
// application.
BufferItemConsumer(const sp<IGraphicBufferConsumer>& consumer,
- uint32_t consumerUsage, int bufferCount = DEFAULT_MAX_BUFFERS,
+ uint64_t consumerUsage, int bufferCount = DEFAULT_MAX_BUFFERS,
bool controlledByApp = false);
~BufferItemConsumer() override;
diff --git a/libs/gui/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h
index d6f215e..5c7ffb4 100644
--- a/libs/gui/include/gui/BufferQueueProducer.h
+++ b/libs/gui/include/gui/BufferQueueProducer.h
@@ -183,6 +183,9 @@
// See IGraphicBufferProducer::getUniqueId
virtual status_t getUniqueId(uint64_t* outId) const override;
+ // See IGraphicBufferProducer::getConsumerUsage
+ virtual status_t getConsumerUsage(uint64_t* outUsage) const override;
+
private:
// This is required by the IBinder::DeathRecipient interface
virtual void binderDied(const wp<IBinder>& who);
diff --git a/libs/gui/include/gui/GLConsumer.h b/libs/gui/include/gui/GLConsumer.h
index 2cf6162..75f2cca 100644
--- a/libs/gui/include/gui/GLConsumer.h
+++ b/libs/gui/include/gui/GLConsumer.h
@@ -210,7 +210,7 @@
// so the refactoring can proceed smoothly
status_t setDefaultBufferFormat(PixelFormat defaultFormat);
status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace);
- status_t setConsumerUsageBits(uint32_t usage);
+ status_t setConsumerUsageBits(uint64_t usage);
status_t setTransformHint(uint32_t hint);
status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers);
@@ -386,7 +386,7 @@
// BufferQueue instance; these will be OR:d with any additional flags passed
// from the GLConsumer user. In particular, GLConsumer will always
// consume buffers as hardware textures.
- static const uint32_t DEFAULT_USAGE_FLAGS = GraphicBuffer::USAGE_HW_TEXTURE;
+ static const uint64_t DEFAULT_USAGE_FLAGS = GraphicBuffer::USAGE_HW_TEXTURE;
// mCurrentTextureImage is the EglImage/buffer of the current texture. It's
// possible that this buffer is not associated with any buffer slot, so we
diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h
index f231f95..039dc0d 100644
--- a/libs/gui/include/gui/IGraphicBufferProducer.h
+++ b/libs/gui/include/gui/IGraphicBufferProducer.h
@@ -593,6 +593,12 @@
// Returns a unique id for this BufferQueue
virtual status_t getUniqueId(uint64_t* outId) const = 0;
+
+ // Returns the consumer usage flags for this BufferQueue. This returns the
+ // full 64-bit usage flags, rather than the truncated 32-bit usage flags
+ // returned by querying the now deprecated
+ // NATIVE_WINDOW_CONSUMER_USAGE_BITS attribute.
+ virtual status_t getConsumerUsage(uint64_t* outUsage) const = 0;
};
// ----------------------------------------------------------------------------
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 60eac0c..55dd6bf 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -159,6 +159,7 @@
status_t getHdrSupport(bool* supported);
status_t getUniqueId(uint64_t* outId) const;
+ status_t getConsumerUsage(uint64_t* outUsage) const;
// Returns the CLOCK_MONOTONIC start time of the last dequeueBuffer call
nsecs_t getLastDequeueStartTime() const;
@@ -223,6 +224,7 @@
int dispatchGetFrameTimestamps(va_list args);
int dispatchGetWideColorSupport(va_list args);
int dispatchGetHdrSupport(va_list args);
+ int dispatchGetConsumerUsage64(va_list args);
protected:
virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd);
diff --git a/libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h b/libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
index c1c3ae7..74850b4 100644
--- a/libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
+++ b/libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
@@ -94,6 +94,7 @@
sp<Fence>* outFence, float outTransformMatrix[16]) override;
void getFrameTimestamps(FrameEventHistoryDelta* outDelta) override;
status_t getUniqueId(uint64_t* outId) const override;
+ status_t getConsumerUsage(uint64_t* outUsage) const override;
};
} // namespace utils
diff --git a/libs/gui/tests/Malicious.cpp b/libs/gui/tests/Malicious.cpp
index 2b9fd5d..bb6b8a5 100644
--- a/libs/gui/tests/Malicious.cpp
+++ b/libs/gui/tests/Malicious.cpp
@@ -92,6 +92,9 @@
}
void getFrameTimestamps(FrameEventHistoryDelta*) override {}
status_t getUniqueId(uint64_t* outId) const override { return mProducer->getUniqueId(outId); }
+ status_t getConsumerUsage(uint64_t* outUsage) const override {
+ return mProducer->getConsumerUsage(outUsage);
+ }
protected:
sp<IGraphicBufferProducer> mProducer;
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index bd598e4..d5b2f00 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -28,7 +28,7 @@
#include <utils/Log.h>
#include <utils/Thread.h>
-EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
+extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
#define CROP_EXT_STR "EGL_ANDROID_image_crop"
namespace android {
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index 3df97a1..6490804 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -115,7 +115,7 @@
* The consumer gralloc usage bits currently set by the consumer.
* The values are defined in hardware/libhardware/include/gralloc.h.
*/
- NATIVE_WINDOW_CONSUMER_USAGE_BITS = 10,
+ NATIVE_WINDOW_CONSUMER_USAGE_BITS = 10, /* deprecated */
/**
* Transformation that will by applied to buffers by the hwcomposer.
@@ -224,6 +224,7 @@
NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT = 28,
NATIVE_WINDOW_GET_HDR_SUPPORT = 29,
NATIVE_WINDOW_SET_USAGE64 = 30,
+ NATIVE_WINDOW_GET_CONSUMER_USAGE64 = 31,
// clang-format on
};
@@ -900,13 +901,18 @@
static inline int native_window_get_wide_color_support(
struct ANativeWindow* window, bool* outSupport) {
- return window->perform(window, NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT,
- outSupport);
+ return window->perform(window, NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT,
+ outSupport);
}
static inline int native_window_get_hdr_support(struct ANativeWindow* window,
bool* outSupport) {
- return window->perform(window, NATIVE_WINDOW_GET_HDR_SUPPORT, outSupport);
+ return window->perform(window, NATIVE_WINDOW_GET_HDR_SUPPORT, outSupport);
+}
+
+static inline int native_window_get_consumer_usage(struct ANativeWindow* window,
+ uint64_t* outUsage) {
+ return window->perform(window, NATIVE_WINDOW_GET_CONSUMER_USAGE64, outUsage);
}
__END_DECLS
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
index bfb9a55..f9f87ff 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
@@ -417,6 +417,28 @@
on_buffer_removed_ = callback;
}
+pdx::Status<void> BufferHubQueue::FreeAllBuffers() {
+ // Clear all available buffers.
+ available_buffers_.Clear();
+
+ pdx::Status<void> last_error; // No error.
+ // Clear all buffers this producer queue is tracking.
+ for (size_t slot = 0; slot < BufferHubQueue::kMaxQueueCapacity; slot++) {
+ if (buffers_[slot] != nullptr) {
+ auto status = RemoveBuffer(slot);
+ if (!status) {
+ ALOGE(
+ "ProducerQueue::FreeAllBuffers: Failed to remove buffer at "
+ "slot=%d.",
+ slot);
+ last_error = status.error_status();
+ }
+ }
+ }
+
+ return last_error;
+}
+
ProducerQueue::ProducerQueue(LocalChannelHandle handle)
: BASE(std::move(handle)) {
auto status = ImportQueue();
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
index 6613add..53eed89 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
@@ -206,11 +206,11 @@
// It's either in free state (if the buffer has never been used before) or
// in queued state (if the buffer has been dequeued and queued back to
// BufferHubQueue).
- // TODO(jwcai) Clean this up, make mBufferState compatible with BufferHub's
- // model.
- LOG_ALWAYS_FATAL_IF((!buffers_[slot].mBufferState.isFree() &&
- !buffers_[slot].mBufferState.isQueued()),
- "dequeueBuffer: slot %zu is not free or queued.", slot);
+ LOG_ALWAYS_FATAL_IF(
+ (!buffers_[slot].mBufferState.isFree() &&
+ !buffers_[slot].mBufferState.isQueued()),
+ "dequeueBuffer: slot %zu is not free or queued, actual state: %s.", slot,
+ buffers_[slot].mBufferState.string());
buffers_[slot].mBufferState.freeQueued();
buffers_[slot].mBufferState.dequeue();
@@ -514,6 +514,7 @@
return BAD_VALUE;
}
+ FreeAllBuffers();
connected_api_ = kNoConnectedApi;
return NO_ERROR;
}
@@ -608,6 +609,14 @@
return NO_ERROR;
}
+status_t BufferHubQueueProducer::getConsumerUsage(uint64_t* out_usage) const {
+ ALOGD_IF(TRACE, __FUNCTION__);
+
+ // same value as returned by querying NATIVE_WINDOW_CONSUMER_USAGE_BITS
+ *out_usage = 0;
+ return NO_ERROR;
+}
+
status_t BufferHubQueueProducer::AllocateBuffer(uint32_t width, uint32_t height,
uint32_t layer_count,
PixelFormat format,
@@ -647,5 +656,31 @@
return NO_ERROR;
}
+status_t BufferHubQueueProducer::FreeAllBuffers() {
+ for (size_t slot = 0; slot < BufferHubQueue::kMaxQueueCapacity; slot++) {
+ // Reset in memory objects related the the buffer.
+ buffers_[slot].mGraphicBuffer = nullptr;
+ buffers_[slot].mBufferState.reset();
+ buffers_[slot].mRequestBufferCalled = false;
+ buffers_[slot].mBufferProducer = nullptr;
+ buffers_[slot].mFence = Fence::NO_FENCE;
+ }
+
+ auto status = queue_->FreeAllBuffers();
+ if (!status) {
+ ALOGE(
+ "BufferHubQueueProducer::FreeAllBuffers: Failed to free all buffers on "
+ "the queue: %s",
+ status.GetErrorMessage().c_str());
+ }
+
+ if (queue_->capacity() != 0 || queue_->count() != 0) {
+ LOG_ALWAYS_FATAL(
+ "BufferHubQueueProducer::FreeAllBuffers: Not all buffers are freed.");
+ }
+
+ return NO_ERROR;
+}
+
} // namespace dvr
} // namespace android
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
index d57c7af..3e93788 100644
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
@@ -122,6 +122,10 @@
// to deregister a buffer for epoll and internal bookkeeping.
virtual pdx::Status<void> RemoveBuffer(size_t slot);
+ // Free all buffers that belongs to this queue. Can only be called from
+ // producer side.
+ virtual pdx::Status<void> FreeAllBuffers();
+
// Dequeue a buffer from the free queue, blocking until one is available. The
// timeout argument specifies the number of milliseconds that |Dequeue()| will
// block. Specifying a timeout of -1 causes Dequeue() to block indefinitely,
@@ -297,6 +301,11 @@
// Remove producer buffer from the queue.
pdx::Status<void> RemoveBuffer(size_t slot) override;
+ // Free all buffers on this producer queue.
+ pdx::Status<void> FreeAllBuffers() override {
+ return BufferHubQueue::FreeAllBuffers();
+ }
+
// Dequeue a producer buffer to write. The returned buffer in |Gain|'ed mode,
// and caller should call Post() once it's done writing to release the buffer
// to the consumer side.
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h
index d33a831..7ed55fb 100644
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h
@@ -112,6 +112,9 @@
// See |IGraphicBufferProducer::getUniqueId|
status_t getUniqueId(uint64_t* out_id) const override;
+ // See |IGraphicBufferProducer::getConsumerUsage|
+ status_t getConsumerUsage(uint64_t* out_usage) const override;
+
private:
using LocalHandle = pdx::LocalHandle;
@@ -132,6 +135,10 @@
// Remove a buffer via BufferHubRPC.
status_t RemoveBuffer(size_t slot);
+ // Free all buffers which are owned by the prodcuer. Note that if graphic
+ // buffers are acquired by the consumer, we can't .
+ status_t FreeAllBuffers();
+
// Concreate implementation backed by BufferHubBuffer.
std::shared_ptr<ProducerQueue> queue_;
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
index e0a4052..7581a06 100644
--- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
+++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
@@ -570,6 +570,103 @@
EXPECT_EQ(consumer_queue_->is_async(), kIsAsync);
}
+TEST_F(BufferHubQueueTest, TestFreeAllBuffers) {
+ constexpr size_t kBufferCount = 2;
+
+#define CHECK_NO_BUFFER_THEN_ALLOCATE(num_buffers) \
+ EXPECT_EQ(consumer_queue_->count(), 0U); \
+ EXPECT_EQ(consumer_queue_->capacity(), 0U); \
+ EXPECT_EQ(producer_queue_->count(), 0U); \
+ EXPECT_EQ(producer_queue_->capacity(), 0U); \
+ for (size_t i = 0; i < num_buffers; i++) { \
+ AllocateBuffer(); \
+ } \
+ EXPECT_EQ(producer_queue_->count(), num_buffers); \
+ EXPECT_EQ(producer_queue_->capacity(), num_buffers);
+
+ size_t slot;
+ uint64_t seq;
+ LocalHandle fence;
+ pdx::Status<void> status;
+ pdx::Status<std::shared_ptr<BufferConsumer>> consumer_status;
+ pdx::Status<std::shared_ptr<BufferProducer>> producer_status;
+ std::shared_ptr<BufferConsumer> consumer_buffer;
+ std::shared_ptr<BufferProducer> producer_buffer;
+
+ ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<uint64_t>().Build(),
+ UsagePolicy{}));
+
+ // Free all buffers when buffers are avaible for dequeue.
+ CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
+ status = producer_queue_->FreeAllBuffers();
+ EXPECT_TRUE(status.ok());
+
+ // Free all buffers when one buffer is dequeued.
+ CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
+ producer_status = producer_queue_->Dequeue(0, &slot, &fence);
+ ASSERT_TRUE(producer_status.ok());
+ status = producer_queue_->FreeAllBuffers();
+ EXPECT_TRUE(status.ok());
+
+ // Free all buffers when all buffers are dequeued.
+ CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
+ for (size_t i = 0; i < kBufferCount; i++) {
+ producer_status = producer_queue_->Dequeue(0, &slot, &fence);
+ ASSERT_TRUE(producer_status.ok());
+ }
+ status = producer_queue_->FreeAllBuffers();
+ EXPECT_TRUE(status.ok());
+
+ // Free all buffers when one buffer is posted.
+ CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
+ producer_status = producer_queue_->Dequeue(0, &slot, &fence);
+ ASSERT_TRUE(producer_status.ok());
+ producer_buffer = producer_status.take();
+ ASSERT_NE(nullptr, producer_buffer);
+ ASSERT_EQ(0, producer_buffer->Post(fence, &seq, sizeof(seq)));
+ status = producer_queue_->FreeAllBuffers();
+ EXPECT_TRUE(status.ok());
+
+ // Free all buffers when all buffers are posted.
+ CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
+ for (size_t i = 0; i < kBufferCount; i++) {
+ producer_status = producer_queue_->Dequeue(0, &slot, &fence);
+ ASSERT_TRUE(producer_status.ok());
+ producer_buffer = producer_status.take();
+ ASSERT_NE(nullptr, producer_buffer);
+ ASSERT_EQ(0, producer_buffer->Post(fence, &seq, sizeof(seq)));
+ }
+ status = producer_queue_->FreeAllBuffers();
+ EXPECT_TRUE(status.ok());
+
+ // Free all buffers when all buffers are acquired.
+ CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
+ for (size_t i = 0; i < kBufferCount; i++) {
+ producer_status = producer_queue_->Dequeue(0, &slot, &fence);
+ ASSERT_TRUE(producer_status.ok());
+ producer_buffer = producer_status.take();
+ ASSERT_NE(nullptr, producer_buffer);
+ ASSERT_EQ(0, producer_buffer->Post(fence, &seq, sizeof(seq)));
+ consumer_status = consumer_queue_->Dequeue(0, &slot, &seq, &fence);
+ ASSERT_TRUE(consumer_status.ok());
+ }
+
+ status = producer_queue_->FreeAllBuffers();
+ EXPECT_TRUE(status.ok());
+
+ // In addition to FreeAllBuffers() from the queue, it is also required to
+ // delete all references to the ProducerBuffer (i.e. the PDX client).
+ producer_buffer = nullptr;
+
+ // Crank consumer queue events to pickup EPOLLHUP events on the queue.
+ consumer_queue_->HandleQueueEvents();
+
+ // One last check.
+ CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
+
+#undef CHECK_NO_BUFFER_THEN_ALLOCATE
+}
+
} // namespace
} // namespace dvr
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp
index 8f55125..28cd63a 100644
--- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp
+++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp
@@ -508,6 +508,44 @@
ASSERT_EQ(NO_INIT, mProducer->cancelBuffer(slot, Fence::NO_FENCE));
}
+TEST_F(BufferHubQueueProducerTest, ConnectDisconnectReconnect) {
+ int slot = -1;
+ sp<GraphicBuffer> buffer;
+ IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput();
+ IGraphicBufferProducer::QueueBufferOutput output;
+
+ EXPECT_NO_FATAL_FAILURE(ConnectProducer());
+
+ constexpr int maxDequeuedBuffers = 1;
+ int minUndequeuedBuffers;
+ EXPECT_EQ(NO_ERROR, mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+ &minUndequeuedBuffers));
+ EXPECT_EQ(NO_ERROR, mProducer->setAsyncMode(false));
+ EXPECT_EQ(NO_ERROR, mProducer->setMaxDequeuedBufferCount(maxDequeuedBuffers));
+
+ int maxCapacity = maxDequeuedBuffers + minUndequeuedBuffers;
+
+ // Dequeue, request, and queue all buffers.
+ for (int i = 0; i < maxCapacity; i++) {
+ EXPECT_NO_FATAL_FAILURE(DequeueBuffer(&slot));
+ EXPECT_EQ(NO_ERROR, mProducer->requestBuffer(slot, &buffer));
+ EXPECT_EQ(NO_ERROR, mProducer->queueBuffer(slot, input, &output));
+ }
+
+ // Disconnect then reconnect.
+ EXPECT_EQ(NO_ERROR, mProducer->disconnect(kTestApi));
+ EXPECT_NO_FATAL_FAILURE(ConnectProducer());
+
+ // Dequeue, request, and queue all buffers.
+ for (int i = 0; i < maxCapacity; i++) {
+ EXPECT_NO_FATAL_FAILURE(DequeueBuffer(&slot));
+ EXPECT_EQ(NO_ERROR, mProducer->requestBuffer(slot, &buffer));
+ EXPECT_EQ(NO_ERROR, mProducer->queueBuffer(slot, input, &output));
+ }
+
+ EXPECT_EQ(NO_ERROR, mProducer->disconnect(kTestApi));
+}
+
} // namespace
} // namespace dvr
diff --git a/libs/vr/libdvr/dvr_buffer_queue.cpp b/libs/vr/libdvr/dvr_buffer_queue.cpp
index 018abbb..e4e20f9 100644
--- a/libs/vr/libdvr/dvr_buffer_queue.cpp
+++ b/libs/vr/libdvr/dvr_buffer_queue.cpp
@@ -14,6 +14,8 @@
using android::dvr::BufferProducer;
using android::dvr::ConsumerQueue;
using android::dvr::ProducerQueue;
+using android::dvr::ProducerQueueConfigBuilder;
+using android::dvr::UsagePolicy;
extern "C" {
@@ -156,6 +158,36 @@
return 0;
}
+int dvrWriteBufferQueueCreate(uint32_t width, uint32_t height, uint32_t format,
+ uint32_t layer_count, uint64_t usage,
+ size_t capacity, size_t metadata_size,
+ DvrWriteBufferQueue** out_write_queue) {
+ if (!out_write_queue)
+ return -EINVAL;
+
+ auto config_builder = ProducerQueueConfigBuilder()
+ .SetDefaultWidth(width)
+ .SetDefaultHeight(height)
+ .SetDefaultFormat(format)
+ .SetMetadataSize(metadata_size);
+ std::unique_ptr<ProducerQueue> producer_queue =
+ ProducerQueue::Create(config_builder.Build(), UsagePolicy{});
+ if (!producer_queue) {
+ ALOGE("dvrWriteBufferQueueCreate: Failed to create producer queue.");
+ return -ENOMEM;
+ }
+
+ auto status = producer_queue->AllocateBuffers(width, height, layer_count,
+ format, usage, capacity);
+ if (!status.ok()) {
+ ALOGE("dvrWriteBufferQueueCreate: Failed to allocate buffers.");
+ return -ENOMEM;
+ }
+
+ *out_write_queue = new DvrWriteBufferQueue(std::move(producer_queue));
+ return 0;
+}
+
void dvrWriteBufferQueueDestroy(DvrWriteBufferQueue* write_queue) {
delete write_queue;
}
diff --git a/libs/vr/libdvr/include/dvr/dvr_api.h b/libs/vr/libdvr/include/dvr/dvr_api.h
index d0dbd8d..451d037 100644
--- a/libs/vr/libdvr/include/dvr/dvr_api.h
+++ b/libs/vr/libdvr/include/dvr/dvr_api.h
@@ -159,6 +159,12 @@
DvrBuffer* buffer);
// dvr_buffer_queue.h
+typedef int (*DvrWriteBufferQueueCreatePtr)(uint32_t width, uint32_t height,
+ uint32_t format,
+ uint32_t layer_count,
+ uint64_t usage, size_t capacity,
+ size_t metadata_size,
+ DvrWriteBufferQueue** queue_out);
typedef void (*DvrWriteBufferQueueDestroyPtr)(DvrWriteBufferQueue* write_queue);
typedef ssize_t (*DvrWriteBufferQueueGetCapacityPtr)(
DvrWriteBufferQueue* write_queue);
diff --git a/libs/vr/libdvr/include/dvr/dvr_api_entries.h b/libs/vr/libdvr/include/dvr/dvr_api_entries.h
index 72e0f67..da12c13 100644
--- a/libs/vr/libdvr/include/dvr/dvr_api_entries.h
+++ b/libs/vr/libdvr/include/dvr/dvr_api_entries.h
@@ -160,3 +160,6 @@
// Read buffer queue
DVR_V1_API_ENTRY(ReadBufferQueueGetEventFd);
+
+// Create write buffer queue locally
+DVR_V1_API_ENTRY(WriteBufferQueueCreate);
diff --git a/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h b/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
index e2127f8..b3b41e2 100644
--- a/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
+++ b/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
@@ -12,6 +12,36 @@
typedef struct DvrWriteBufferQueue DvrWriteBufferQueue;
typedef struct DvrReadBufferQueue DvrReadBufferQueue;
+// Creates a write buffer queue to be used locally.
+//
+// Note that this API is mostly for testing purpose. For now there is no
+// mechanism to send a DvrWriteBufferQueue cross process. Use
+// dvrSurfaceCreateWriteBufferQueue if cross-process buffer transport is
+// intended.
+//
+// @param width The width of the buffers that this queue will produce.
+// @param height The height of buffers that this queue will produce.
+// @param format The format of the buffers that this queue will produce. This
+// must be one of the AHARDWAREBUFFER_FORMAT_XXX enums.
+// @param layer_count The number of layers of the buffers that this queue will
+// produce.
+// @param usage The usage of the buffers that this queue will produce. This
+// must a combination of the AHARDWAREBUFFER_USAGE_XXX flags.
+// @param capacity The number of buffer that this queue will allocate. Note that
+// all buffers will be allocated on create. Currently, the number of buffers
+// is the queue cannot be changed after creation though DVR API. However,
+// ANativeWindow can choose to reallocate, attach, or detach buffers from
+// a DvrWriteBufferQueue through Android platform logic.
+// @param metadata_size The size of metadata in bytes.
+// @param out_write_queue The pointer of a DvrWriteBufferQueue will be filled
+// here if the method call succeeds. The metadata size must match
+// the metadata size in dvrWriteBufferPost/dvrReadBufferAcquire.
+// @return Zero on success, or negative error code.
+int dvrWriteBufferQueueCreate(uint32_t width, uint32_t height, uint32_t format,
+ uint32_t layer_count, uint64_t usage,
+ size_t capacity, size_t metadata_size,
+ DvrWriteBufferQueue** out_write_queue);
+
// Destroy a write buffer queue.
//
// @param write_queue The DvrWriteBufferQueue of interest.
diff --git a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
index f75283d..7520eee 100644
--- a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
+++ b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
@@ -1,24 +1,30 @@
+#include <android/log.h>
+#include <android/native_window.h>
+#include <android-base/unique_fd.h>
#include <dvr/dvr_api.h>
#include <dvr/dvr_buffer_queue.h>
-#include <gui/Surface.h>
-#include <private/dvr/buffer_hub_queue_client.h>
-#include <base/logging.h>
#include <gtest/gtest.h>
-#include "../dvr_internal.h"
-#include "../dvr_buffer_queue_internal.h"
+#include <array>
+#include <unordered_map>
-namespace android {
-namespace dvr {
+#ifndef ALOGD
+#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
+#endif
+
+#ifndef ALOGD_IF
+#define ALOGD_IF(cond, ...) \
+ ((__predict_false(cond)) ? ((void)ALOGD(__VA_ARGS__)) : (void)0)
+#endif
namespace {
static constexpr uint32_t kBufferWidth = 100;
static constexpr uint32_t kBufferHeight = 1;
static constexpr uint32_t kLayerCount = 1;
-static constexpr uint32_t kBufferFormat = HAL_PIXEL_FORMAT_BLOB;
-static constexpr uint64_t kBufferUsage = GRALLOC_USAGE_SW_READ_RARELY;
+static constexpr uint32_t kBufferFormat = AHARDWAREBUFFER_FORMAT_BLOB;
+static constexpr uint64_t kBufferUsage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN;
static constexpr size_t kQueueCapacity = 3;
typedef uint64_t TestMeta;
@@ -36,14 +42,6 @@
}
protected:
- void SetUp() override {
- config_builder_ = ProducerQueueConfigBuilder()
- .SetDefaultWidth(kBufferWidth)
- .SetDefaultHeight(kBufferHeight)
- .SetDefaultFormat(kBufferFormat)
- .SetMetadata<TestMeta>();
- }
-
void TearDown() override {
if (write_queue_ != nullptr) {
dvrWriteBufferQueueDestroy(write_queue_);
@@ -51,19 +49,6 @@
}
}
- void CreateWriteBufferQueue() {
- write_queue_ = new DvrWriteBufferQueue(
- ProducerQueue::Create(config_builder_.Build(), UsagePolicy{}));
- ASSERT_NE(nullptr, write_queue_);
- }
-
- void AllocateBuffers(size_t buffer_count) {
- auto status = write_queue_->producer_queue()->AllocateBuffers(
- kBufferWidth, kBufferHeight, kLayerCount, kBufferFormat, kBufferUsage,
- buffer_count);
- ASSERT_TRUE(status.ok());
- }
-
void HandleBufferAvailable() {
buffer_available_count_ += 1;
ALOGD_IF(TRACE, "Buffer avaiable, count=%d", buffer_available_count_);
@@ -75,22 +60,26 @@
buffer_removed_count_);
}
- ProducerQueueConfigBuilder config_builder_;
DvrWriteBufferQueue* write_queue_{nullptr};
int buffer_available_count_{0};
int buffer_removed_count_{0};
};
TEST_F(DvrBufferQueueTest, TestWrite_QueueCreateDestroy) {
- ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+ int ret = dvrWriteBufferQueueCreate(
+ kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+ /*capacity=*/0, sizeof(TestMeta), &write_queue_);
+ ASSERT_EQ(0, ret);
dvrWriteBufferQueueDestroy(write_queue_);
write_queue_ = nullptr;
}
TEST_F(DvrBufferQueueTest, TestWrite_QueueGetCapacity) {
- ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
- ASSERT_NO_FATAL_FAILURE(AllocateBuffers(kQueueCapacity));
+ int ret = dvrWriteBufferQueueCreate(
+ kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+ kQueueCapacity, sizeof(TestMeta), &write_queue_);
+ ASSERT_EQ(0, ret);
size_t capacity = dvrWriteBufferQueueGetCapacity(write_queue_);
@@ -99,10 +88,13 @@
}
TEST_F(DvrBufferQueueTest, TestCreateReadQueueFromWriteQueue) {
- ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+ int ret = dvrWriteBufferQueueCreate(
+ kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+ /*capacity=*/0, sizeof(TestMeta), &write_queue_);
+ ASSERT_EQ(0, ret);
DvrReadBufferQueue* read_queue = nullptr;
- int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+ ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
ASSERT_EQ(0, ret);
ASSERT_NE(nullptr, read_queue);
@@ -111,11 +103,14 @@
}
TEST_F(DvrBufferQueueTest, TestCreateReadQueueFromReadQueue) {
- ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+ int ret = dvrWriteBufferQueueCreate(
+ kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+ /*capacity=*/0, sizeof(TestMeta), &write_queue_);
+ ASSERT_EQ(0, ret);
DvrReadBufferQueue* read_queue1 = nullptr;
DvrReadBufferQueue* read_queue2 = nullptr;
- int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue1);
+ ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue1);
ASSERT_EQ(0, ret);
ASSERT_NE(nullptr, read_queue1);
@@ -130,8 +125,10 @@
}
TEST_F(DvrBufferQueueTest, CreateEmptyBuffer) {
- ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
- ASSERT_NO_FATAL_FAILURE(AllocateBuffers(3));
+ int ret = dvrWriteBufferQueueCreate(
+ kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+ kQueueCapacity, sizeof(TestMeta), &write_queue_);
+ ASSERT_EQ(0, ret);
DvrReadBuffer* read_buffer = nullptr;
DvrWriteBuffer* write_buffer = nullptr;
@@ -164,8 +161,10 @@
}
TEST_F(DvrBufferQueueTest, TestDequeuePostDequeueRelease) {
- ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
- ASSERT_NO_FATAL_FAILURE(AllocateBuffers(kQueueCapacity));
+ int ret = dvrWriteBufferQueueCreate(
+ kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+ kQueueCapacity, sizeof(TestMeta), &write_queue_);
+ ASSERT_EQ(0, ret);
static constexpr int kTimeout = 0;
DvrReadBufferQueue* read_queue = nullptr;
@@ -173,7 +172,7 @@
DvrWriteBuffer* wb = nullptr;
int fence_fd = -1;
- int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+ ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
ASSERT_EQ(0, ret);
ASSERT_NE(nullptr, read_queue);
@@ -193,7 +192,7 @@
ASSERT_TRUE(dvrWriteBufferIsValid(wb));
ALOGD_IF(TRACE, "TestDequeuePostDequeueRelease, gain buffer %p, fence_fd=%d",
wb, fence_fd);
- pdx::LocalHandle release_fence(fence_fd);
+ android::base::unique_fd release_fence(fence_fd);
// Post buffer to the read_queue.
TestMeta seq = 42U;
@@ -215,7 +214,7 @@
ALOGD_IF(TRACE,
"TestDequeuePostDequeueRelease, acquire buffer %p, fence_fd=%d", rb,
fence_fd);
- pdx::LocalHandle acquire_fence(fence_fd);
+ android::base::unique_fd acquire_fence(fence_fd);
// Release buffer to the write_queue.
ret = dvrReadBufferRelease(rb, -1);
@@ -234,40 +233,52 @@
}
TEST_F(DvrBufferQueueTest, TestGetExternalSurface) {
- ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+ int ret = dvrWriteBufferQueueCreate(
+ kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+ /*capacity=*/0, sizeof(TestMeta), &write_queue_);
+ ASSERT_EQ(0, ret);
ANativeWindow* window = nullptr;
// The |write_queue_| doesn't have proper metadata (must be
// DvrNativeBufferMetadata) configured during creation.
- int ret = dvrWriteBufferQueueGetExternalSurface(write_queue_, &window);
+ ret = dvrWriteBufferQueueGetExternalSurface(write_queue_, &window);
ASSERT_EQ(-EINVAL, ret);
ASSERT_EQ(nullptr, window);
+ dvrWriteBufferQueueDestroy(write_queue_);
+ write_queue_ = nullptr;
// A write queue with DvrNativeBufferMetadata should work fine.
- auto config = ProducerQueueConfigBuilder()
- .SetMetadata<DvrNativeBufferMetadata>()
- .Build();
- std::unique_ptr<DvrWriteBufferQueue, decltype(&dvrWriteBufferQueueDestroy)>
- write_queue(
- new DvrWriteBufferQueue(ProducerQueue::Create(config, UsagePolicy{})),
- dvrWriteBufferQueueDestroy);
- ASSERT_NE(nullptr, write_queue.get());
+ ASSERT_EQ(nullptr, write_queue_);
- ret = dvrWriteBufferQueueGetExternalSurface(write_queue.get(), &window);
+ ret = dvrWriteBufferQueueCreate(
+ kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+ /*capacity=*/0, sizeof(DvrNativeBufferMetadata), &write_queue_);
+ ASSERT_EQ(0, ret);
+ ASSERT_NE(nullptr, write_queue_);
+
+ ret = dvrWriteBufferQueueGetExternalSurface(write_queue_, &window);
ASSERT_EQ(0, ret);
ASSERT_NE(nullptr, window);
- sp<Surface> surface = static_cast<Surface*>(window);
- ASSERT_TRUE(Surface::isValid(surface));
+ // TODO(b/64723700): Remove dependencies of Android platform bits so that we
+ // can run dvr_buffer_queue-test in DTS.
+ uint32_t width = ANativeWindow_getWidth(window);
+ uint32_t height = ANativeWindow_getHeight(window);
+ uint32_t format = ANativeWindow_getFormat(window);
+ ASSERT_EQ(kBufferWidth, width);
+ ASSERT_EQ(kBufferHeight, height);
+ ASSERT_EQ(kBufferFormat, format);
}
// Create buffer queue of three buffers and dequeue three buffers out of it.
// Before each dequeue operation, we resize the buffer queue and expect the
// queue always return buffer with desired dimension.
TEST_F(DvrBufferQueueTest, TestResizeBuffer) {
- ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
- ASSERT_NO_FATAL_FAILURE(AllocateBuffers(kQueueCapacity));
+ int ret = dvrWriteBufferQueueCreate(
+ kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+ kQueueCapacity, sizeof(TestMeta), &write_queue_);
+ ASSERT_EQ(0, ret);
static constexpr int kTimeout = 0;
int fence_fd = -1;
@@ -281,7 +292,7 @@
AHardwareBuffer* ahb3 = nullptr;
AHardwareBuffer_Desc buffer_desc;
- int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+ ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
ASSERT_EQ(0, ret);
ASSERT_NE(nullptr, read_queue);
@@ -314,7 +325,7 @@
ASSERT_EQ(0, ret);
ASSERT_TRUE(dvrWriteBufferIsValid(wb1));
ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p", wb1);
- pdx::LocalHandle release_fence1(fence_fd);
+ android::base::unique_fd release_fence1(fence_fd);
// Check the buffer dimension.
ret = dvrWriteBufferGetAHardwareBuffer(wb1, &ahb1);
@@ -341,7 +352,7 @@
ASSERT_TRUE(dvrWriteBufferIsValid(wb2));
ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p, fence_fd=%d", wb2,
fence_fd);
- pdx::LocalHandle release_fence2(fence_fd);
+ android::base::unique_fd release_fence2(fence_fd);
// Check the buffer dimension, should be new width
ret = dvrWriteBufferGetAHardwareBuffer(wb2, &ahb2);
@@ -367,7 +378,7 @@
ASSERT_TRUE(dvrWriteBufferIsValid(wb3));
ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p, fence_fd=%d", wb3,
fence_fd);
- pdx::LocalHandle release_fence3(fence_fd);
+ android::base::unique_fd release_fence3(fence_fd);
// Check the buffer dimension, should be new width
ret = dvrWriteBufferGetAHardwareBuffer(wb3, &ahb3);
@@ -387,9 +398,10 @@
TEST_F(DvrBufferQueueTest, DequeueEmptyMetadata) {
// Overrides default queue parameters: Empty metadata.
- config_builder_.SetMetadata<void>();
- ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
- ASSERT_NO_FATAL_FAILURE(AllocateBuffers(1));
+ int ret = dvrWriteBufferQueueCreate(
+ kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+ /*capacity=*/1, /*metadata_size=*/0, &write_queue_);
+ ASSERT_EQ(0, ret);
DvrReadBuffer* rb = nullptr;
DvrWriteBuffer* wb = nullptr;
@@ -416,8 +428,10 @@
}
TEST_F(DvrBufferQueueTest, DequeueMismatchMetadata) {
- ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
- ASSERT_NO_FATAL_FAILURE(AllocateBuffers(1));
+ int ret = dvrWriteBufferQueueCreate(
+ kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+ /*capacity=*/1, sizeof(TestMeta), &write_queue_);
+ ASSERT_EQ(0, ret);
DvrReadBuffer* rb = nullptr;
DvrWriteBuffer* wb = nullptr;
@@ -451,11 +465,13 @@
}
TEST_F(DvrBufferQueueTest, TestReadQueueEventFd) {
- ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
- ASSERT_NO_FATAL_FAILURE(AllocateBuffers(kQueueCapacity));
+ int ret = dvrWriteBufferQueueCreate(
+ kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+ kQueueCapacity, sizeof(TestMeta), &write_queue_);
+ ASSERT_EQ(0, ret);
DvrReadBufferQueue* read_queue = nullptr;
- int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+ ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
ASSERT_EQ(0, ret);
ASSERT_NE(nullptr, read_queue);
@@ -468,8 +484,10 @@
// Dvr{Read,Write}Buffer(s) during their lifecycles. And for the same buffer_id,
// the corresponding AHardwareBuffer handle stays the same.
TEST_F(DvrBufferQueueTest, TestStableBufferIdAndHardwareBuffer) {
- ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
- ASSERT_NO_FATAL_FAILURE(AllocateBuffers(kQueueCapacity));
+ int ret = dvrWriteBufferQueueCreate(
+ kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+ kQueueCapacity, sizeof(TestMeta), &write_queue_);
+ ASSERT_EQ(0, ret);
int fence_fd = -1;
DvrReadBufferQueue* read_queue = nullptr;
@@ -621,6 +639,3 @@
}
} // namespace
-
-} // namespace dvr
-} // namespace android
diff --git a/opengl/Android.bp b/opengl/Android.bp
index aec5a95..9ca8b0b 100644
--- a/opengl/Android.bp
+++ b/opengl/Android.bp
@@ -52,6 +52,30 @@
license: "include/KHR/NOTICE",
}
+llndk_library {
+ name: "libEGL",
+ symbol_file: "libs/libEGL.map.txt",
+ export_include_dirs: ["include"],
+}
+
+llndk_library {
+ name: "libGLESv1_CM",
+ symbol_file: "libs/libGLESv1_CM.map.txt",
+ export_include_dirs: ["include"],
+}
+
+llndk_library {
+ name: "libGLESv2",
+ symbol_file: "libs/libGLESv2.map.txt",
+ export_include_dirs: ["include"],
+}
+
+llndk_library {
+ name: "libGLESv3",
+ symbol_file: "libs/libGLESv3.map.txt",
+ export_include_dirs: ["include"],
+}
+
cc_library_headers {
name: "gl_headers",
vendor_available: true,
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index 1cfc513..802b3b4 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -85,7 +85,6 @@
cc_defaults {
name: "egl_libs_defaults",
defaults: ["gl_libs_defaults"],
- vendor_available: true,
cflags: [
"-DLOG_TAG=\"libEGL\"",
],
@@ -117,9 +116,6 @@
cc_library_shared {
name: "libEGL",
defaults: ["egl_libs_defaults"],
- vndk: {
- enabled: true,
- },
srcs: [
"EGL/egl_tls.cpp",
"EGL/egl_cache.cpp",
@@ -155,7 +151,6 @@
cc_defaults {
name: "gles_libs_defaults",
defaults: ["gl_libs_defaults"],
- vendor_available: true,
arch: {
arm: {
instruction_set: "arm",
@@ -183,9 +178,6 @@
cc_library_shared {
name: "libGLESv2",
defaults: ["gles_libs_defaults"],
- vndk: {
- enabled: true,
- },
srcs: ["GLES2/gl2.cpp"],
cflags: ["-DLOG_TAG=\"libGLESv2\""],
}
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 0214b0e..94dfe6a 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -1447,7 +1447,7 @@
return setError(EGL_BAD_PARAMETER, (const char *)0);
}
-EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name)
+extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name)
{
clearError();
diff --git a/opengl/libs/libEGL.map.txt b/opengl/libs/libEGL.map.txt
index 89269a0..fa26e33 100644
--- a/opengl/libs/libEGL.map.txt
+++ b/opengl/libs/libEGL.map.txt
@@ -21,6 +21,7 @@
eglDestroyStreamKHR; # introduced=23
eglDestroySurface;
eglDestroySyncKHR; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
+ eglDupNativeFenceFDANDROID; # vndk
eglGetConfigAttrib;
eglGetConfigs;
eglGetCurrentContext;
@@ -44,6 +45,7 @@
eglQueryStreamTimeKHR; # introduced=23
eglQueryStreamu64KHR; # introduced=23
eglQueryString;
+ eglQueryStringImplementationANDROID; # vndk
eglQuerySurface;
eglReleaseTexImage;
eglReleaseThread;
diff --git a/opengl/tests/gl2_basic/gl2_basic.cpp b/opengl/tests/gl2_basic/gl2_basic.cpp
index ee88667..67c0969 100644
--- a/opengl/tests/gl2_basic/gl2_basic.cpp
+++ b/opengl/tests/gl2_basic/gl2_basic.cpp
@@ -30,7 +30,7 @@
#include <EGLUtils.h>
using namespace android;
-EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
+extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
static void printGLString(const char *name, GLenum s) {
// fprintf(stderr, "printGLString %s, %d\n", name, s);
diff --git a/opengl/tests/lib/include/EGLUtils.h b/opengl/tests/lib/include/EGLUtils.h
index 014c261..9dc6bcf 100644
--- a/opengl/tests/lib/include/EGLUtils.h
+++ b/opengl/tests/lib/include/EGLUtils.h
@@ -20,11 +20,16 @@
#include <stdint.h>
#include <stdlib.h>
+#include <vector>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
#include <system/window.h>
#include <utils/Errors.h>
-#include <EGL/egl.h>
+#include <utils/String8.h>
+extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
// ----------------------------------------------------------------------------
namespace android {
@@ -47,6 +52,17 @@
EGLint const* attrs,
EGLNativeWindowType window,
EGLConfig* outConfig);
+
+ static inline String8 printGLString(const char* name, GLenum s);
+ static inline String8 printEGLString(EGLDisplay dpy, const char* name, GLenum s);
+ static inline String8 checkEglError(const char* op, EGLBoolean returnVal);
+ static inline String8 checkGlError(const char* op);
+ static inline String8 printEGLConfiguration(EGLDisplay dpy, EGLConfig config);
+ static inline bool printEGLConfigurations(EGLDisplay dpy, String8& msg);
+ static inline bool printEGLConfigurations(FILE* output, EGLDisplay dpy);
+ static inline String8 decodeColorSpace(EGLint colorSpace);
+ static inline bool hasEglExtension(EGLDisplay dpy, const char* name);
+ static inline bool hasExtension(const char* exts, const char* name);
};
// ----------------------------------------------------------------------------
@@ -91,9 +107,8 @@
if (eglGetConfigs(dpy, NULL, 0, &numConfigs) == EGL_FALSE)
return BAD_VALUE;
- EGLConfig* const configs = (EGLConfig*)malloc(sizeof(EGLConfig)*numConfigs);
- if (eglChooseConfig(dpy, attrs, configs, numConfigs, &n) == EGL_FALSE) {
- free(configs);
+ std::vector<EGLConfig> configs(numConfigs);
+ if (eglChooseConfig(dpy, attrs, configs.data(), numConfigs, &n) == EGL_FALSE) {
return BAD_VALUE;
}
@@ -108,8 +123,6 @@
}
}
- free(configs);
-
if (i<n) {
*outConfig = config;
return NO_ERROR;
@@ -137,6 +150,159 @@
return selectConfigForPixelFormat(dpy, attrs, format, outConfig);
}
+String8 EGLUtils::printGLString(const char* name, GLenum s) {
+ String8 msg;
+ const char* v = reinterpret_cast<const char*>(glGetString(s));
+ msg.appendFormat("GL %s = %s\n", name, v);
+ return msg;
+}
+
+String8 EGLUtils::printEGLString(EGLDisplay dpy, const char* name, GLenum s) {
+ String8 msg;
+ const char* v = static_cast<const char*>(eglQueryString(dpy, s));
+ msg.appendFormat("GL %s = %s\n", name, v);
+ const char* va = (const char*)eglQueryStringImplementationANDROID(dpy, s);
+ msg.appendFormat("ImplementationANDROID: %s = %s\n", name, va);
+ return msg;
+}
+
+String8 EGLUtils::checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) {
+ String8 msg;
+ if (returnVal != EGL_TRUE) {
+ msg.appendFormat("%s() returned %d\n", op, returnVal);
+ }
+
+ for (EGLint error = eglGetError(); error != EGL_SUCCESS; error = eglGetError()) {
+ msg.appendFormat("after %s() eglError %s (0x%x)\n", op, EGLUtils::strerror(error), error);
+ }
+ return msg;
+}
+
+String8 EGLUtils::checkGlError(const char* op) {
+ String8 msg;
+ for (GLint error = glGetError(); error != GL_NO_ERROR; error = glGetError()) {
+ msg.appendFormat("after %s() glError (0x%x)\n", op, error);
+ }
+ return msg;
+}
+
+String8 EGLUtils::printEGLConfiguration(EGLDisplay dpy, EGLConfig config) {
+#define X(VAL) \
+ { VAL, #VAL }
+ struct {
+ EGLint attribute;
+ const char* name;
+ } names[] = {
+ X(EGL_BUFFER_SIZE),
+ X(EGL_ALPHA_SIZE),
+ X(EGL_BLUE_SIZE),
+ X(EGL_GREEN_SIZE),
+ X(EGL_RED_SIZE),
+ X(EGL_DEPTH_SIZE),
+ X(EGL_STENCIL_SIZE),
+ X(EGL_CONFIG_CAVEAT),
+ X(EGL_CONFIG_ID),
+ X(EGL_LEVEL),
+ X(EGL_MAX_PBUFFER_HEIGHT),
+ X(EGL_MAX_PBUFFER_PIXELS),
+ X(EGL_MAX_PBUFFER_WIDTH),
+ X(EGL_NATIVE_RENDERABLE),
+ X(EGL_NATIVE_VISUAL_ID),
+ X(EGL_NATIVE_VISUAL_TYPE),
+ X(EGL_SAMPLES),
+ X(EGL_SAMPLE_BUFFERS),
+ X(EGL_SURFACE_TYPE),
+ X(EGL_TRANSPARENT_TYPE),
+ X(EGL_TRANSPARENT_RED_VALUE),
+ X(EGL_TRANSPARENT_GREEN_VALUE),
+ X(EGL_TRANSPARENT_BLUE_VALUE),
+ X(EGL_BIND_TO_TEXTURE_RGB),
+ X(EGL_BIND_TO_TEXTURE_RGBA),
+ X(EGL_MIN_SWAP_INTERVAL),
+ X(EGL_MAX_SWAP_INTERVAL),
+ X(EGL_LUMINANCE_SIZE),
+ X(EGL_ALPHA_MASK_SIZE),
+ X(EGL_COLOR_BUFFER_TYPE),
+ X(EGL_RENDERABLE_TYPE),
+ X(EGL_CONFORMANT),
+ };
+#undef X
+
+ String8 msg;
+ for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) {
+ EGLint value = -1;
+ EGLint returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, &value);
+ EGLint error = eglGetError();
+ if (returnVal && error == EGL_SUCCESS) {
+ msg.appendFormat(" %s: %d (0x%x)", names[j].name, value, value);
+ }
+ }
+ msg.append("\n");
+ return msg;
+}
+
+bool EGLUtils::printEGLConfigurations(EGLDisplay dpy, String8& msg) {
+ EGLint numConfig = 0;
+ EGLint returnVal = eglGetConfigs(dpy, NULL, 0, &numConfig);
+ msg.append(checkEglError("eglGetConfigs", returnVal));
+ if (!returnVal) {
+ return false;
+ }
+
+ msg.appendFormat("Number of EGL configuration: %d\n", numConfig);
+
+ std::vector<EGLConfig> configs(numConfig);
+
+ returnVal = eglGetConfigs(dpy, configs.data(), numConfig, &numConfig);
+ msg.append(checkEglError("eglGetConfigs", returnVal));
+ if (!returnVal) {
+ return false;
+ }
+
+ for (int i = 0; i < numConfig; i++) {
+ msg.appendFormat("Configuration %d\n", i);
+ msg.append(printEGLConfiguration(dpy, configs[i]));
+ }
+
+ return true;
+}
+
+bool EGLUtils::printEGLConfigurations(FILE* output, EGLDisplay dpy) {
+ String8 msg;
+ bool status = printEGLConfigurations(dpy, msg);
+ fprintf(output, "%s", msg.c_str());
+ return status;
+}
+
+String8 EGLUtils::decodeColorSpace(EGLint colorSpace) {
+ switch (colorSpace) {
+ case EGL_GL_COLORSPACE_SRGB_KHR:
+ return String8("EGL_GL_COLORSPACE_SRGB_KHR");
+ case EGL_GL_COLORSPACE_DISPLAY_P3_EXT:
+ return String8("EGL_GL_COLORSPACE_DISPLAY_P3_EXT");
+ case EGL_GL_COLORSPACE_LINEAR_KHR:
+ return String8("EGL_GL_COLORSPACE_LINEAR_KHR");
+ default:
+ return String8::format("UNKNOWN ColorSpace %d", colorSpace);
+ }
+}
+
+bool EGLUtils::hasExtension(const char* exts, const char* name) {
+ size_t nameLen = strlen(name);
+ if (exts) {
+ for (const char* match = strstr(exts, name); match; match = strstr(match + nameLen, name)) {
+ if (match[nameLen] == '\0' || match[nameLen] == ' ') {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool EGLUtils::hasEglExtension(EGLDisplay dpy, const char* name) {
+ return hasExtension(eglQueryString(dpy, EGL_EXTENSIONS), name);
+}
+
// ----------------------------------------------------------------------------
}; // namespace android
// ----------------------------------------------------------------------------
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 34f1cec..1de5e48 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -627,6 +627,10 @@
return INVALID_OPERATION;
}
+status_t VirtualDisplaySurface::getConsumerUsage(uint64_t* outUsage) const {
+ return mSource[SOURCE_SINK]->getConsumerUsage(outUsage);
+}
+
void VirtualDisplaySurface::updateQueueBufferOutput(
QueueBufferOutput&& qbo) {
mQueueBufferOutput = std::move(qbo);
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index ac200ca..1671aba 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -130,6 +130,7 @@
virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
sp<Fence>* outFence, float outTransformMatrix[16]) override;
virtual status_t getUniqueId(uint64_t* outId) const override;
+ virtual status_t getConsumerUsage(uint64_t* outUsage) const override;
//
// Utility methods
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 4edde14..038ece2 100755
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -202,9 +202,11 @@
mFrameTracker.logAndResetStats(mName);
#ifdef USE_HWC2
- ALOGE_IF(!mHwcLayers.empty(),
- "Found stale hardware composer layers when destroying "
- "surface flinger layer");
+ if (!mHwcLayers.empty()) {
+ ALOGE("Found stale hardware composer layers when destroying "
+ "surface flinger layer %s", mName.string());
+ destroyAllHwcLayers();
+ }
#endif
}
@@ -293,20 +295,27 @@
}
}
-// called with SurfaceFlinger::mStateLock from the drawing thread after
-// the layer has been remove from the current state list (and just before
-// it's removed from the drawing state list)
-void Layer::onRemoved() {
+void Layer::onRemovedFromCurrentState() {
+ // the layer is removed from SF mCurrentState to mLayersPendingRemoval
+
if (mCurrentState.zOrderRelativeOf != nullptr) {
sp<Layer> strongRelative = mCurrentState.zOrderRelativeOf.promote();
if (strongRelative != nullptr) {
strongRelative->removeZOrderRelative(this);
+ mFlinger->setTransactionFlags(eTraversalNeeded);
}
mCurrentState.zOrderRelativeOf = nullptr;
}
- mSurfaceFlingerConsumer->abandon();
+ for (const auto& child : mCurrentChildren) {
+ child->onRemovedFromCurrentState();
+ }
+}
+void Layer::onRemoved() {
+ // the layer is removed from SF mLayersPendingRemoval
+
+ mSurfaceFlingerConsumer->abandon();
#ifdef USE_HWC2
destroyAllHwcLayers();
#endif
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 222718b..c34d8a0 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -419,8 +419,14 @@
bool isPotentialCursor() const { return mPotentialCursor;}
/*
- * called with the state lock when the surface is removed from the
- * current list
+ * called with the state lock from a binder thread when the layer is
+ * removed from the current list to the pending removal list
+ */
+ void onRemovedFromCurrentState();
+
+ /*
+ * called with the state lock from the main thread when the layer is
+ * removed from the pending removal list
*/
void onRemoved();
diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp
index d103820..1a5a85e 100644
--- a/services/surfaceflinger/MonitoredProducer.cpp
+++ b/services/surfaceflinger/MonitoredProducer.cpp
@@ -158,6 +158,10 @@
return mProducer->getUniqueId(outId);
}
+status_t MonitoredProducer::getConsumerUsage(uint64_t* outUsage) const {
+ return mProducer->getConsumerUsage(outUsage);
+}
+
IBinder* MonitoredProducer::onAsBinder() {
return this;
}
diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h
index ff7f0f0..1246d14 100644
--- a/services/surfaceflinger/MonitoredProducer.h
+++ b/services/surfaceflinger/MonitoredProducer.h
@@ -68,6 +68,7 @@
virtual status_t setAutoRefresh(bool autoRefresh) override;
virtual void getFrameTimestamps(FrameEventHistoryDelta *outDelta) override;
virtual status_t getUniqueId(uint64_t* outId) const override;
+ virtual status_t getConsumerUsage(uint64_t* outUsage) const override;
// The Layer which created this producer, and on which queued Buffer's will be displayed.
sp<Layer> getLayer() const;
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
index 57f468d..56e9ac0 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
@@ -26,7 +26,7 @@
#include <vector>
#include <SurfaceFlinger.h>
-EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
+extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
// ---------------------------------------------------------------------------
namespace android {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 06e2a7f..7363464 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -97,7 +97,7 @@
*/
#define DEBUG_SCREENSHOTS false
-EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
+extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
namespace android {
@@ -391,20 +391,10 @@
LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM,
ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
- sp<LambdaMessage> bootFinished = new LambdaMessage([&]() {
- mBootFinished = true;
-
+ sp<LambdaMessage> readProperties = new LambdaMessage([&]() {
readPersistentProperties();
-
-#ifdef USE_HWC2
- sp<DisplayDevice> hw(getDisplayDevice(mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY]));
- if (hw->getWideColorSupport()) {
- hw->setCompositionDataSpace(HAL_DATASPACE_V0_SRGB);
- setActiveColorModeInternal(hw, HAL_COLOR_MODE_SRGB);
- }
-#endif
});
- postMessageAsync(bootFinished);
+ postMessageAsync(readProperties);
}
void SurfaceFlinger::deleteTextureAsync(uint32_t texture) {
@@ -569,7 +559,7 @@
ALOGI( "SurfaceFlinger's main thread ready to run. "
"Initializing graphics H/W...");
- ALOGI("Phase offset NS: %" PRId64 "", vsyncPhaseOffsetNs);
+ ALOGI("Phase offest NS: %" PRId64 "", vsyncPhaseOffsetNs);
Mutex::Autolock _l(mStateLock);
@@ -1231,7 +1221,11 @@
token, fbs, producer, mRenderEngine->getEGLConfig(),
hasWideColorModes && hasWideColorDisplay);
mDisplays.add(token, hw);
- setActiveColorModeInternal(hw, HAL_COLOR_MODE_NATIVE);
+ android_color_mode defaultColorMode = HAL_COLOR_MODE_NATIVE;
+ if (hasWideColorModes && hasWideColorDisplay) {
+ defaultColorMode = HAL_COLOR_MODE_SRGB;
+ }
+ setActiveColorModeInternal(hw, defaultColorMode);
hw->setCompositionDataSpace(HAL_DATASPACE_UNKNOWN);
// Add the primary display token to mDrawingState so we don't try to
@@ -1874,12 +1868,7 @@
}
newColorMode = pickColorMode(newDataSpace);
- // We want the color mode of the boot animation to match that of the bootloader
- // To achieve this we suppress color mode changes until after the boot animation
- if (mBootFinished) {
- setActiveColorModeInternal(displayDevice, newColorMode);
- displayDevice->setCompositionDataSpace(newDataSpace);
- }
+ setActiveColorModeInternal(displayDevice, newColorMode);
}
}
@@ -2790,6 +2779,7 @@
return NO_ERROR;
}
+ layer->onRemovedFromCurrentState();
mLayersPendingRemoval.add(layer);
mLayersRemoved = true;
mNumLayers -= 1 + layer->getChildrenCount();
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index a41d35f..b28fe68 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -94,7 +94,7 @@
*/
#define DEBUG_SCREENSHOTS false
-EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
+extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
namespace android {
// ---------------------------------------------------------------------------
@@ -2382,6 +2382,7 @@
return NO_ERROR;
}
+ layer->onRemovedFromCurrentState();
mLayersPendingRemoval.add(layer);
mLayersRemoved = true;
mNumLayers -= 1 + layer->getChildrenCount();
diff --git a/services/vr/hardware_composer/impl/vr_composer_client.cpp b/services/vr/hardware_composer/impl/vr_composer_client.cpp
index c31417b..abe571a 100644
--- a/services/vr/hardware_composer/impl/vr_composer_client.cpp
+++ b/services/vr/hardware_composer/impl/vr_composer_client.cpp
@@ -161,6 +161,10 @@
client_->onHotplug(display, connected);
}
+void VrComposerClient::onRefresh(Display display) {
+ client_->onRefresh(display);
+}
+
Return<void> VrComposerClient::registerCallback(
const sp<IComposerCallback>& callback) {
return client_->registerCallback(callback);
diff --git a/services/vr/hardware_composer/impl/vr_composer_client.h b/services/vr/hardware_composer/impl/vr_composer_client.h
index f492230..dfc656a 100644
--- a/services/vr/hardware_composer/impl/vr_composer_client.h
+++ b/services/vr/hardware_composer/impl/vr_composer_client.h
@@ -35,6 +35,7 @@
virtual ~VrComposerClient();
void onHotplug(Display display, IComposerCallback::Connection connected);
+ void onRefresh(Display display);
// IComposerClient
Return<void> registerCallback(const sp<IComposerCallback>& callback) override;
diff --git a/services/vr/hardware_composer/impl/vr_hwc.cpp b/services/vr/hardware_composer/impl/vr_hwc.cpp
index 9f069cd..5e32af0 100644
--- a/services/vr/hardware_composer/impl/vr_hwc.cpp
+++ b/services/vr/hardware_composer/impl/vr_hwc.cpp
@@ -851,6 +851,14 @@
return Void();
}
+void VrHwc::ForceDisplaysRefresh() {
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (client_ != nullptr) {
+ for (const auto& pair : displays_)
+ client_.promote()->onRefresh(pair.first);
+ }
+}
+
void VrHwc::RegisterObserver(Observer* observer) {
std::lock_guard<std::mutex> guard(mutex_);
if (observer_)
diff --git a/services/vr/hardware_composer/impl/vr_hwc.h b/services/vr/hardware_composer/impl/vr_hwc.h
index 523cda3..fce9a06 100644
--- a/services/vr/hardware_composer/impl/vr_hwc.h
+++ b/services/vr/hardware_composer/impl/vr_hwc.h
@@ -103,6 +103,7 @@
virtual ~ComposerView() {}
+ virtual void ForceDisplaysRefresh() = 0;
virtual void RegisterObserver(Observer* observer) = 0;
virtual void UnregisterObserver(Observer* observer) = 0;
};
@@ -288,6 +289,7 @@
Return<void> createClient(createClient_cb hidl_cb) override;
// ComposerView:
+ void ForceDisplaysRefresh() override;
void RegisterObserver(Observer* observer) override;
void UnregisterObserver(Observer* observer) override;
@@ -295,7 +297,6 @@
HwcDisplay* FindDisplay(Display display);
wp<VrComposerClient> client_;
- sp<IComposerCallback> callbacks_;
// Guard access to internal state from binder threads.
std::mutex mutex_;
diff --git a/services/vr/hardware_composer/tests/vr_composer_test.cpp b/services/vr/hardware_composer/tests/vr_composer_test.cpp
index d082f4b..2e70928 100644
--- a/services/vr/hardware_composer/tests/vr_composer_test.cpp
+++ b/services/vr/hardware_composer/tests/vr_composer_test.cpp
@@ -10,6 +10,24 @@
const char kVrDisplayName[] = "VrDisplay_Test";
+class TestComposerView : public ComposerView {
+ public:
+ TestComposerView() {}
+ ~TestComposerView() override = default;
+
+ size_t display_refresh_count() const { return display_refresh_count_; }
+
+ void ForceDisplaysRefresh() override { display_refresh_count_++; }
+ void RegisterObserver(Observer* observer) override {}
+ void UnregisterObserver(Observer* observer) override {}
+
+ TestComposerView(const TestComposerView&) = delete;
+ void operator=(const TestComposerView&) = delete;
+
+ private:
+ size_t display_refresh_count_ = 0;
+};
+
class TestComposerCallback : public BnVrComposerCallback {
public:
TestComposerCallback() {}
@@ -57,7 +75,7 @@
class VrComposerTest : public testing::Test {
public:
- VrComposerTest() : composer_(new VrComposer()) {}
+ VrComposerTest() : composer_(new VrComposer(&composer_view_)) {}
~VrComposerTest() override = default;
sp<IVrComposer> GetComposerProxy() const {
@@ -72,6 +90,7 @@
}
protected:
+ TestComposerView composer_view_;
sp<VrComposer> composer_;
VrComposerTest(const VrComposerTest&) = delete;
@@ -89,7 +108,9 @@
TEST_F(VrComposerTest, TestWithObserver) {
sp<IVrComposer> composer = GetComposerProxy();
sp<TestComposerCallback> callback = new TestComposerCallback();
+ ASSERT_EQ(0, composer_view_.display_refresh_count());
ASSERT_TRUE(composer->registerObserver(callback).isOk());
+ ASSERT_EQ(1, composer_view_.display_refresh_count());
ComposerView::Frame frame;
base::unique_fd fence = composer_->OnNewFrame(frame);
diff --git a/services/vr/hardware_composer/vr_composer.cpp b/services/vr/hardware_composer/vr_composer.cpp
index 36a313a..d93f370 100644
--- a/services/vr/hardware_composer/vr_composer.cpp
+++ b/services/vr/hardware_composer/vr_composer.cpp
@@ -21,24 +21,36 @@
} // namespace
-VrComposer::VrComposer() {}
+VrComposer::VrComposer(ComposerView* composer_view)
+ : composer_view_(composer_view) {
+ composer_view_->RegisterObserver(this);
+}
-VrComposer::~VrComposer() {}
+VrComposer::~VrComposer() {
+ composer_view_->UnregisterObserver(this);
+}
binder::Status VrComposer::registerObserver(
const sp<IVrComposerCallback>& callback) {
- std::lock_guard<std::mutex> guard(mutex_);
+ {
+ std::lock_guard<std::mutex> guard(mutex_);
- if (!CheckPermission())
- return binder::Status::fromStatusT(PERMISSION_DENIED);
+ if (!CheckPermission())
+ return binder::Status::fromStatusT(PERMISSION_DENIED);
- if (callback_.get()) {
- ALOGE("Failed to register callback, already registered");
- return binder::Status::fromStatusT(ALREADY_EXISTS);
+ if (callback_.get()) {
+ ALOGE("Failed to register callback, already registered");
+ return binder::Status::fromStatusT(ALREADY_EXISTS);
+ }
+
+ callback_ = callback;
+ IInterface::asBinder(callback_)->linkToDeath(this);
}
- callback_ = callback;
- IInterface::asBinder(callback_)->linkToDeath(this);
+ // Don't take the lock to force display refresh otherwise it could end in a
+ // deadlock since HWC calls this with new frames and it has a lock of its own
+ // to serialize access to the display information.
+ composer_view_->ForceDisplaysRefresh();
return binder::Status::ok();
}
diff --git a/services/vr/hardware_composer/vr_composer.h b/services/vr/hardware_composer/vr_composer.h
index 7b580c6..1273352 100644
--- a/services/vr/hardware_composer/vr_composer.h
+++ b/services/vr/hardware_composer/vr_composer.h
@@ -20,7 +20,7 @@
public ComposerView::Observer,
public IBinder::DeathRecipient {
public:
- VrComposer();
+ explicit VrComposer(ComposerView* composer_view);
~VrComposer() override;
// BnVrComposer:
@@ -40,6 +40,8 @@
sp<IVrComposerCallback> callback_;
+ ComposerView* composer_view_; // Not owned.
+
VrComposer(const VrComposer&) = delete;
void operator=(const VrComposer&) = delete;
};
diff --git a/services/vr/hardware_composer/vr_hardware_composer_service.cpp b/services/vr/hardware_composer/vr_hardware_composer_service.cpp
index e36b0ae..7701847 100644
--- a/services/vr/hardware_composer/vr_hardware_composer_service.cpp
+++ b/services/vr/hardware_composer/vr_hardware_composer_service.cpp
@@ -36,8 +36,7 @@
"Failed to register service");
android::sp<android::dvr::VrComposer> composer =
- new android::dvr::VrComposer();
- service->RegisterObserver(composer.get());
+ new android::dvr::VrComposer(service.get());
android::sp<android::IServiceManager> sm(android::defaultServiceManager());
@@ -52,7 +51,5 @@
android::hardware::ProcessState::self()->startThreadPool();
android::hardware::IPCThreadState::self()->joinThreadPool();
- service->UnregisterObserver(composer.get());
-
return 0;
}
diff --git a/services/vr/performanced/performance_service.cpp b/services/vr/performanced/performance_service.cpp
index 4b9fbe0..4c26671 100644
--- a/services/vr/performanced/performance_service.cpp
+++ b/services/vr/performanced/performance_service.cpp
@@ -22,13 +22,15 @@
using android::pdx::ErrorStatus;
using android::pdx::Message;
using android::pdx::Status;
-using android::pdx::rpc::DispatchRemoteMethod;
using android::pdx::default_transport::Endpoint;
+using android::pdx::rpc::DispatchRemoteMethod;
namespace {
const char kCpuSetBasePath[] = "/dev/cpuset";
+const char kRootCpuSet[] = "/";
+
constexpr unsigned long kTimerSlackForegroundNs = 50000;
constexpr unsigned long kTimerSlackBackgroundNs = 40000000;
@@ -123,22 +125,22 @@
// hack for now to put some form of permission logic in place while a longer
// term solution is developed.
using AllowRootSystem =
- CheckAnd<SameProcess, CheckOr<UserId<AID_ROOT, AID_SYSTEM>,
- GroupId<AID_SYSTEM>>>;
+ CheckAnd<SameProcess,
+ CheckOr<UserId<AID_ROOT, AID_SYSTEM>, GroupId<AID_SYSTEM>>>;
using AllowRootSystemGraphics =
CheckAnd<SameProcess, CheckOr<UserId<AID_ROOT, AID_SYSTEM, AID_GRAPHICS>,
GroupId<AID_SYSTEM, AID_GRAPHICS>>>;
using AllowRootSystemAudio =
CheckAnd<SameProcess, CheckOr<UserId<AID_ROOT, AID_SYSTEM, AID_AUDIO>,
GroupId<AID_SYSTEM, AID_AUDIO>>>;
- using AllowRootSystemTrusted = CheckOr<Trusted, UserId<AID_ROOT, AID_SYSTEM>,
- GroupId<AID_SYSTEM>>;
+ using AllowRootSystemTrusted =
+ CheckOr<Trusted, UserId<AID_ROOT, AID_SYSTEM>, GroupId<AID_SYSTEM>>;
partition_permission_check_ = AllowRootSystemTrusted::Check;
// Setup the scheduler classes.
// TODO(eieio): Replace this with a device-specific config file.
- scheduler_classes_ = {
+ scheduler_policies_ = {
{"audio:low",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
@@ -183,12 +185,14 @@
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
.priority = fifo_medium + 2,
- .permission_check = AllowRootSystemTrusted::Check}},
+ .permission_check = AllowRootSystemTrusted::Check,
+ "/system/performance"}},
{"vr:app:render",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
.priority = fifo_medium + 1,
- .permission_check = AllowRootSystemTrusted::Check}},
+ .permission_check = AllowRootSystemTrusted::Check,
+ "/application/performance"}},
{"normal",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_NORMAL,
@@ -219,14 +223,80 @@
Status<void> PerformanceService::OnSetSchedulerPolicy(
Message& message, pid_t task_id, const std::string& scheduler_policy) {
- // Forward to scheduler class handler for now. In the future this method will
- // subsume the others by unifying both scheduler class and cpu partiton into a
- // single policy concept.
ALOGI(
"PerformanceService::OnSetSchedulerPolicy: task_id=%d "
"scheduler_policy=%s",
task_id, scheduler_policy.c_str());
- return OnSetSchedulerClass(message, task_id, scheduler_policy);
+
+ Task task(task_id);
+ if (!task) {
+ ALOGE(
+ "PerformanceService::OnSetSchedulerPolicy: Unable to access /proc/%d "
+ "to gather task information.",
+ task_id);
+ return ErrorStatus(EINVAL);
+ }
+
+ auto search = scheduler_policies_.find(scheduler_policy);
+ if (search != scheduler_policies_.end()) {
+ auto config = search->second;
+
+ // Make sure the sending process is allowed to make the requested change to
+ // this task.
+ if (!config.IsAllowed(message, task))
+ return ErrorStatus(EINVAL);
+
+ // Get the thread group's cpu set. Policies that do not specify a cpuset
+ // should default to this cpuset.
+ std::string thread_group_cpuset;
+ Task thread_group{task.thread_group_id()};
+ if (thread_group) {
+ thread_group_cpuset = thread_group.GetCpuSetPath();
+ } else {
+ ALOGE(
+ "PerformanceService::OnSetSchedulerPolicy: Failed to get thread "
+ "group tgid=%d for task_id=%d",
+ task.thread_group_id(), task_id);
+ thread_group_cpuset = kRootCpuSet;
+ }
+
+ std::string target_cpuset;
+ if (config.cpuset.empty()) {
+ target_cpuset = thread_group_cpuset;
+ } else {
+ target_cpuset = config.cpuset;
+ }
+ ALOGI("PerformanceService::OnSetSchedulerPolicy: Using cpuset=%s",
+ target_cpuset.c_str());
+
+ auto target_set = cpuset_.Lookup(target_cpuset);
+ if (target_set) {
+ auto attach_status = target_set->AttachTask(task_id);
+ ALOGW_IF(!attach_status,
+ "PerformanceService::OnSetSchedulerPolicy: Failed to attach "
+ "task=%d to cpuset=%s: %s",
+ task_id, target_cpuset.c_str(),
+ attach_status.GetErrorMessage().c_str());
+ } else {
+ ALOGW(
+ "PerformanceService::OnSetSchedulerPolicy: Failed to lookup "
+ "cpuset=%s",
+ target_cpuset.c_str());
+ }
+
+ struct sched_param param;
+ param.sched_priority = config.priority;
+
+ sched_setscheduler(task_id, config.scheduler_policy, ¶m);
+ prctl(PR_SET_TIMERSLACK_PID, config.timer_slack, task_id);
+ return {};
+ } else {
+ ALOGE(
+ "PerformanceService::OnSetSchedulerPolicy: Invalid scheduler_policy=%s "
+ "requested by task=%d.",
+ scheduler_policy.c_str(), task_id);
+ return ErrorStatus(EINVAL);
+ }
}
Status<void> PerformanceService::OnSetCpuPartition(
@@ -259,8 +329,8 @@
if (!task)
return ErrorStatus(EINVAL);
- auto search = scheduler_classes_.find(scheduler_class);
- if (search != scheduler_classes_.end()) {
+ auto search = scheduler_policies_.find(scheduler_class);
+ if (search != scheduler_policies_.end()) {
auto config = search->second;
// Make sure the sending process is allowed to make the requested change to
diff --git a/services/vr/performanced/performance_service.h b/services/vr/performanced/performance_service.h
index b28d94a..6b519ab 100644
--- a/services/vr/performanced/performance_service.h
+++ b/services/vr/performanced/performance_service.h
@@ -44,13 +44,13 @@
int sched_fifo_min_priority_;
int sched_fifo_max_priority_;
- // Scheduler class config type.
- struct SchedulerClassConfig {
+ struct SchedulerPolicyConfig {
unsigned long timer_slack;
int scheduler_policy;
int priority;
std::function<bool(const pdx::Message& message, const Task& task)>
permission_check;
+ std::string cpuset;
// Check the permisison of the given task to use this scheduler class. If a
// permission check function is not set then operations are only allowed on
@@ -65,7 +65,7 @@
}
};
- std::unordered_map<std::string, SchedulerClassConfig> scheduler_classes_;
+ std::unordered_map<std::string, SchedulerPolicyConfig> scheduler_policies_;
std::function<bool(const pdx::Message& message, const Task& task)>
partition_permission_check_;
diff --git a/services/vr/performanced/performance_service_tests.cpp b/services/vr/performanced/performance_service_tests.cpp
index 274a1b3..4065785 100644
--- a/services/vr/performanced/performance_service_tests.cpp
+++ b/services/vr/performanced/performance_service_tests.cpp
@@ -1,24 +1,65 @@
#include <errno.h>
#include <sched.h>
+#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <condition_variable>
#include <cstdlib>
+#include <iostream>
#include <mutex>
+#include <sstream>
#include <thread>
+#include <utility>
+#include <android-base/unique_fd.h>
#include <dvr/performance_client_api.h>
#include <gtest/gtest.h>
#include <private/android_filesystem_config.h>
+#include "stdio_filebuf.h"
+#include "string_trim.h"
+#include "unique_file.h"
+
+using android::dvr::Trim;
+using android::dvr::UniqueFile;
+using android::dvr::stdio_filebuf;
+
namespace {
const char kTrustedUidEnvironmentVariable[] = "GTEST_TRUSTED_UID";
+const char kProcBase[] = "/proc";
+
+std::pair<UniqueFile, int> OpenTaskFile(pid_t task_id,
+ const std::string& name) {
+ std::ostringstream stream;
+ stream << kProcBase << "/" << task_id << "/" << name;
+
+ UniqueFile file{fopen(stream.str().c_str(), "r")};
+ const int error = file ? 0 : errno;
+ return {std::move(file), error};
+}
+
+std::string GetTaskCpuSet(pid_t task_id) {
+ int error;
+ UniqueFile file;
+
+ std::tie(file, error) = OpenTaskFile(task_id, "cpuset");
+ if (!file)
+ return std::string("errno:") + strerror(error);
+
+ stdio_filebuf<char> filebuf(file.get());
+ std::istream file_stream(&filebuf);
+
+ std::string line;
+ std::getline(file_stream, line);
+ return Trim(line);
+}
+
} // anonymous namespace
-TEST(DISABLED_PerformanceTest, SetCpuPartition) {
+TEST(PerformanceTest, SetCpuPartition) {
int error;
// Test setting the the partition for the current task.
@@ -59,13 +100,6 @@
}
thread.join();
- // Test setting the partition for a task that isn't valid using
- // the task id of the thread that we just joined. Technically the
- // id could wrap around by the time we get here, but this is
- // extremely unlikely.
- error = dvrSetCpuPartition(task_id, "/application");
- EXPECT_EQ(-EINVAL, error);
-
// Test setting the partition for a task that doesn't belong to us.
error = dvrSetCpuPartition(1, "/application");
EXPECT_EQ(-EINVAL, error);
@@ -73,6 +107,10 @@
// Test setting the partition to one that doesn't exist.
error = dvrSetCpuPartition(0, "/foobar");
EXPECT_EQ(-ENOENT, error);
+
+ // Set the test back to the root partition.
+ error = dvrSetCpuPartition(0, "/");
+ EXPECT_EQ(0, error);
}
TEST(PerformanceTest, SetSchedulerClass) {
@@ -96,8 +134,6 @@
EXPECT_EQ(-EINVAL, error);
}
-// This API mirrors SetSchedulerClass for now. Replace with with a more specific
-// test once the policy API is fully implemented.
TEST(PerformanceTest, SetSchedulerPolicy) {
int error;
@@ -115,6 +151,50 @@
error = dvrSetSchedulerPolicy(0, "foobar");
EXPECT_EQ(-EINVAL, error);
+
+ // Set the test back to the root partition.
+ error = dvrSetCpuPartition(0, "/");
+ EXPECT_EQ(0, error);
+
+ const std::string original_cpuset = GetTaskCpuSet(gettid());
+ EXPECT_EQ("/", original_cpuset);
+
+ error = dvrSetSchedulerPolicy(0, "vr:system:arp");
+ EXPECT_EQ(0, error);
+ EXPECT_EQ(SCHED_FIFO | SCHED_RESET_ON_FORK, sched_getscheduler(0));
+
+ const std::string new_cpuset = GetTaskCpuSet(gettid());
+ EXPECT_NE(original_cpuset, new_cpuset);
+
+ // The cpuset for the thread group is now new_cpuset. Scheduler profiles that
+ // do not specify a cpuset should not change the cpuset of a thread, except to
+ // restore it to the thread group cpuset.
+ std::string thread_original_cpuset;
+ std::string thread_new_cpuset;
+ std::string thread_final_cpuset;
+
+ std::thread thread{
+ [&thread_original_cpuset, &thread_new_cpuset, &thread_final_cpuset]() {
+ thread_original_cpuset = GetTaskCpuSet(gettid());
+
+ int error = dvrSetSchedulerPolicy(0, "vr:app:render");
+ EXPECT_EQ(0, error);
+
+ thread_new_cpuset = GetTaskCpuSet(gettid());
+
+ error = dvrSetSchedulerPolicy(0, "normal");
+ EXPECT_EQ(0, error);
+
+ thread_final_cpuset = GetTaskCpuSet(gettid());
+ }};
+ thread.join();
+
+ EXPECT_EQ(new_cpuset, thread_original_cpuset);
+ EXPECT_NE(new_cpuset, thread_new_cpuset);
+ EXPECT_EQ(new_cpuset, thread_final_cpuset);
+
+ error = dvrSetCpuPartition(0, original_cpuset.c_str());
+ EXPECT_EQ(0, error);
}
TEST(PerformanceTest, SchedulerClassResetOnFork) {
@@ -424,11 +504,11 @@
error = dvrSetSchedulerPolicy(0, "audio:high");
EXPECT_EQ(-EINVAL, error);
error = dvrSetSchedulerPolicy(0, "graphics");
- EXPECT_EQ(0, error);
+ EXPECT_EQ(-EINVAL, error);
error = dvrSetSchedulerPolicy(0, "graphics:low");
- EXPECT_EQ(0, error);
+ EXPECT_EQ(-EINVAL, error);
error = dvrSetSchedulerPolicy(0, "graphics:high");
- EXPECT_EQ(0, error);
+ EXPECT_EQ(-EINVAL, error);
error = dvrSetSchedulerPolicy(0, "sensors");
EXPECT_EQ(-EINVAL, error);
error = dvrSetSchedulerPolicy(0, "sensors:low");
diff --git a/services/vr/performanced/task.cpp b/services/vr/performanced/task.cpp
index 1175a7b..c2f078e 100644
--- a/services/vr/performanced/task.cpp
+++ b/services/vr/performanced/task.cpp
@@ -48,15 +48,18 @@
thread_count_(0),
cpus_allowed_mask_(0) {
task_fd_ = OpenTaskDirectory(task_id_);
- ALOGE_IF(task_fd_.get() < 0,
+ const int error = errno;
+ ALOGE_IF(task_fd_.get() < 0 && error != EACCES,
"Task::Task: Failed to open task directory for task_id=%d: %s",
- task_id, strerror(errno));
+ task_id, strerror(error));
- ReadStatusFields();
-
- ALOGD_IF(TRACE, "Task::Task: task_id=%d name=%s tgid=%d ppid=%d cpu_mask=%x",
- task_id_, name_.c_str(), thread_group_id_, parent_process_id_,
- cpus_allowed_mask_);
+ if (IsValid()) {
+ ReadStatusFields();
+ ALOGD_IF(TRACE,
+ "Task::Task: task_id=%d name=%s tgid=%d ppid=%d cpu_mask=%x",
+ task_id_, name_.c_str(), thread_group_id_, parent_process_id_,
+ cpus_allowed_mask_);
+ }
}
base::unique_fd Task::OpenTaskFile(const std::string& name) const {
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 069fb36..a346c0a 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -430,6 +430,8 @@
return HAL_DATASPACE_DISPLAY_P3;
case VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT:
return HAL_DATASPACE_V0_SCRGB_LINEAR;
+ case VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT:
+ return HAL_DATASPACE_V0_SCRGB;
case VK_COLOR_SPACE_DCI_P3_LINEAR_EXT:
return HAL_DATASPACE_DCI_P3_LINEAR;
case VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT: