Roll src/third_party/WebKit f298044:aa8346d (svn 202628:202629)
[chromium-blink-merge.git] / content / browser / compositor / buffer_queue.cc
blob4845e57916e9997020048c916e9e142fff305afc
1 // Copyright 2014 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/compositor/buffer_queue.h"
7 #include "content/browser/compositor/image_transport_factory.h"
8 #include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
9 #include "content/common/gpu/client/context_provider_command_buffer.h"
10 #include "content/common/gpu/client/gl_helper.h"
11 #include "gpu/GLES2/gl2extchromium.h"
12 #include "gpu/command_buffer/client/gles2_interface.h"
13 #include "gpu/command_buffer/service/image_factory.h"
14 #include "third_party/skia/include/core/SkRect.h"
15 #include "third_party/skia/include/core/SkRegion.h"
16 #include "ui/gfx/gpu_memory_buffer.h"
18 namespace content {
20 BufferQueue::BufferQueue(
21 scoped_refptr<cc::ContextProvider> context_provider,
22 unsigned int texture_target,
23 unsigned int internalformat,
24 GLHelper* gl_helper,
25 BrowserGpuMemoryBufferManager* gpu_memory_buffer_manager,
26 int surface_id)
27 : context_provider_(context_provider),
28 fbo_(0),
29 allocated_count_(0),
30 texture_target_(texture_target),
31 internal_format_(internalformat),
32 gl_helper_(gl_helper),
33 gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
34 surface_id_(surface_id) {}
36 BufferQueue::~BufferQueue() {
37 FreeAllSurfaces();
39 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
40 if (fbo_)
41 gl->DeleteFramebuffers(1, &fbo_);
44 void BufferQueue::Initialize() {
45 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
46 gl->GenFramebuffers(1, &fbo_);
49 void BufferQueue::BindFramebuffer() {
50 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
51 gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_);
53 if (!current_surface_.texture) {
54 current_surface_ = GetNextSurface();
55 gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
56 texture_target_, current_surface_.texture, 0);
60 void BufferQueue::CopyBufferDamage(int texture,
61 int source_texture,
62 const gfx::Rect& new_damage,
63 const gfx::Rect& old_damage) {
64 gl_helper_->CopySubBufferDamage(
65 texture_target_, texture, source_texture,
66 SkRegion(SkIRect::MakeXYWH(new_damage.x(), new_damage.y(),
67 new_damage.width(), new_damage.height())),
68 SkRegion(SkIRect::MakeXYWH(old_damage.x(), old_damage.y(),
69 old_damage.width(), old_damage.height())));
72 void BufferQueue::UpdateBufferDamage(const gfx::Rect& damage) {
73 displayed_surface_.damage.Union(damage);
74 for (size_t i = 0; i < available_surfaces_.size(); i++)
75 available_surfaces_[i].damage.Union(damage);
77 for (std::deque<AllocatedSurface>::iterator it =
78 in_flight_surfaces_.begin();
79 it != in_flight_surfaces_.end();
80 ++it)
81 it->damage.Union(damage);
84 void BufferQueue::SwapBuffers(const gfx::Rect& damage) {
85 if (damage != gfx::Rect(size_)) {
86 // We must have a frame available to copy from.
87 DCHECK(!in_flight_surfaces_.empty() || displayed_surface_.texture);
88 unsigned int texture_id = !in_flight_surfaces_.empty()
89 ? in_flight_surfaces_.back().texture
90 : displayed_surface_.texture;
92 CopyBufferDamage(current_surface_.texture, texture_id, damage,
93 current_surface_.damage);
95 UpdateBufferDamage(damage);
96 current_surface_.damage = gfx::Rect();
97 in_flight_surfaces_.push_back(current_surface_);
98 current_surface_.texture = 0;
99 current_surface_.image = 0;
100 // Some things reset the framebuffer (CopySubBufferDamage, some GLRenderer
101 // paths), so ensure we restore it here.
102 context_provider_->ContextGL()->BindFramebuffer(GL_FRAMEBUFFER, fbo_);
105 void BufferQueue::Reshape(const gfx::Size& size, float scale_factor) {
106 if (size == size_)
107 return;
108 // TODO(ccameron): This assert is being hit on Mac try jobs. Determine if that
109 // is cause for concern or if it is benign.
110 // http://crbug.com/524624
111 #if !defined(OS_MACOSX)
112 DCHECK(!current_surface_.texture);
113 #endif
114 size_ = size;
116 // TODO: add stencil buffer when needed.
117 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
118 gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_);
119 gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
120 texture_target_, 0, 0);
122 FreeAllSurfaces();
125 void BufferQueue::RecreateBuffers() {
126 // We need to recreate the buffers, for whatever reason the old ones are not
127 // presentable on the device anymore.
128 // Unused buffers can be freed directly, they will be re-allocated as needed.
129 // Any in flight, current or displayed surface must be replaced.
130 for (size_t i = 0; i < available_surfaces_.size(); i++)
131 FreeSurface(&available_surfaces_[i]);
132 available_surfaces_.clear();
134 for (auto& surface : in_flight_surfaces_)
135 surface = RecreateBuffer(&surface);
137 current_surface_ = RecreateBuffer(&current_surface_);
138 displayed_surface_ = RecreateBuffer(&displayed_surface_);
140 if (current_surface_.texture) {
141 // If we have a texture bound, we will need to re-bind it.
142 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
143 gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_);
144 gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
145 texture_target_, current_surface_.texture, 0);
149 BufferQueue::AllocatedSurface BufferQueue::RecreateBuffer(
150 AllocatedSurface* surface) {
151 if (!surface->texture)
152 return *surface;
153 AllocatedSurface new_surface = GetNextSurface();
154 new_surface.damage = surface->damage;
156 // Copy the entire texture.
157 CopyBufferDamage(new_surface.texture, surface->texture, gfx::Rect(),
158 gfx::Rect(size_));
160 FreeSurface(surface);
161 return new_surface;
164 void BufferQueue::PageFlipComplete() {
165 DCHECK(!in_flight_surfaces_.empty());
167 if (displayed_surface_.texture)
168 available_surfaces_.push_back(displayed_surface_);
170 displayed_surface_ = in_flight_surfaces_.front();
171 in_flight_surfaces_.pop_front();
174 void BufferQueue::FreeAllSurfaces() {
175 FreeSurface(&displayed_surface_);
176 FreeSurface(&current_surface_);
177 // This is intentionally not emptied since the swap buffers acks are still
178 // expected to arrive.
179 for (auto& surface : in_flight_surfaces_)
180 FreeSurface(&surface);
182 for (size_t i = 0; i < available_surfaces_.size(); i++)
183 FreeSurface(&available_surfaces_[i]);
185 available_surfaces_.clear();
188 void BufferQueue::FreeSurface(AllocatedSurface* surface) {
189 if (surface->texture) {
190 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
191 gl->BindTexture(texture_target_, surface->texture);
192 gl->ReleaseTexImage2DCHROMIUM(texture_target_, surface->image);
193 gl->DeleteTextures(1, &surface->texture);
194 gl->DestroyImageCHROMIUM(surface->image);
195 surface->image = 0;
196 surface->texture = 0;
197 allocated_count_--;
201 BufferQueue::AllocatedSurface BufferQueue::GetNextSurface() {
202 if (!available_surfaces_.empty()) {
203 AllocatedSurface surface = available_surfaces_.back();
204 available_surfaces_.pop_back();
205 return surface;
208 unsigned int texture = 0;
209 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
210 gl->GenTextures(1, &texture);
211 if (!texture)
212 return AllocatedSurface();
214 // We don't want to allow anything more than triple buffering.
215 DCHECK_LT(allocated_count_, 4U);
217 scoped_ptr<gfx::GpuMemoryBuffer> buffer(
218 gpu_memory_buffer_manager_->AllocateGpuMemoryBufferForScanout(
219 size_, gpu::ImageFactory::DefaultBufferFormatForImageFormat(
220 internal_format_),
221 surface_id_));
222 if (!buffer) {
223 gl->DeleteTextures(1, &texture);
224 DLOG(ERROR) << "Failed to allocate GPU memory buffer";
225 return AllocatedSurface();
228 unsigned int id = gl->CreateImageCHROMIUM(
229 buffer->AsClientBuffer(), size_.width(), size_.height(),
230 internal_format_);
232 if (!id) {
233 LOG(ERROR) << "Failed to allocate backing image surface";
234 gl->DeleteTextures(1, &texture);
235 return AllocatedSurface();
237 allocated_count_++;
238 gl->BindTexture(texture_target_, texture);
239 gl->BindTexImage2DCHROMIUM(texture_target_, id);
240 return AllocatedSurface(texture, id, gfx::Rect(size_));
243 } // namespace content