Add DaydreamVR native libraries and services
Upstreaming the main VR system components from master-dreamos-dev
into goog/master.
Bug: None
Test: `m -j32` succeeds. Sailfish boots and basic_vr sample app works
Change-Id: I853015872afc443aecee10411ef2d6b79184d051
diff --git a/libs/vr/libdisplay/native_window.cpp b/libs/vr/libdisplay/native_window.cpp
new file mode 100644
index 0000000..63c81ed
--- /dev/null
+++ b/libs/vr/libdisplay/native_window.cpp
@@ -0,0 +1,459 @@
+#include <EGL/egl.h>
+
+#include <android/native_window.h>
+#include <base/logging.h>
+#include <cutils/native_handle.h>
+#include <errno.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdarg.h>
+#include <string.h>
+#include <sys/timerfd.h>
+#include <system/window.h>
+#include <time.h>
+#include <ui/ANativeObjectBase.h>
+#include <utils/Errors.h>
+
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include <utils/Trace.h>
+
+#include <cutils/log.h>
+
+#include <memory>
+#include <mutex>
+
+#include <dvr/graphics.h>
+#include <private/dvr/clock_ns.h>
+#include <private/dvr/display_client.h>
+#include <private/dvr/native_buffer.h>
+#include <private/dvr/native_buffer_queue.h>
+
+namespace {
+
+constexpr int kDefaultDisplaySurfaceUsage =
+ GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
+constexpr int kDefaultDisplaySurfaceFormat = HAL_PIXEL_FORMAT_RGBA_8888;
+constexpr int kWarpedDisplaySurfaceFlags = 0;
+constexpr int kUnwarpedDisplaySurfaceFlags =
+ DVR_DISPLAY_SURFACE_FLAGS_DISABLE_SYSTEM_EDS |
+ DVR_DISPLAY_SURFACE_FLAGS_DISABLE_SYSTEM_DISTORTION |
+ DVR_DISPLAY_SURFACE_FLAGS_DISABLE_SYSTEM_CAC;
+constexpr int kDefaultBufferCount = 4;
+
+} // anonymous namespace
+
+namespace android {
+namespace dvr {
+
+// NativeWindow is an implementation of ANativeWindow. This class interacts with
+// displayd through the DisplaySurfaceClient and NativeBufferQueue.
+class NativeWindow : public ANativeObjectBase<ANativeWindow, NativeWindow,
+ LightRefBase<NativeWindow> > {
+ public:
+ explicit NativeWindow(const std::shared_ptr<DisplaySurfaceClient>& surface);
+
+ void SetVisible(bool visible);
+ void SetZOrder(int z_order);
+ void PostEarly();
+
+ private:
+ friend class LightRefBase<NativeWindow>;
+
+ void Post(sp<NativeBufferProducer> buffer, int fence_fd);
+
+ static int SetSwapInterval(ANativeWindow* window, int interval);
+ static int DequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer,
+ int* fence_fd);
+ static int QueueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer,
+ int fence_fd);
+ static int CancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer,
+ int fence_fd);
+ static int Query(const ANativeWindow* window, int what, int* value);
+ static int Perform(ANativeWindow* window, int operation, ...);
+
+ static int DequeueBuffer_DEPRECATED(ANativeWindow* window,
+ ANativeWindowBuffer** buffer);
+ static int CancelBuffer_DEPRECATED(ANativeWindow* window,
+ ANativeWindowBuffer* buffer);
+ static int QueueBuffer_DEPRECATED(ANativeWindow* window,
+ ANativeWindowBuffer* buffer);
+ static int LockBuffer_DEPRECATED(ANativeWindow* window,
+ ANativeWindowBuffer* buffer);
+
+ std::shared_ptr<DisplaySurfaceClient> surface_;
+
+ std::mutex lock_;
+ NativeBufferQueue buffer_queue_;
+ sp<NativeBufferProducer> next_post_buffer_;
+ bool next_buffer_already_posted_;
+
+ NativeWindow(const NativeWindow&) = delete;
+ void operator=(NativeWindow&) = delete;
+};
+
+NativeWindow::NativeWindow(const std::shared_ptr<DisplaySurfaceClient>& surface)
+ : surface_(surface),
+ buffer_queue_(surface, kDefaultBufferCount),
+ next_post_buffer_(nullptr),
+ next_buffer_already_posted_(false) {
+ ANativeWindow::setSwapInterval = SetSwapInterval;
+ ANativeWindow::dequeueBuffer = DequeueBuffer;
+ ANativeWindow::cancelBuffer = CancelBuffer;
+ ANativeWindow::queueBuffer = QueueBuffer;
+ ANativeWindow::query = Query;
+ ANativeWindow::perform = Perform;
+
+ ANativeWindow::dequeueBuffer_DEPRECATED = DequeueBuffer_DEPRECATED;
+ ANativeWindow::cancelBuffer_DEPRECATED = CancelBuffer_DEPRECATED;
+ ANativeWindow::lockBuffer_DEPRECATED = LockBuffer_DEPRECATED;
+ ANativeWindow::queueBuffer_DEPRECATED = QueueBuffer_DEPRECATED;
+}
+
+void NativeWindow::SetVisible(bool visible) { surface_->SetVisible(visible); }
+
+void NativeWindow::SetZOrder(int z_order) { surface_->SetZOrder(z_order); }
+
+void NativeWindow::PostEarly() {
+ ATRACE_NAME("NativeWindow::PostEarly");
+ ALOGI_IF(TRACE, "NativeWindow::PostEarly");
+
+ std::lock_guard<std::mutex> autolock(lock_);
+
+ if (!next_buffer_already_posted_) {
+ next_buffer_already_posted_ = true;
+
+ if (!next_post_buffer_.get()) {
+ next_post_buffer_ = buffer_queue_.Dequeue();
+ }
+ ATRACE_ASYNC_BEGIN("BufferPost", next_post_buffer_->buffer()->id());
+ Post(next_post_buffer_, -1);
+ }
+}
+
+void NativeWindow::Post(sp<NativeBufferProducer> buffer, int fence_fd) {
+ ATRACE_NAME(__PRETTY_FUNCTION__);
+ ALOGI_IF(TRACE, "NativeWindow::Post: buffer_id=%d, fence_fd=%d",
+ buffer->buffer()->id(), fence_fd);
+ ALOGW_IF(!surface_->visible(),
+ "NativeWindow::Post: Posting buffer on invisible surface!!!");
+ buffer->Post(fence_fd, 0);
+}
+
+int NativeWindow::SetSwapInterval(ANativeWindow* window, int interval) {
+ ALOGI_IF(TRACE, "SetSwapInterval: window=%p interval=%d", window, interval);
+ return 0;
+}
+
+int NativeWindow::DequeueBuffer(ANativeWindow* window,
+ ANativeWindowBuffer** buffer, int* fence_fd) {
+ ATRACE_NAME(__PRETTY_FUNCTION__);
+
+ NativeWindow* self = getSelf(window);
+ std::lock_guard<std::mutex> autolock(self->lock_);
+
+ if (!self->next_post_buffer_.get()) {
+ self->next_post_buffer_ = self->buffer_queue_.Dequeue();
+ }
+ ATRACE_ASYNC_BEGIN("BufferDraw", self->next_post_buffer_->buffer()->id());
+ *fence_fd = self->next_post_buffer_->ClaimReleaseFence().Release();
+ *buffer = self->next_post_buffer_.get();
+
+ ALOGI_IF(TRACE, "NativeWindow::DequeueBuffer: fence_fd=%d", *fence_fd);
+ return 0;
+}
+
+int NativeWindow::QueueBuffer(ANativeWindow* window,
+ ANativeWindowBuffer* buffer, int fence_fd) {
+ ATRACE_NAME("NativeWindow::QueueBuffer");
+ ALOGI_IF(TRACE, "NativeWindow::QueueBuffer: fence_fd=%d", fence_fd);
+
+ NativeWindow* self = getSelf(window);
+ std::lock_guard<std::mutex> autolock(self->lock_);
+
+ NativeBufferProducer* native_buffer =
+ static_cast<NativeBufferProducer*>(buffer);
+ ATRACE_ASYNC_END("BufferDraw", native_buffer->buffer()->id());
+ bool do_post = true;
+ if (self->next_buffer_already_posted_) {
+ // Check that the buffer is the one we expect, but handle it if this happens
+ // in production by allowing this buffer to post on top of the previous one.
+ DCHECK(native_buffer == self->next_post_buffer_.get());
+ if (native_buffer == self->next_post_buffer_.get()) {
+ do_post = false;
+ if (fence_fd >= 0)
+ close(fence_fd);
+ }
+ }
+ if (do_post) {
+ ATRACE_ASYNC_BEGIN("BufferPost", native_buffer->buffer()->id());
+ self->Post(native_buffer, fence_fd);
+ }
+ self->next_buffer_already_posted_ = false;
+ self->next_post_buffer_ = nullptr;
+
+ return NO_ERROR;
+}
+
+int NativeWindow::CancelBuffer(ANativeWindow* window,
+ ANativeWindowBuffer* buffer, int fence_fd) {
+ ATRACE_NAME("NativeWindow::CancelBuffer");
+ ALOGI_IF(TRACE, "NativeWindow::CancelBuffer: fence_fd: %d", fence_fd);
+
+ NativeWindow* self = getSelf(window);
+ std::lock_guard<std::mutex> autolock(self->lock_);
+
+ NativeBufferProducer* native_buffer =
+ static_cast<NativeBufferProducer*>(buffer);
+ ATRACE_ASYNC_END("BufferDraw", native_buffer->buffer()->id());
+ ATRACE_INT("CancelBuffer", native_buffer->buffer()->id());
+ bool do_enqueue = true;
+ if (self->next_buffer_already_posted_) {
+ // Check that the buffer is the one we expect, but handle it if this happens
+ // in production by returning this buffer to the buffer queue.
+ DCHECK(native_buffer == self->next_post_buffer_.get());
+ if (native_buffer == self->next_post_buffer_.get()) {
+ do_enqueue = false;
+ }
+ }
+ if (do_enqueue) {
+ self->buffer_queue_.Enqueue(native_buffer);
+ }
+ if (fence_fd >= 0)
+ close(fence_fd);
+ self->next_buffer_already_posted_ = false;
+ self->next_post_buffer_ = nullptr;
+
+ return NO_ERROR;
+}
+
+int NativeWindow::Query(const ANativeWindow* window, int what, int* value) {
+ NativeWindow* self = getSelf(const_cast<ANativeWindow*>(window));
+ std::lock_guard<std::mutex> autolock(self->lock_);
+
+ switch (what) {
+ case NATIVE_WINDOW_WIDTH:
+ *value = self->surface_->width();
+ return NO_ERROR;
+ case NATIVE_WINDOW_HEIGHT:
+ *value = self->surface_->height();
+ return NO_ERROR;
+ case NATIVE_WINDOW_FORMAT:
+ *value = self->surface_->format();
+ return NO_ERROR;
+ case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
+ *value = 1;
+ return NO_ERROR;
+ case NATIVE_WINDOW_CONCRETE_TYPE:
+ *value = NATIVE_WINDOW_SURFACE;
+ return NO_ERROR;
+ case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
+ *value = 1;
+ return NO_ERROR;
+ case NATIVE_WINDOW_DEFAULT_WIDTH:
+ *value = self->surface_->width();
+ return NO_ERROR;
+ case NATIVE_WINDOW_DEFAULT_HEIGHT:
+ *value = self->surface_->height();
+ return NO_ERROR;
+ case NATIVE_WINDOW_TRANSFORM_HINT:
+ *value = 0;
+ return NO_ERROR;
+ }
+
+ *value = 0;
+ return BAD_VALUE;
+}
+
+int NativeWindow::Perform(ANativeWindow* window, int operation, ...) {
+ NativeWindow* self = getSelf(window);
+ std::lock_guard<std::mutex> autolock(self->lock_);
+
+ va_list args;
+ va_start(args, operation);
+
+ // TODO(eieio): The following operations are not used at this time. They are
+ // included here to help document which operations may be useful and what
+ // parameters they take.
+ switch (operation) {
+ case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS: {
+ int w = va_arg(args, int);
+ int h = va_arg(args, int);
+ ALOGD_IF(TRACE, "NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS: w=%d h=%d", w, h);
+ return NO_ERROR;
+ }
+
+ case NATIVE_WINDOW_SET_BUFFERS_FORMAT: {
+ int format = va_arg(args, int);
+ ALOGD_IF(TRACE, "NATIVE_WINDOW_SET_BUFFERS_FORMAT: format=%d", format);
+ return NO_ERROR;
+ }
+
+ case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM: {
+ int transform = va_arg(args, int);
+ ALOGD_IF(TRACE, "NATIVE_WINDOW_SET_BUFFERS_TRANSFORM: transform=%d",
+ transform);
+ return NO_ERROR;
+ }
+
+ case NATIVE_WINDOW_SET_USAGE: {
+ int usage = va_arg(args, int);
+ ALOGD_IF(TRACE, "NATIVE_WINDOW_SET_USAGE: usage=%d", usage);
+ return NO_ERROR;
+ }
+
+ case NATIVE_WINDOW_CONNECT:
+ case NATIVE_WINDOW_DISCONNECT:
+ case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
+ case NATIVE_WINDOW_API_CONNECT:
+ case NATIVE_WINDOW_API_DISCONNECT:
+ // TODO(eieio): we should implement these
+ return NO_ERROR;
+
+ case NATIVE_WINDOW_SET_BUFFER_COUNT: {
+ int buffer_count = va_arg(args, int);
+ ALOGD_IF(TRACE, "NATIVE_WINDOW_SET_BUFFER_COUNT: bufferCount=%d",
+ buffer_count);
+ return NO_ERROR;
+ }
+ case NATIVE_WINDOW_SET_BUFFERS_DATASPACE: {
+ android_dataspace_t data_space =
+ static_cast<android_dataspace_t>(va_arg(args, int));
+ ALOGD_IF(TRACE, "NATIVE_WINDOW_SET_BUFFERS_DATASPACE: dataSpace=%d",
+ data_space);
+ return NO_ERROR;
+ }
+ case NATIVE_WINDOW_SET_SCALING_MODE: {
+ int mode = va_arg(args, int);
+ ALOGD_IF(TRACE, "NATIVE_WINDOW_SET_SCALING_MODE: mode=%d", mode);
+ return NO_ERROR;
+ }
+
+ case NATIVE_WINDOW_LOCK:
+ case NATIVE_WINDOW_UNLOCK_AND_POST:
+ case NATIVE_WINDOW_SET_CROP:
+ case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
+ return INVALID_OPERATION;
+ }
+
+ return NAME_NOT_FOUND;
+}
+
+int NativeWindow::DequeueBuffer_DEPRECATED(ANativeWindow* window,
+ ANativeWindowBuffer** buffer) {
+ int fence_fd = -1;
+ int ret = DequeueBuffer(window, buffer, &fence_fd);
+
+ // wait for fence
+ if (ret == NO_ERROR && fence_fd != -1)
+ close(fence_fd);
+
+ return ret;
+}
+
+int NativeWindow::CancelBuffer_DEPRECATED(ANativeWindow* window,
+ ANativeWindowBuffer* buffer) {
+ return CancelBuffer(window, buffer, -1);
+}
+
+int NativeWindow::QueueBuffer_DEPRECATED(ANativeWindow* window,
+ ANativeWindowBuffer* buffer) {
+ return QueueBuffer(window, buffer, -1);
+}
+
+int NativeWindow::LockBuffer_DEPRECATED(ANativeWindow* /*window*/,
+ ANativeWindowBuffer* /*buffer*/) {
+ return NO_ERROR;
+}
+
+} // namespace dvr
+} // namespace android
+
+static EGLNativeWindowType CreateDisplaySurface(int* display_width,
+ int* display_height, int format,
+ int usage, int flags) {
+ auto client = android::dvr::DisplayClient::Create();
+ if (!client) {
+ ALOGE("Failed to create display client!");
+ return nullptr;
+ }
+
+ // TODO(eieio,jbates): Consider passing flags and other parameters to get
+ // metrics based on specific surface requirements.
+ android::dvr::SystemDisplayMetrics metrics;
+ const int ret = client->GetDisplayMetrics(&metrics);
+ if (ret < 0) {
+ ALOGE("Failed to get display metrics: %s", strerror(-ret));
+ return nullptr;
+ }
+
+ int width, height;
+
+ if (flags & DVR_DISPLAY_SURFACE_FLAGS_DISABLE_SYSTEM_DISTORTION) {
+ width = metrics.display_native_width;
+ height = metrics.display_native_height;
+ } else {
+ width = metrics.distorted_width;
+ height = metrics.distorted_height;
+ }
+
+ std::shared_ptr<android::dvr::DisplaySurfaceClient> surface =
+ client->CreateDisplaySurface(width, height, format, usage, flags);
+
+ if (display_width)
+ *display_width = metrics.display_native_width;
+ if (display_height)
+ *display_height = metrics.display_native_height;
+
+ // Set the surface visible by default.
+ // TODO(eieio,jbates): Remove this from here and set visible somewhere closer
+ // to the application to account for situations where the application wants to
+ // create surfaces that will be used later or shouldn't be visible yet.
+ surface->SetVisible(true);
+
+ return new android::dvr::NativeWindow(surface);
+}
+
+std::shared_ptr<android::dvr::DisplaySurfaceClient> CreateDisplaySurfaceClient(
+ struct DvrSurfaceParameter* parameters,
+ /*out*/ android::dvr::SystemDisplayMetrics* metrics);
+
+extern "C" EGLNativeWindowType dvrCreateDisplaySurfaceExtended(
+ struct DvrSurfaceParameter* parameters) {
+ android::dvr::SystemDisplayMetrics metrics;
+ auto surface = CreateDisplaySurfaceClient(parameters, &metrics);
+ if (!surface) {
+ ALOGE("Failed to create display surface client");
+ return nullptr;
+ }
+ return new android::dvr::NativeWindow(surface);
+}
+
+extern "C" EGLNativeWindowType dvrCreateDisplaySurface() {
+ return CreateDisplaySurface(NULL, NULL, kDefaultDisplaySurfaceFormat,
+ kDefaultDisplaySurfaceUsage,
+ kUnwarpedDisplaySurfaceFlags);
+}
+
+extern "C" EGLNativeWindowType dvrCreateWarpedDisplaySurface(
+ int* display_width, int* display_height) {
+ return CreateDisplaySurface(
+ display_width, display_height, kDefaultDisplaySurfaceFormat,
+ kDefaultDisplaySurfaceUsage, kWarpedDisplaySurfaceFlags);
+}
+
+extern "C" void dvrDisplaySurfaceSetVisible(EGLNativeWindowType window,
+ int visible) {
+ auto native_window = reinterpret_cast<android::dvr::NativeWindow*>(window);
+ native_window->SetVisible(visible);
+}
+
+extern "C" void dvrDisplaySurfaceSetZOrder(EGLNativeWindowType window,
+ int z_order) {
+ auto native_window = reinterpret_cast<android::dvr::NativeWindow*>(window);
+ native_window->SetZOrder(z_order);
+}
+
+extern "C" void dvrDisplayPostEarly(EGLNativeWindowType window) {
+ auto native_window = reinterpret_cast<android::dvr::NativeWindow*>(window);
+ native_window->PostEarly();
+}