[go: nahoru, domu]

blob: 391341cd81f162dcbad55ed3021ceb6cbba06b54 [file] [log] [blame]
// Copyright 2017 The Chromium Authors
// 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_handle.h"
#include <atomic>
#include <cstddef>
#include "base/debug/alias.h"
#include "base/feature_list.h"
#include "base/files/scoped_file.h"
#include "base/logging.h"
#include "base/memory/scoped_refptr.h"
#include "base/notreached.h"
#include "build/build_config.h"
#include "ui/gfx/switches.h"
#if BUILDFLAG(IS_POSIX)
#include <unistd.h>
#include "base/posix/eintr_wrapper.h"
#endif
#if BUILDFLAG(IS_FUCHSIA)
#include "base/fuchsia/fuchsia_logging.h"
#endif
#if BUILDFLAG(IS_WIN)
#include <windows.h>
#include "base/process/process_handle.h"
#endif
namespace {
std::atomic<uint32_t> g_num_clones_counter{0};
bool IsEnabledUseSmartRefForGPUFenceHandle() {
static bool is_enabled =
base::FeatureList::IsEnabled(features::kUseSmartRefForGPUFenceHandle);
return is_enabled;
} // namespace
gfx::GpuFenceHandle::ScopedPlatformFence PlatformDuplicate(
const gfx::GpuFenceHandle::ScopedPlatformFence& scoped_fence) {
g_num_clones_counter++;
#if BUILDFLAG(IS_POSIX)
return base::ScopedFD(HANDLE_EINTR(dup(scoped_fence.get())));
#elif BUILDFLAG(IS_FUCHSIA)
zx::event temp_event;
zx_status_t status =
scoped_fence.duplicate(ZX_RIGHT_SAME_RIGHTS, &temp_event);
if (status != ZX_OK) {
ZX_DLOG(ERROR, status) << "zx_handle_duplicate";
return gfx::GpuFenceHandle::ScopedPlatformFence();
}
return temp_event;
#elif BUILDFLAG(IS_WIN)
const base::ProcessHandle process = ::GetCurrentProcess();
HANDLE duplicated_handle = INVALID_HANDLE_VALUE;
const BOOL result =
::DuplicateHandle(process, scoped_fence.Get(), process,
&duplicated_handle, 0, FALSE, DUPLICATE_SAME_ACCESS);
if (!result) {
const DWORD last_error = ::GetLastError();
base::debug::Alias(&last_error);
CHECK(false);
}
return base::win::ScopedHandle(duplicated_handle);
#else
NOTREACHED();
#endif
}
} // namespace
namespace gfx {
GpuFenceHandle::GpuFenceHandle() = default;
GpuFenceHandle::GpuFenceHandle(GpuFenceHandle&& other)
: smart_fence_(std::move(other.smart_fence_)) {}
GpuFenceHandle& GpuFenceHandle::operator=(GpuFenceHandle&& other) {
if (this != &other) {
smart_fence_ = std::move(other.smart_fence_);
}
return *this;
}
void GpuFenceHandle::Reset() {
smart_fence_.reset();
}
GpuFenceHandle::~GpuFenceHandle() = default;
bool GpuFenceHandle::is_null() const {
if (!smart_fence_.get()) {
return true;
}
#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
return !smart_fence_.get()->scoped_fence_.is_valid();
#elif BUILDFLAG(IS_WIN)
return !smart_fence_.get()->scoped_fence_.IsValid();
#else
return true;
#endif
}
GpuFenceHandle::RefCountedScopedFence::RefCountedScopedFence(
ScopedPlatformFence scoped_fence)
: scoped_fence_(std::move(scoped_fence)) {}
GpuFenceHandle::RefCountedScopedFence::~RefCountedScopedFence() = default;
#if BUILDFLAG(IS_POSIX)
int GpuFenceHandle::Peek() const {
return is_null() ? base::ScopedFD().get()
: smart_fence_.get()->scoped_fence_.get();
}
#elif BUILDFLAG(IS_WIN)
HANDLE GpuFenceHandle::Peek() const {
return is_null() ? INVALID_HANDLE_VALUE
: smart_fence_.get()->scoped_fence_.Get();
}
#endif
void GpuFenceHandle::Adopt(ScopedPlatformFence scoped_fence) {
if (scoped_fence.is_valid()) {
smart_fence_ =
base::MakeRefCounted<RefCountedScopedFence>(std::move(scoped_fence));
} else {
Reset();
}
}
GpuFenceHandle::ScopedPlatformFence GpuFenceHandle::Release() {
if (is_null()) {
return ScopedPlatformFence();
}
GpuFenceHandle::ScopedPlatformFence return_fence;
if (smart_fence_->HasOneRef()) {
// Sole owner of this FD. Non dup optimization below.
return_fence = std::move(smart_fence_->scoped_fence_);
} else {
DCHECK(IsEnabledUseSmartRefForGPUFenceHandle());
return_fence = PlatformDuplicate(smart_fence_->scoped_fence_);
}
Reset();
return return_fence;
}
// static
uint32_t GpuFenceHandle::GetAndClearNumberOfClones() {
return g_num_clones_counter.exchange(0);
}
GpuFenceHandle GpuFenceHandle::Clone() const {
if (is_null()) {
return GpuFenceHandle();
}
gfx::GpuFenceHandle handle;
if (IsEnabledUseSmartRefForGPUFenceHandle()) {
handle.smart_fence_ = this->smart_fence_;
} else {
handle.Adopt(PlatformDuplicate(smart_fence_->scoped_fence_));
}
return handle;
}
} // namespace gfx