// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "ui/gfx/gpu_fence.h" #include "base/logging.h" #include "base/notreached.h" #include "base/time/time.h" #if defined(OS_LINUX) || defined(OS_ANDROID) #include #endif namespace gfx { GpuFence::GpuFence(const GpuFenceHandle& handle) : type_(handle.type) { switch (type_) { case GpuFenceHandleType::kEmpty: break; case GpuFenceHandleType::kAndroidNativeFenceSync: #if defined(OS_POSIX) owned_fd_.reset(handle.native_fd.fd); #else NOTREACHED(); #endif break; } } GpuFence::~GpuFence() = default; GpuFenceHandle GpuFence::GetGpuFenceHandle() const { gfx::GpuFenceHandle handle; switch (type_) { case GpuFenceHandleType::kEmpty: break; case GpuFenceHandleType::kAndroidNativeFenceSync: #if defined(OS_POSIX) handle.type = gfx::GpuFenceHandleType::kAndroidNativeFenceSync; handle.native_fd = base::FileDescriptor(owned_fd_.get(), /*auto_close=*/false); #else NOTREACHED(); #endif break; } return handle; } ClientGpuFence GpuFence::AsClientGpuFence() { return reinterpret_cast(this); } // static GpuFence* GpuFence::FromClientGpuFence(ClientGpuFence gpu_fence) { return reinterpret_cast(gpu_fence); } void GpuFence::Wait() { switch (type_) { case GpuFenceHandleType::kEmpty: break; case GpuFenceHandleType::kAndroidNativeFenceSync: #if defined(OS_LINUX) || defined(OS_ANDROID) static const int kInfiniteSyncWaitTimeout = -1; DCHECK_GE(owned_fd_.get(), 0); if (sync_wait(owned_fd_.get(), kInfiniteSyncWaitTimeout) < 0) { LOG(FATAL) << "Failed while waiting for gpu fence fd"; } #else NOTREACHED(); #endif break; } } // static GpuFence::FenceStatus GpuFence::GetStatusChangeTime(int fd, base::TimeTicks* time) { DCHECK_NE(fd, -1); #if defined(OS_LINUX) || defined(OS_ANDROID) auto info = std::unique_ptr{ sync_fence_info(fd), sync_fence_info_free}; if (!info) { LOG(ERROR) << "sync_fence_info returned null for fd : " << fd; return FenceStatus::kInvalid; } // Not signalled yet. if (info->status != 1) { return FenceStatus::kNotSignaled; } uint64_t timestamp_ns = 0u; struct sync_pt_info* pt_info = nullptr; while ((pt_info = sync_pt_info(info.get(), pt_info))) timestamp_ns = std::max(timestamp_ns, pt_info->timestamp_ns); if (timestamp_ns == 0u) { LOG(ERROR) << "No timestamp provided from sync_pt_info for fd : " << fd; return FenceStatus::kInvalid; } *time = base::TimeTicks() + base::TimeDelta::FromNanoseconds(timestamp_ns); return FenceStatus::kSignaled; #endif NOTREACHED(); return FenceStatus::kInvalid; } base::TimeTicks GpuFence::GetMaxTimestamp() const { base::TimeTicks timestamp; #if defined(OS_LINUX) || defined(OS_ANDROID) FenceStatus status = GetStatusChangeTime(owned_fd_.get(), ×tamp); DCHECK_EQ(status, FenceStatus::kSignaled); return timestamp; #endif NOTREACHED(); return timestamp; } } // namespace gfx