1 // Copyright 2013 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 "gpu/ipc/common/gpu_memory_buffer_impl_io_surface.h"
6 
7 #include "base/bind.h"
8 #include "base/callback_helpers.h"
9 #include "base/debug/dump_without_crashing.h"
10 #include "base/logging.h"
11 #include "base/memory/ptr_util.h"
12 #include "gpu/ipc/common/gpu_memory_buffer_support.h"
13 #include "ui/gfx/buffer_format_util.h"
14 #include "ui/gfx/mac/io_surface.h"
15 
16 namespace gpu {
17 namespace {
18 
19 // The maximum number of times to dump before throttling (to avoid sending
20 // thousands of crash dumps).
21 
22 const int kMaxCrashDumps = 10;
23 
LockFlags(gfx::BufferUsage usage)24 uint32_t LockFlags(gfx::BufferUsage usage) {
25   switch (usage) {
26     case gfx::BufferUsage::GPU_READ_CPU_READ_WRITE:
27     case gfx::BufferUsage::SCANOUT_VEA_READ_CAMERA_AND_CPU_READ_WRITE:
28       // The AvoidSync call has the property that it will not preserve the
29       // previous contents of the buffer if those contents were written by a
30       // GPU.
31       return kIOSurfaceLockAvoidSync;
32     case gfx::BufferUsage::SCANOUT_VEA_CPU_READ:
33       // This constant is used for buffers used by video capture. On macOS,
34       // these buffers are only ever written to in the capture process,
35       // directly as IOSurfaces.
36       // Once they are sent to other processes, no CPU writes are performed.
37       return kIOSurfaceLockReadOnly;
38     case gfx::BufferUsage::GPU_READ:
39     case gfx::BufferUsage::SCANOUT:
40     case gfx::BufferUsage::SCANOUT_CAMERA_READ_WRITE:
41     case gfx::BufferUsage::CAMERA_AND_CPU_READ_WRITE:
42     case gfx::BufferUsage::SCANOUT_CPU_READ_WRITE:
43     case gfx::BufferUsage::SCANOUT_VDA_WRITE:
44     case gfx::BufferUsage::PROTECTED_SCANOUT_VDA_WRITE:
45       return 0;
46   }
47   NOTREACHED();
48   return 0;
49 }
50 
51 }  // namespace
52 
GpuMemoryBufferImplIOSurface(gfx::GpuMemoryBufferId id,const gfx::Size & size,gfx::BufferFormat format,DestructionCallback callback,IOSurfaceRef io_surface,uint32_t lock_flags)53 GpuMemoryBufferImplIOSurface::GpuMemoryBufferImplIOSurface(
54     gfx::GpuMemoryBufferId id,
55     const gfx::Size& size,
56     gfx::BufferFormat format,
57     DestructionCallback callback,
58     IOSurfaceRef io_surface,
59     uint32_t lock_flags)
60     : GpuMemoryBufferImpl(id, size, format, std::move(callback)),
61       io_surface_(io_surface),
62       lock_flags_(lock_flags) {}
63 
~GpuMemoryBufferImplIOSurface()64 GpuMemoryBufferImplIOSurface::~GpuMemoryBufferImplIOSurface() {}
65 
66 // static
67 std::unique_ptr<GpuMemoryBufferImplIOSurface>
CreateFromHandle(const gfx::GpuMemoryBufferHandle & handle,const gfx::Size & size,gfx::BufferFormat format,gfx::BufferUsage usage,DestructionCallback callback)68 GpuMemoryBufferImplIOSurface::CreateFromHandle(
69     const gfx::GpuMemoryBufferHandle& handle,
70     const gfx::Size& size,
71     gfx::BufferFormat format,
72     gfx::BufferUsage usage,
73     DestructionCallback callback) {
74   if (!handle.io_surface) {
75     LOG(ERROR) << "Invalid IOSurface returned to client.";
76     return nullptr;
77   }
78 
79   gfx::ScopedIOSurface io_surface = handle.io_surface;
80   if (!io_surface) {
81     LOG(ERROR) << "Failed to open IOSurface via mach port returned to client.";
82     static int dump_counter = kMaxCrashDumps;
83     if (dump_counter) {
84       dump_counter -= 1;
85       base::debug::DumpWithoutCrashing();
86     }
87     return nullptr;
88   }
89   int64_t io_surface_width = IOSurfaceGetWidth(io_surface);
90   int64_t io_surface_height = IOSurfaceGetHeight(io_surface);
91   if (io_surface_width < size.width() || io_surface_height < size.height()) {
92     DLOG(ERROR) << "IOSurface size does not match handle.";
93     return nullptr;
94   }
95 
96   return base::WrapUnique(new GpuMemoryBufferImplIOSurface(
97       handle.id, size, format, std::move(callback), io_surface.release(),
98       LockFlags(usage)));
99 }
100 
101 // static
AllocateForTesting(const gfx::Size & size,gfx::BufferFormat format,gfx::BufferUsage usage,gfx::GpuMemoryBufferHandle * handle)102 base::OnceClosure GpuMemoryBufferImplIOSurface::AllocateForTesting(
103     const gfx::Size& size,
104     gfx::BufferFormat format,
105     gfx::BufferUsage usage,
106     gfx::GpuMemoryBufferHandle* handle) {
107   gfx::GpuMemoryBufferId kBufferId(1);
108   handle->type = gfx::IO_SURFACE_BUFFER;
109   handle->id = kBufferId;
110   handle->io_surface.reset(gfx::CreateIOSurface(size, format));
111   DCHECK(handle->io_surface);
112   return base::DoNothing();
113 }
114 
Map()115 bool GpuMemoryBufferImplIOSurface::Map() {
116   DCHECK(!mapped_);
117   IOReturn status = IOSurfaceLock(io_surface_, lock_flags_, nullptr);
118   DCHECK_NE(status, kIOReturnCannotLock);
119   mapped_ = true;
120   return true;
121 }
122 
memory(size_t plane)123 void* GpuMemoryBufferImplIOSurface::memory(size_t plane) {
124   DCHECK(mapped_);
125   DCHECK_LT(plane, gfx::NumberOfPlanesForLinearBufferFormat(format_));
126   return IOSurfaceGetBaseAddressOfPlane(io_surface_, plane);
127 }
128 
Unmap()129 void GpuMemoryBufferImplIOSurface::Unmap() {
130   DCHECK(mapped_);
131   IOSurfaceUnlock(io_surface_, lock_flags_, nullptr);
132   mapped_ = false;
133 }
134 
stride(size_t plane) const135 int GpuMemoryBufferImplIOSurface::stride(size_t plane) const {
136   DCHECK_LT(plane, gfx::NumberOfPlanesForLinearBufferFormat(format_));
137   return IOSurfaceGetBytesPerRowOfPlane(io_surface_, plane);
138 }
139 
SetColorSpace(const gfx::ColorSpace & color_space)140 void GpuMemoryBufferImplIOSurface::SetColorSpace(
141     const gfx::ColorSpace& color_space) {
142   if (color_space == color_space_)
143     return;
144   color_space_ = color_space;
145   IOSurfaceSetColorSpace(io_surface_, color_space);
146 }
147 
GetType() const148 gfx::GpuMemoryBufferType GpuMemoryBufferImplIOSurface::GetType() const {
149   return gfx::IO_SURFACE_BUFFER;
150 }
151 
CloneHandle() const152 gfx::GpuMemoryBufferHandle GpuMemoryBufferImplIOSurface::CloneHandle() const {
153   gfx::GpuMemoryBufferHandle handle;
154   handle.type = gfx::IO_SURFACE_BUFFER;
155   handle.id = id_;
156   handle.io_surface = io_surface_;
157   return handle;
158 }
159 
160 }  // namespace gpu
161