Revert "Remove NativeWindow and unused DVR functions"

This reverts commit a001af5ae07e156f9c31dcdb24fb7ddead4d9f1e.

Change-Id: Ieb60bc8e8e7caefee30b0fbd13cda15298c32075
diff --git a/libs/vr/libdisplay/Android.mk b/libs/vr/libdisplay/Android.mk
index 05e1bab..6a9458c 100644
--- a/libs/vr/libdisplay/Android.mk
+++ b/libs/vr/libdisplay/Android.mk
@@ -15,6 +15,7 @@
 LOCAL_PATH := $(call my-dir)
 
 sourceFiles := \
+	native_window.cpp \
 	native_buffer_queue.cpp \
 	display_client.cpp \
 	display_manager_client.cpp \
diff --git a/libs/vr/libdisplay/graphics.cpp b/libs/vr/libdisplay/graphics.cpp
index 61f6fea..d0557a9 100644
--- a/libs/vr/libdisplay/graphics.cpp
+++ b/libs/vr/libdisplay/graphics.cpp
@@ -483,6 +483,25 @@
   return 0;
 }
 
+extern "C" int dvrGetDisplaySurfaceInfo(EGLNativeWindowType win, int* width,
+                                        int* height, int* format) {
+  ANativeWindow* nwin = reinterpret_cast<ANativeWindow*>(win);
+  int w, h, f;
+
+  nwin->query(nwin, NATIVE_WINDOW_DEFAULT_WIDTH, &w);
+  nwin->query(nwin, NATIVE_WINDOW_DEFAULT_HEIGHT, &h);
+  nwin->query(nwin, NATIVE_WINDOW_FORMAT, &f);
+
+  if (width)
+    *width = w;
+  if (height)
+    *height = h;
+  if (format)
+    *format = f;
+
+  return 0;
+}
+
 struct DvrGraphicsContext : public android::ANativeObjectBase<
                                 ANativeWindow, DvrGraphicsContext,
                                 android::LightRefBase<DvrGraphicsContext>> {
diff --git a/libs/vr/libdisplay/include/dvr/graphics.h b/libs/vr/libdisplay/include/dvr/graphics.h
index 19deec3..50d2754 100644
--- a/libs/vr/libdisplay/include/dvr/graphics.h
+++ b/libs/vr/libdisplay/include/dvr/graphics.h
@@ -21,6 +21,11 @@
 
 __BEGIN_DECLS
 
+// Create a stereo surface that will be lens-warped by the system.
+EGLNativeWindowType dvrCreateWarpedDisplaySurface(int* display_width,
+                                                  int* display_height);
+EGLNativeWindowType dvrCreateDisplaySurface(void);
+
 // Display surface parameters used to specify display surface options.
 enum {
   DVR_SURFACE_PARAMETER_NONE = 0,
@@ -158,16 +163,9 @@
   float right_fov[4];
 };
 
-int dvrGetNativeDisplayDimensions(int* native_width, int* native_height);
-
-// Opaque struct that represents a graphics context, the texture swap chain,
-// and surfaces.
-typedef struct DvrGraphicsContext DvrGraphicsContext;
-
-// Create the graphics context. with the given parameters. The list of
-// parameters is terminated with an entry where key ==
-// DVR_SURFACE_PARAMETER_NONE. For example, the parameters array could be built
-// as follows:
+// Creates a display surface with the given parameters. The list of parameters
+// is terminated with an entry where key == DVR_SURFACE_PARAMETER_NONE.
+// For example, the parameters array could be built as follows:
 //   int display_width = 0, display_height = 0;
 //   int surface_width = 0, surface_height = 0;
 //   float inter_lens_meters = 0.0f;
@@ -185,6 +183,38 @@
 //       DVR_SURFACE_PARAMETER_OUT(RIGHT_FOV_LRBT, right_fov),
 //       DVR_SURFACE_PARAMETER_LIST_END,
 //   };
+EGLNativeWindowType dvrCreateDisplaySurfaceExtended(
+    struct DvrSurfaceParameter* parameters);
+
+int dvrGetNativeDisplayDimensions(int* native_width, int* native_height);
+
+int dvrGetDisplaySurfaceInfo(EGLNativeWindowType win, int* width, int* height,
+                             int* format);
+
+// NOTE: Only call the functions below on windows created with the API above.
+
+// Sets the display surface visible based on the boolean evaluation of
+// |visible|.
+void dvrDisplaySurfaceSetVisible(EGLNativeWindowType window, int visible);
+
+// Sets the application z-order of the display surface. Higher values display on
+// top of lower values.
+void dvrDisplaySurfaceSetZOrder(EGLNativeWindowType window, int z_order);
+
+// Post the next buffer early. This allows the application to race with either
+// the async EDS process or the scanline for applications that are not using
+// system distortion. When this is called, the next buffer in the queue is
+// posted for display. It is up to the application to kick its GPU rendering
+// work in time. If the rendering is incomplete there will be significant,
+// undesirable tearing artifacts.
+// It is not recommended to use this feature with system distortion.
+void dvrDisplayPostEarly(EGLNativeWindowType window);
+
+// Opaque struct that represents a graphics context, the texture swap chain,
+// and surfaces.
+typedef struct DvrGraphicsContext DvrGraphicsContext;
+
+// Create the graphics context.
 int dvrGraphicsContextCreate(struct DvrSurfaceParameter* parameters,
                              DvrGraphicsContext** return_graphics_context);
 
diff --git a/libs/vr/libdisplay/native_window.cpp b/libs/vr/libdisplay/native_window.cpp
new file mode 100644
index 0000000..24ecd8a
--- /dev/null
+++ b/libs/vr/libdisplay/native_window.cpp
@@ -0,0 +1,458 @@
+#include <EGL/egl.h>
+
+#include <android/native_window.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 <log/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.
+    LOG_FATAL_IF(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.
+    LOG_FATAL_IF(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();
+}
diff --git a/libs/vr/libdisplay/native_window_test.cpp b/libs/vr/libdisplay/native_window_test.cpp
new file mode 100644
index 0000000..2f3bc33
--- /dev/null
+++ b/libs/vr/libdisplay/native_window_test.cpp
@@ -0,0 +1,43 @@
+#include <iostream>
+#include <memory>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <dvr/graphics.h>
+#include <private/dvr/display_client.h>
+
+#include <cpp_free_mock/cpp_free_mock.h>
+
+// Checks querying the VSync of the device on display surface creation.
+TEST(CreateDisplaySurface, QueryVSyncPeriod) {
+  using ::testing::_;
+
+  const uint64_t kExpectedVSync = 123456;
+
+  // We only care about the expected VSync value
+  android::dvr::DisplayMetrics metrics;
+  metrics.vsync_period_ns = kExpectedVSync;
+
+  uint64_t outPeriod;
+
+  DvrSurfaceParameter display_params[] = {
+      DVR_SURFACE_PARAMETER_IN(WIDTH, 256),
+      DVR_SURFACE_PARAMETER_IN(HEIGHT, 256),
+      DVR_SURFACE_PARAMETER_OUT(VSYNC_PERIOD, &outPeriod),
+      DVR_SURFACE_PARAMETER_LIST_END,
+  };
+
+  // inject the mocking code to the target method
+  auto mocked_function =
+      MOCKER(&android::dvr::DisplayClient::GetDisplayMetrics);
+
+  // instrument the mock function to return our custom metrics
+  EXPECT_CALL(*mocked_function, MOCK_FUNCTION(_, _))
+      .WillOnce(::testing::DoAll(::testing::SetArgPointee<1>(metrics),
+                                 ::testing::Return(0)));
+
+  ASSERT_NE(nullptr, dvrCreateDisplaySurfaceExtended(display_params));
+
+  EXPECT_EQ(kExpectedVSync, outPeriod);
+}
diff --git a/libs/vr/libdisplay/tests/graphics_app_tests.cpp b/libs/vr/libdisplay/tests/graphics_app_tests.cpp
index f51dd8a..7ea3952 100644
--- a/libs/vr/libdisplay/tests/graphics_app_tests.cpp
+++ b/libs/vr/libdisplay/tests/graphics_app_tests.cpp
@@ -1,6 +1,55 @@
 #include <dvr/graphics.h>
 #include <gtest/gtest.h>
 
+TEST(GraphicsAppTests, CreateWarpedDisplaySurfaceParams) {
+  int width = 0, height = 0;
+  EGLNativeWindowType window = dvrCreateWarpedDisplaySurface(&width, &height);
+  EXPECT_GT(width, 0);
+  EXPECT_GT(height, 0);
+  EXPECT_NE(window, nullptr);
+}
+
+TEST(GraphicsAppTests, CreateDisplaySurface) {
+  EGLNativeWindowType window = dvrCreateDisplaySurface();
+  EXPECT_NE(window, nullptr);
+}
+
+TEST(GraphicsAppTests, CreateDisplaySurfaceExtended) {
+  int display_width = 0, display_height = 0;
+  int surface_width = 0, surface_height = 0;
+  float inter_lens_meters = 0.0f;
+  float left_fov[4] = {0.0f};
+  float right_fov[4] = {0.0f};
+  int disable_warp = 0;
+  DvrSurfaceParameter surface_params[] = {
+      DVR_SURFACE_PARAMETER_IN(DISABLE_DISTORTION, disable_warp),
+      DVR_SURFACE_PARAMETER_OUT(DISPLAY_WIDTH, &display_width),
+      DVR_SURFACE_PARAMETER_OUT(DISPLAY_HEIGHT, &display_height),
+      DVR_SURFACE_PARAMETER_OUT(SURFACE_WIDTH, &surface_width),
+      DVR_SURFACE_PARAMETER_OUT(SURFACE_HEIGHT, &surface_height),
+      DVR_SURFACE_PARAMETER_OUT(INTER_LENS_METERS, &inter_lens_meters),
+      DVR_SURFACE_PARAMETER_OUT(LEFT_FOV_LRBT, left_fov),
+      DVR_SURFACE_PARAMETER_OUT(RIGHT_FOV_LRBT, right_fov),
+      DVR_SURFACE_PARAMETER_LIST_END,
+  };
+
+  EGLNativeWindowType window = dvrCreateDisplaySurfaceExtended(surface_params);
+  EXPECT_NE(window, nullptr);
+  EXPECT_GT(display_width, 0);
+  EXPECT_GT(display_height, 0);
+  EXPECT_GT(surface_width, 0);
+  EXPECT_GT(surface_height, 0);
+  EXPECT_GT(inter_lens_meters, 0);
+  EXPECT_GT(left_fov[0], 0);
+  EXPECT_GT(left_fov[1], 0);
+  EXPECT_GT(left_fov[2], 0);
+  EXPECT_GT(left_fov[3], 0);
+  EXPECT_GT(right_fov[0], 0);
+  EXPECT_GT(right_fov[1], 0);
+  EXPECT_GT(right_fov[2], 0);
+  EXPECT_GT(right_fov[3], 0);
+}
+
 TEST(GraphicsAppTests, GetNativeDisplayDimensions) {
   int width, height;
   dvrGetNativeDisplayDimensions(&width, &height);
@@ -8,6 +57,17 @@
   EXPECT_GT(height, 0);
 }
 
+TEST(GraphicsAppTests, GetDisplaySurfaceInfo) {
+  int ret, width, height, format;
+  EGLNativeWindowType window = dvrCreateDisplaySurface();
+  ASSERT_NE(window, nullptr);
+  ret = dvrGetDisplaySurfaceInfo(window, &width, &height, &format);
+  ASSERT_EQ(0, ret);
+  ASSERT_GT(width, 0);
+  ASSERT_GT(height, 0);
+  ASSERT_NE(0, format);
+}
+
 // TODO(jpoichet) How to check it worked?
 TEST(GraphicsAppTests, GraphicsSurfaceSetVisible) {
   DvrSurfaceParameter surface_params[] = {DVR_SURFACE_PARAMETER_LIST_END};