blob: 537491d960df77dc745397b3b197cc4bc84f0581 [file] [log] [blame]
// Copyright 2013 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 "gpu/ipc/common/gpu_memory_buffer_impl_io_surface.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/debug/dump_without_crashing.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "gpu/ipc/common/gpu_memory_buffer_support.h"
#include "ui/gfx/buffer_format_util.h"
#include "ui/gfx/mac/io_surface.h"
namespace gpu {
namespace {
// The maximum number of times to dump before throttling (to avoid sending
// thousands of crash dumps).
const int kMaxCrashDumps = 10;
uint32_t LockFlags(gfx::BufferUsage usage) {
switch (usage) {
case gfx::BufferUsage::GPU_READ_CPU_READ_WRITE:
return kIOSurfaceLockAvoidSync;
case gfx::BufferUsage::GPU_READ:
case gfx::BufferUsage::SCANOUT:
case gfx::BufferUsage::SCANOUT_CAMERA_READ_WRITE:
case gfx::BufferUsage::CAMERA_AND_CPU_READ_WRITE:
case gfx::BufferUsage::SCANOUT_CPU_READ_WRITE:
case gfx::BufferUsage::SCANOUT_VDA_WRITE:
case gfx::BufferUsage::SCANOUT_VEA_READ_CAMERA_AND_CPU_READ_WRITE:
return 0;
}
NOTREACHED();
return 0;
}
} // namespace
GpuMemoryBufferImplIOSurface::GpuMemoryBufferImplIOSurface(
gfx::GpuMemoryBufferId id,
const gfx::Size& size,
gfx::BufferFormat format,
DestructionCallback callback,
IOSurfaceRef io_surface,
uint32_t lock_flags)
: GpuMemoryBufferImpl(id, size, format, std::move(callback)),
io_surface_(io_surface),
lock_flags_(lock_flags) {}
GpuMemoryBufferImplIOSurface::~GpuMemoryBufferImplIOSurface() {}
// static
std::unique_ptr<GpuMemoryBufferImplIOSurface>
GpuMemoryBufferImplIOSurface::CreateFromHandle(
const gfx::GpuMemoryBufferHandle& handle,
const gfx::Size& size,
gfx::BufferFormat format,
gfx::BufferUsage usage,
DestructionCallback callback) {
if (!handle.mach_port) {
LOG(ERROR) << "Invalid IOSurface mach port returned to client.";
return nullptr;
}
base::ScopedCFTypeRef<IOSurfaceRef> io_surface(
IOSurfaceLookupFromMachPort(handle.mach_port.get()));
if (!io_surface) {
LOG(ERROR) << "Failed to open IOSurface via mach port returned to client.";
static int dump_counter = kMaxCrashDumps;
if (dump_counter) {
dump_counter -= 1;
base::debug::DumpWithoutCrashing();
}
return nullptr;
}
int64_t io_surface_width = IOSurfaceGetWidth(io_surface);
int64_t io_surface_height = IOSurfaceGetHeight(io_surface);
if (io_surface_width < size.width() || io_surface_height < size.height()) {
DLOG(ERROR) << "IOSurface size does not match handle.";
return nullptr;
}
return base::WrapUnique(new GpuMemoryBufferImplIOSurface(
handle.id, size, format, std::move(callback), io_surface.release(),
LockFlags(usage)));
}
// static
base::OnceClosure GpuMemoryBufferImplIOSurface::AllocateForTesting(
const gfx::Size& size,
gfx::BufferFormat format,
gfx::BufferUsage usage,
gfx::GpuMemoryBufferHandle* handle) {
base::ScopedCFTypeRef<IOSurfaceRef> io_surface(
gfx::CreateIOSurface(size, format));
DCHECK(io_surface);
gfx::GpuMemoryBufferId kBufferId(1);
handle->type = gfx::IO_SURFACE_BUFFER;
handle->id = kBufferId;
handle->mach_port.reset(IOSurfaceCreateMachPort(io_surface));
return base::DoNothing();
}
bool GpuMemoryBufferImplIOSurface::Map() {
DCHECK(!mapped_);
IOReturn status = IOSurfaceLock(io_surface_, lock_flags_, nullptr);
DCHECK_NE(status, kIOReturnCannotLock);
mapped_ = true;
return true;
}
void* GpuMemoryBufferImplIOSurface::memory(size_t plane) {
DCHECK(mapped_);
DCHECK_LT(plane, gfx::NumberOfPlanesForLinearBufferFormat(format_));
return IOSurfaceGetBaseAddressOfPlane(io_surface_, plane);
}
void GpuMemoryBufferImplIOSurface::Unmap() {
DCHECK(mapped_);
IOSurfaceUnlock(io_surface_, lock_flags_, nullptr);
mapped_ = false;
}
int GpuMemoryBufferImplIOSurface::stride(size_t plane) const {
DCHECK_LT(plane, gfx::NumberOfPlanesForLinearBufferFormat(format_));
return IOSurfaceGetBytesPerRowOfPlane(io_surface_, plane);
}
void GpuMemoryBufferImplIOSurface::SetColorSpace(
const gfx::ColorSpace& color_space) {
if (color_space == color_space_)
return;
color_space_ = color_space;
IOSurfaceSetColorSpace(io_surface_, color_space);
}
gfx::GpuMemoryBufferType GpuMemoryBufferImplIOSurface::GetType() const {
return gfx::IO_SURFACE_BUFFER;
}
gfx::GpuMemoryBufferHandle GpuMemoryBufferImplIOSurface::CloneHandle() const {
gfx::GpuMemoryBufferHandle handle;
handle.type = gfx::IO_SURFACE_BUFFER;
handle.id = id_;
handle.mach_port.reset(IOSurfaceCreateMachPort(io_surface_));
return handle;
}
} // namespace gpu