1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "ui/gl/gl_fence_android_native_fence_sync.h"
6 
7 #include <sync/sync.h>
8 
9 #include "base/files/scoped_file.h"
10 #include "base/logging.h"
11 #include "base/memory/ptr_util.h"
12 #include "base/time/time.h"
13 #include "ui/gfx/gpu_fence_handle.h"
14 #include "ui/gl/gl_surface_egl.h"
15 
16 #if defined(OS_POSIX) || defined(OS_FUCHSIA)
17 #include <unistd.h>
18 
19 #include "base/posix/eintr_wrapper.h"
20 #endif
21 
22 namespace gl {
23 
GLFenceAndroidNativeFenceSync()24 GLFenceAndroidNativeFenceSync::GLFenceAndroidNativeFenceSync() {}
25 
~GLFenceAndroidNativeFenceSync()26 GLFenceAndroidNativeFenceSync::~GLFenceAndroidNativeFenceSync() {}
27 
28 // static
29 std::unique_ptr<GLFenceAndroidNativeFenceSync>
CreateInternal(EGLenum type,EGLint * attribs)30 GLFenceAndroidNativeFenceSync::CreateInternal(EGLenum type, EGLint* attribs) {
31   DCHECK(GLSurfaceEGL::IsAndroidNativeFenceSyncSupported());
32 
33   // Can't use MakeUnique, the no-args constructor is private.
34   auto fence = base::WrapUnique(new GLFenceAndroidNativeFenceSync());
35 
36   if (!fence->InitializeInternal(type, attribs))
37     return nullptr;
38   return fence;
39 }
40 
41 // static
42 std::unique_ptr<GLFenceAndroidNativeFenceSync>
CreateForGpuFence()43 GLFenceAndroidNativeFenceSync::CreateForGpuFence() {
44   return CreateInternal(EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
45 }
46 
47 // static
48 std::unique_ptr<GLFenceAndroidNativeFenceSync>
CreateFromGpuFence(const gfx::GpuFence & gpu_fence)49 GLFenceAndroidNativeFenceSync::CreateFromGpuFence(
50     const gfx::GpuFence& gpu_fence) {
51   gfx::GpuFenceHandle handle =
52       gfx::CloneHandleForIPC(gpu_fence.GetGpuFenceHandle());
53   DCHECK_GE(handle.native_fd.fd, 0);
54   EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, handle.native_fd.fd,
55                       EGL_NONE};
56   return CreateInternal(EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
57 }
58 
GetGpuFence()59 std::unique_ptr<gfx::GpuFence> GLFenceAndroidNativeFenceSync::GetGpuFence() {
60   DCHECK(GLSurfaceEGL::IsAndroidNativeFenceSyncSupported());
61 
62   EGLint sync_fd = eglDupNativeFenceFDANDROID(display_, sync_);
63   if (sync_fd < 0)
64     return nullptr;
65 
66   gfx::GpuFenceHandle handle;
67   handle.type = gfx::GpuFenceHandleType::kAndroidNativeFenceSync;
68   handle.native_fd = base::FileDescriptor(sync_fd, /*auto_close=*/true);
69 
70   return std::make_unique<gfx::GpuFence>(handle);
71 }
72 
GetStatusChangeTime()73 base::TimeTicks GLFenceAndroidNativeFenceSync::GetStatusChangeTime() {
74   EGLint sync_fd = eglDupNativeFenceFDANDROID(display_, sync_);
75   if (sync_fd < 0)
76     return base::TimeTicks();
77 
78   base::ScopedFD scoped_fd(sync_fd);
79   base::TimeTicks time;
80   GetStatusChangeTimeForFence(sync_fd, &time);
81   return time;
82 }
83 
84 // static
85 GLFenceAndroidNativeFenceSync::Status
GetStatusChangeTimeForFence(int fd,base::TimeTicks * time)86 GLFenceAndroidNativeFenceSync::GetStatusChangeTimeForFence(
87     int fd,
88     base::TimeTicks* time) {
89   DCHECK_NE(fd, -1);
90 
91   auto info =
92       std::unique_ptr<sync_fence_info_data, void (*)(sync_fence_info_data*)>{
93           sync_fence_info(fd), sync_fence_info_free};
94   if (!info) {
95     LOG(ERROR) << "sync_fence_info returned null for fd : " << fd;
96     return Status::kInvalid;
97   }
98 
99   const bool signaled = info->status == 1;
100   if (!signaled)
101     return Status::kNotSignaled;
102 
103   struct sync_pt_info* pt_info = nullptr;
104   uint64_t timestamp_ns = 0u;
105   while ((pt_info = sync_pt_info(info.get(), pt_info)))
106     timestamp_ns = std::max(timestamp_ns, pt_info->timestamp_ns);
107 
108   if (timestamp_ns == 0u) {
109     LOG(ERROR) << "No timestamp provided from sync_pt_info for fd : " << fd;
110     return Status::kInvalid;
111   }
112 
113   *time = base::TimeTicks() + base::TimeDelta::FromNanoseconds(timestamp_ns);
114   return Status::kSignaled;
115 }
116 
117 }  // namespace gl
118