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