Add long running gmail memory benchmark for background tab.
[chromium-blink-merge.git] / content / browser / renderer_host / media / video_capture_buffer_pool.cc
blob38a579b6f1cb8eaec5cf44390b1931d1ce0a1aa0
1 // Copyright (c) 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.
5 #include "content/browser/renderer_host/media/video_capture_buffer_pool.h"
7 #include "base/logging.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/stl_util.h"
10 #include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
11 #include "content/common/gpu/client/gpu_memory_buffer_impl.h"
12 #include "content/public/browser/browser_thread.h"
14 namespace content {
16 const int VideoCaptureBufferPool::kInvalidId = -1;
18 // A simple holder of a memory-backed buffer and accesors to it.
19 class SimpleBufferHandle final : public VideoCaptureBufferPool::BufferHandle {
20 public:
21 SimpleBufferHandle(void* data, size_t size, base::SharedMemoryHandle handle)
22 : data_(data),
23 size_(size)
24 #if defined(OS_POSIX)
25 , handle_(handle)
26 #endif
29 ~SimpleBufferHandle() override {}
31 size_t size() const override { return size_; }
32 void* data() override { return data_; }
33 ClientBuffer AsClientBuffer() override { return nullptr; }
34 #if defined(OS_POSIX)
35 base::FileDescriptor AsPlatformFile() override {
36 #if defined(OS_MACOSX)
37 return handle_.GetFileDescriptor();
38 #else
39 return handle_;
40 #endif // defined(OS_MACOSX)
42 #endif
44 private:
45 void* const data_;
46 const size_t size_;
47 #if defined(OS_POSIX)
48 const base::SharedMemoryHandle handle_;
49 #endif
52 // A holder of a GpuMemoryBuffer-backed buffer, Map()ed on ctor and Unmap()ed on
53 // dtor. Holds a weak reference to its GpuMemoryBuffer.
54 // TODO(mcasas) Map()ed on ctor, or on first use?
55 class GpuMemoryBufferBufferHandle
56 final : public VideoCaptureBufferPool::BufferHandle {
57 public:
58 GpuMemoryBufferBufferHandle(gfx::GpuMemoryBuffer* gmb, size_t size)
59 : gmb_(gmb),
60 data_(new void* [GpuMemoryBufferImpl::
61 NumberOfPlanesForGpuMemoryBufferFormat(
62 gmb_->GetFormat())]),
63 size_(size) {
64 DCHECK(gmb && !gmb_->IsMapped());
65 gmb_->Map(data_.get());
67 ~GpuMemoryBufferBufferHandle() override { gmb_->Unmap(); }
69 size_t size() const override { return size_; }
70 void* data() override { return data_[0]; }
71 ClientBuffer AsClientBuffer() override { return gmb_->AsClientBuffer(); }
72 #if defined(OS_POSIX)
73 base::FileDescriptor AsPlatformFile() override {
74 #if defined(OS_MACOSX)
75 return gmb_->GetHandle().handle.GetFileDescriptor();
76 #else
77 return gmb_->GetHandle().handle;
78 #endif // defined(OS_MACOSX)
80 #endif
82 private:
83 gfx::GpuMemoryBuffer* const gmb_;
84 scoped_ptr<void*[]> data_;
85 const size_t size_;
88 // Tracker specifics for SharedMemory.
89 class VideoCaptureBufferPool::SharedMemTracker final : public Tracker {
90 public:
91 SharedMemTracker();
92 bool Init(media::VideoCapturePixelFormat format,
93 media::VideoPixelStorage storage_type,
94 const gfx::Size& dimensions) override;
96 size_t mapped_size() const override { return shared_memory_.mapped_size(); }
98 scoped_ptr<BufferHandle> GetBufferHandle() override {
99 return make_scoped_ptr(new SimpleBufferHandle(
100 shared_memory_.memory(), mapped_size(), shared_memory_.handle()));
103 bool ShareToProcess(base::ProcessHandle process_handle,
104 base::SharedMemoryHandle* new_handle) override {
105 return shared_memory_.ShareToProcess(process_handle, new_handle);
108 private:
109 // The memory created to be shared with renderer processes.
110 base::SharedMemory shared_memory_;
113 // Tracker specifics for GpuMemoryBuffer. Owns one GpuMemoryBuffer and its
114 // associated pixel dimensions.
115 class VideoCaptureBufferPool::GpuMemoryBufferTracker final : public Tracker {
116 public:
117 GpuMemoryBufferTracker();
118 bool Init(media::VideoCapturePixelFormat format,
119 media::VideoPixelStorage storage_type,
120 const gfx::Size& dimensions) override;
121 ~GpuMemoryBufferTracker() override;
123 size_t mapped_size() const override { return packed_size_; }
124 scoped_ptr<BufferHandle> GetBufferHandle() override {
125 return make_scoped_ptr(new GpuMemoryBufferBufferHandle(
126 gpu_memory_buffer_.get(), packed_size_));
129 bool ShareToProcess(base::ProcessHandle process_handle,
130 base::SharedMemoryHandle* new_handle) override {
131 return true;
134 private:
135 size_t packed_size_;
136 scoped_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer_;
139 VideoCaptureBufferPool::SharedMemTracker::SharedMemTracker() : Tracker() {
142 bool VideoCaptureBufferPool::SharedMemTracker::Init(
143 media::VideoCapturePixelFormat format,
144 media::VideoPixelStorage storage_type,
145 const gfx::Size& dimensions) {
146 DVLOG(2) << "allocating ShMem of " << dimensions.ToString();
147 set_pixel_format(format);
148 set_storage_type(storage_type);
149 // |dimensions| can be 0x0 for trackers that do not require memory backing.
150 set_pixel_count(dimensions.GetArea());
151 const size_t byte_count =
152 media::VideoCaptureFormat(dimensions, 0.0f, format, storage_type)
153 .ImageAllocationSize();
154 if (!byte_count)
155 return true;
156 return shared_memory_.CreateAndMapAnonymous(byte_count);
159 VideoCaptureBufferPool::GpuMemoryBufferTracker::GpuMemoryBufferTracker()
160 : Tracker(), packed_size_(0u), gpu_memory_buffer_(nullptr) {
163 VideoCaptureBufferPool::GpuMemoryBufferTracker::~GpuMemoryBufferTracker() {
164 if (gpu_memory_buffer_->IsMapped())
165 gpu_memory_buffer_->Unmap();
168 bool VideoCaptureBufferPool::GpuMemoryBufferTracker::Init(
169 media::VideoCapturePixelFormat format,
170 media::VideoPixelStorage storage_type,
171 const gfx::Size& dimensions) {
172 DVLOG(2) << "allocating GMB for " << dimensions.ToString();
173 // BrowserGpuMemoryBufferManager::current() may not be accessed on IO Thread.
174 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
175 DCHECK(BrowserGpuMemoryBufferManager::current());
176 set_pixel_format(format);
177 set_storage_type(storage_type);
178 set_pixel_count(dimensions.GetArea());
179 // |dimensions| can be 0x0 for trackers that do not require memory backing.
180 if (dimensions.GetArea() == 0u)
181 return true;
182 gpu_memory_buffer_ =
183 BrowserGpuMemoryBufferManager::current()->AllocateGpuMemoryBuffer(
184 dimensions,
185 gfx::GpuMemoryBuffer::BGRA_8888,
186 gfx::GpuMemoryBuffer::MAP);
187 DLOG_IF(ERROR, !gpu_memory_buffer_.get()) << "Allocating GpuMemoryBuffer";
188 if (!gpu_memory_buffer_.get())
189 return false;
190 int plane_sizes;
191 gpu_memory_buffer_->GetStride(&plane_sizes);
192 packed_size_ = plane_sizes * dimensions.height();
193 return true;
196 // static
197 scoped_ptr<VideoCaptureBufferPool::Tracker>
198 VideoCaptureBufferPool::Tracker::CreateTracker(bool use_gmb) {
199 if (!use_gmb)
200 return make_scoped_ptr(new SharedMemTracker());
201 else
202 return make_scoped_ptr(new GpuMemoryBufferTracker());
205 VideoCaptureBufferPool::Tracker::~Tracker() {}
207 VideoCaptureBufferPool::VideoCaptureBufferPool(int count)
208 : count_(count),
209 next_buffer_id_(0) {
210 DCHECK_GT(count, 0);
213 VideoCaptureBufferPool::~VideoCaptureBufferPool() {
214 STLDeleteValues(&trackers_);
217 base::SharedMemoryHandle VideoCaptureBufferPool::ShareToProcess(
218 int buffer_id,
219 base::ProcessHandle process_handle,
220 size_t* memory_size) {
221 base::AutoLock lock(lock_);
223 Tracker* tracker = GetTracker(buffer_id);
224 if (!tracker) {
225 NOTREACHED() << "Invalid buffer_id.";
226 return base::SharedMemory::NULLHandle();
228 base::SharedMemoryHandle remote_handle;
229 if (tracker->ShareToProcess(process_handle, &remote_handle)) {
230 *memory_size = tracker->mapped_size();
231 return remote_handle;
233 DPLOG(ERROR) << "Error mapping Shared Memory";
234 return base::SharedMemoryHandle();
237 scoped_ptr<VideoCaptureBufferPool::BufferHandle>
238 VideoCaptureBufferPool::GetBufferHandle(int buffer_id) {
239 base::AutoLock lock(lock_);
241 Tracker* tracker = GetTracker(buffer_id);
242 if (!tracker) {
243 NOTREACHED() << "Invalid buffer_id.";
244 return scoped_ptr<BufferHandle>();
247 DCHECK(tracker->held_by_producer());
248 return tracker->GetBufferHandle();
251 int VideoCaptureBufferPool::ReserveForProducer(
252 media::VideoCapturePixelFormat format,
253 media::VideoPixelStorage storage,
254 const gfx::Size& dimensions,
255 int* buffer_id_to_drop) {
256 base::AutoLock lock(lock_);
257 return ReserveForProducerInternal(format, storage, dimensions,
258 buffer_id_to_drop);
261 void VideoCaptureBufferPool::RelinquishProducerReservation(int buffer_id) {
262 base::AutoLock lock(lock_);
263 Tracker* tracker = GetTracker(buffer_id);
264 if (!tracker) {
265 NOTREACHED() << "Invalid buffer_id.";
266 return;
268 DCHECK(tracker->held_by_producer());
269 tracker->set_held_by_producer(false);
272 void VideoCaptureBufferPool::HoldForConsumers(
273 int buffer_id,
274 int num_clients) {
275 base::AutoLock lock(lock_);
276 Tracker* tracker = GetTracker(buffer_id);
277 if (!tracker) {
278 NOTREACHED() << "Invalid buffer_id.";
279 return;
281 DCHECK(tracker->held_by_producer());
282 DCHECK(!tracker->consumer_hold_count());
284 tracker->set_consumer_hold_count(num_clients);
285 // Note: |held_by_producer()| will stay true until
286 // RelinquishProducerReservation() (usually called by destructor of the object
287 // wrapping this tracker, e.g. a media::VideoFrame).
290 void VideoCaptureBufferPool::RelinquishConsumerHold(int buffer_id,
291 int num_clients) {
292 base::AutoLock lock(lock_);
293 Tracker* tracker = GetTracker(buffer_id);
294 if (!tracker) {
295 NOTREACHED() << "Invalid buffer_id.";
296 return;
298 DCHECK_GE(tracker->consumer_hold_count(), num_clients);
300 tracker->set_consumer_hold_count(tracker->consumer_hold_count() -
301 num_clients);
304 double VideoCaptureBufferPool::GetBufferPoolUtilization() const {
305 base::AutoLock lock(lock_);
306 int num_buffers_held = 0;
307 for (const auto& entry : trackers_) {
308 Tracker* const tracker = entry.second;
309 if (tracker->held_by_producer() || tracker->consumer_hold_count() > 0)
310 ++num_buffers_held;
312 return static_cast<double>(num_buffers_held) / count_;
315 int VideoCaptureBufferPool::ReserveForProducerInternal(
316 media::VideoCapturePixelFormat pixel_format,
317 media::VideoPixelStorage storage_type,
318 const gfx::Size& dimensions,
319 int* buffer_id_to_drop) {
320 lock_.AssertAcquired();
321 *buffer_id_to_drop = kInvalidId;
323 const size_t size_in_pixels = dimensions.GetArea();
324 // Look for a tracker that's allocated, big enough, and not in use. Track the
325 // largest one that's not big enough, in case we have to reallocate a tracker.
326 *buffer_id_to_drop = kInvalidId;
327 size_t largest_size_in_pixels = 0;
328 TrackerMap::iterator tracker_to_drop = trackers_.end();
329 for (TrackerMap::iterator it = trackers_.begin(); it != trackers_.end();
330 ++it) {
331 Tracker* const tracker = it->second;
332 if (!tracker->consumer_hold_count() && !tracker->held_by_producer()) {
333 if (tracker->pixel_count() >= size_in_pixels &&
334 (tracker->pixel_format() == pixel_format) &&
335 (tracker->storage_type() == storage_type)) {
336 // Existing tracker is big enough and has correct format. Reuse it.
337 tracker->set_held_by_producer(true);
338 return it->first;
340 if (tracker->pixel_count() > largest_size_in_pixels) {
341 largest_size_in_pixels = tracker->pixel_count();
342 tracker_to_drop = it;
347 // Preferably grow the pool by creating a new tracker. If we're at maximum
348 // size, then reallocate by deleting an existing one instead.
349 if (trackers_.size() == static_cast<size_t>(count_)) {
350 if (tracker_to_drop == trackers_.end()) {
351 // We're out of space, and can't find an unused tracker to reallocate.
352 return kInvalidId;
354 *buffer_id_to_drop = tracker_to_drop->first;
355 delete tracker_to_drop->second;
356 trackers_.erase(tracker_to_drop);
359 // Create the new tracker.
360 const int buffer_id = next_buffer_id_++;
362 scoped_ptr<Tracker> tracker = Tracker::CreateTracker(
363 storage_type == media::PIXEL_STORAGE_GPUMEMORYBUFFER);
364 if (!tracker->Init(pixel_format, storage_type, dimensions)) {
365 DLOG(ERROR) << "Error initializing Tracker";
366 return kInvalidId;
368 tracker->set_held_by_producer(true);
369 trackers_[buffer_id] = tracker.release();
371 return buffer_id;
374 VideoCaptureBufferPool::Tracker* VideoCaptureBufferPool::GetTracker(
375 int buffer_id) {
376 TrackerMap::const_iterator it = trackers_.find(buffer_id);
377 return (it == trackers_.end()) ? NULL : it->second;
380 } // namespace content