Merge "media/omx: fix VP9 level enums" into oc-mr1-dev
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 0b8479a..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;
}
@@ -655,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 f4bb4ab..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
@@ -135,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/opengl/tests/lib/include/EGLUtils.h b/opengl/tests/lib/include/EGLUtils.h
index 014c261..29f4fe4 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>
+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
// ----------------------------------------------------------------------------