Roll ANGLE e754fb8..6ffeb74
[chromium-blink-merge.git] / content / browser / compositor / buffer_queue.cc
blobed055826c39c4fe61e501acafb5948a7b0ca719e
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 internalformat,
23 GLHelper* gl_helper,
24 BrowserGpuMemoryBufferManager* gpu_memory_buffer_manager,
25 int surface_id)
26 : context_provider_(context_provider),
27 fbo_(0),
28 allocated_count_(0),
29 internalformat_(internalformat),
30 gl_helper_(gl_helper),
31 gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
32 surface_id_(surface_id) {
35 BufferQueue::~BufferQueue() {
36 FreeAllSurfaces();
38 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
39 if (fbo_)
40 gl->DeleteFramebuffers(1, &fbo_);
43 void BufferQueue::Initialize() {
44 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
45 gl->GenFramebuffers(1, &fbo_);
48 void BufferQueue::BindFramebuffer() {
49 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
50 gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_);
52 if (!current_surface_.texture) {
53 current_surface_ = GetNextSurface();
54 gl->FramebufferTexture2D(GL_FRAMEBUFFER,
55 GL_COLOR_ATTACHMENT0,
56 GL_TEXTURE_2D,
57 current_surface_.texture,
58 0);
62 void BufferQueue::CopyBufferDamage(int texture,
63 int source_texture,
64 const gfx::Rect& new_damage,
65 const gfx::Rect& old_damage) {
66 gl_helper_->CopySubBufferDamage(
67 texture,
68 source_texture,
69 SkRegion(SkIRect::MakeXYWH(new_damage.x(),
70 new_damage.y(),
71 new_damage.width(),
72 new_damage.height())),
73 SkRegion(SkIRect::MakeXYWH(old_damage.x(),
74 old_damage.y(),
75 old_damage.width(),
76 old_damage.height())));
79 void BufferQueue::UpdateBufferDamage(const gfx::Rect& damage) {
80 displayed_surface_.damage.Union(damage);
81 for (size_t i = 0; i < available_surfaces_.size(); i++)
82 available_surfaces_[i].damage.Union(damage);
84 for (std::deque<AllocatedSurface>::iterator it =
85 in_flight_surfaces_.begin();
86 it != in_flight_surfaces_.end();
87 ++it)
88 it->damage.Union(damage);
91 void BufferQueue::SwapBuffers(const gfx::Rect& damage) {
92 if (damage != gfx::Rect(size_)) {
93 // We must have a frame available to copy from.
94 DCHECK(!in_flight_surfaces_.empty() || displayed_surface_.texture);
95 unsigned int texture_id = !in_flight_surfaces_.empty()
96 ? in_flight_surfaces_.back().texture
97 : displayed_surface_.texture;
99 CopyBufferDamage(current_surface_.texture, texture_id, damage,
100 current_surface_.damage);
102 UpdateBufferDamage(damage);
103 current_surface_.damage = gfx::Rect();
104 in_flight_surfaces_.push_back(current_surface_);
105 current_surface_.texture = 0;
106 current_surface_.image = 0;
107 // Some things reset the framebuffer (CopySubBufferDamage, some GLRenderer
108 // paths), so ensure we restore it here.
109 context_provider_->ContextGL()->BindFramebuffer(GL_FRAMEBUFFER, fbo_);
112 void BufferQueue::Reshape(const gfx::Size& size, float scale_factor) {
113 DCHECK(!current_surface_.texture);
114 if (size == size_)
115 return;
116 size_ = size;
118 // TODO: add stencil buffer when needed.
119 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
120 gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_);
121 gl->FramebufferTexture2D(
122 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
124 FreeAllSurfaces();
127 void BufferQueue::PageFlipComplete() {
128 DCHECK(!in_flight_surfaces_.empty());
130 if (displayed_surface_.texture)
131 available_surfaces_.push_back(displayed_surface_);
133 displayed_surface_ = in_flight_surfaces_.front();
134 in_flight_surfaces_.pop_front();
137 void BufferQueue::FreeAllSurfaces() {
138 FreeSurface(&displayed_surface_);
139 FreeSurface(&current_surface_);
140 // This is intentionally not emptied since the swap buffers acks are still
141 // expected to arrive.
142 for (auto& surface : in_flight_surfaces_)
143 FreeSurface(&surface);
145 for (size_t i = 0; i < available_surfaces_.size(); i++)
146 FreeSurface(&available_surfaces_[i]);
148 available_surfaces_.clear();
151 void BufferQueue::FreeSurface(AllocatedSurface* surface) {
152 if (surface->texture) {
153 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
154 gl->BindTexture(GL_TEXTURE_2D, surface->texture);
155 gl->ReleaseTexImage2DCHROMIUM(GL_TEXTURE_2D, surface->image);
156 gl->DeleteTextures(1, &surface->texture);
157 gl->DestroyImageCHROMIUM(surface->image);
158 surface->image = 0;
159 surface->texture = 0;
160 allocated_count_--;
164 BufferQueue::AllocatedSurface BufferQueue::GetNextSurface() {
165 if (!available_surfaces_.empty()) {
166 AllocatedSurface surface = available_surfaces_.back();
167 available_surfaces_.pop_back();
168 return surface;
171 unsigned int texture = 0;
172 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
173 gl->GenTextures(1, &texture);
174 if (!texture)
175 return AllocatedSurface();
177 // We don't want to allow anything more than triple buffering.
178 DCHECK_LT(allocated_count_, 4U);
180 scoped_ptr<gfx::GpuMemoryBuffer> buffer(
181 gpu_memory_buffer_manager_->AllocateGpuMemoryBufferForScanout(
182 size_, gpu::ImageFactory::ImageFormatToGpuMemoryBufferFormat(
183 internalformat_),
184 surface_id_));
185 if (!buffer) {
186 gl->DeleteTextures(1, &texture);
187 DLOG(ERROR) << "Failed to allocate GPU memory buffer";
188 return AllocatedSurface();
191 unsigned int id = gl->CreateImageCHROMIUM(
192 buffer->AsClientBuffer(), size_.width(), size_.height(), internalformat_);
194 if (!id) {
195 LOG(ERROR) << "Failed to allocate backing image surface";
196 gl->DeleteTextures(1, &texture);
197 return AllocatedSurface();
199 allocated_count_++;
200 gl->BindTexture(GL_TEXTURE_2D, texture);
201 gl->BindTexImage2DCHROMIUM(GL_TEXTURE_2D, id);
202 return AllocatedSurface(texture, id, gfx::Rect(size_));
205 } // namespace content