Chromecast: extracts Linux window creation code to a common place.
[chromium-blink-merge.git] / content / browser / compositor / buffer_queue.cc
blob212105940825547dbace9751e83b47702c167698
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/common/gpu/client/context_provider_command_buffer.h"
9 #include "content/common/gpu/client/gl_helper.h"
10 #include "gpu/GLES2/gl2extchromium.h"
11 #include "gpu/command_buffer/client/gles2_interface.h"
12 #include "third_party/skia/include/core/SkRect.h"
13 #include "third_party/skia/include/core/SkRegion.h"
15 namespace content {
17 BufferQueue::BufferQueue(scoped_refptr<cc::ContextProvider> context_provider,
18 unsigned int internalformat)
19 : context_provider_(context_provider),
20 fbo_(0),
21 allocated_count_(0),
22 internalformat_(internalformat) {
25 BufferQueue::~BufferQueue() {
26 FreeAllSurfaces();
28 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
29 if (fbo_)
30 gl->DeleteFramebuffers(1, &fbo_);
33 bool BufferQueue::Initialize() {
34 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
35 gl->GenFramebuffers(1, &fbo_);
36 return fbo_ != 0;
39 void BufferQueue::BindFramebuffer() {
40 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
41 gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_);
43 if (!current_surface_.texture) {
44 current_surface_ = GetNextSurface();
45 gl->FramebufferTexture2D(GL_FRAMEBUFFER,
46 GL_COLOR_ATTACHMENT0,
47 GL_TEXTURE_2D,
48 current_surface_.texture,
49 0);
53 void BufferQueue::CopyBufferDamage(int texture,
54 int source_texture,
55 const gfx::Rect& new_damage,
56 const gfx::Rect& old_damage) {
57 ImageTransportFactory::GetInstance()->GetGLHelper()->CopySubBufferDamage(
58 texture,
59 source_texture,
60 SkRegion(SkIRect::MakeXYWH(new_damage.x(),
61 new_damage.y(),
62 new_damage.width(),
63 new_damage.height())),
64 SkRegion(SkIRect::MakeXYWH(old_damage.x(),
65 old_damage.y(),
66 old_damage.width(),
67 old_damage.height())));
70 void BufferQueue::UpdateBufferDamage(const gfx::Rect& damage) {
71 for (size_t i = 0; i < available_surfaces_.size(); i++)
72 available_surfaces_[i].damage.Union(damage);
73 for (std::deque<AllocatedSurface>::iterator it =
74 in_flight_surfaces_.begin();
75 it != in_flight_surfaces_.end();
76 ++it)
77 it->damage.Union(damage);
80 void BufferQueue::SwapBuffers(const gfx::Rect& damage) {
81 if (damage != gfx::Rect(size_)) {
82 // We must have a frame available to copy from.
83 DCHECK(!in_flight_surfaces_.empty());
84 CopyBufferDamage(current_surface_.texture,
85 in_flight_surfaces_.back().texture,
86 damage,
87 current_surface_.damage);
89 UpdateBufferDamage(damage);
90 current_surface_.damage = gfx::Rect();
91 in_flight_surfaces_.push_back(current_surface_);
92 current_surface_.texture = 0;
93 current_surface_.image = 0;
96 void BufferQueue::Reshape(const gfx::Size& size, float scale_factor) {
97 DCHECK(!current_surface_.texture);
98 if (size == size_)
99 return;
100 size_ = size;
102 // TODO: add stencil buffer when needed.
103 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
104 gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_);
105 gl->FramebufferTexture2D(
106 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
108 FreeAllSurfaces();
111 void BufferQueue::PageFlipComplete() {
112 if (in_flight_surfaces_.size() > 1) {
113 available_surfaces_.push_back(in_flight_surfaces_.front());
114 in_flight_surfaces_.pop_front();
118 void BufferQueue::FreeAllSurfaces() {
119 FreeSurface(&current_surface_);
120 while (!in_flight_surfaces_.empty()) {
121 FreeSurface(&in_flight_surfaces_.front());
122 in_flight_surfaces_.pop_front();
124 for (size_t i = 0; i < available_surfaces_.size(); i++)
125 FreeSurface(&available_surfaces_[i]);
126 available_surfaces_.clear();
129 void BufferQueue::FreeSurface(AllocatedSurface* surface) {
130 if (surface->texture) {
131 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
132 gl->BindTexture(GL_TEXTURE_2D, surface->texture);
133 gl->ReleaseTexImage2DCHROMIUM(GL_TEXTURE_2D, surface->image);
134 gl->DeleteTextures(1, &surface->texture);
135 gl->DestroyImageCHROMIUM(surface->image);
136 surface->image = 0;
137 surface->texture = 0;
138 allocated_count_--;
142 BufferQueue::AllocatedSurface BufferQueue::GetNextSurface() {
143 if (!available_surfaces_.empty()) {
144 AllocatedSurface surface = available_surfaces_.back();
145 available_surfaces_.pop_back();
146 return surface;
149 unsigned int texture = 0;
150 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
151 gl->GenTextures(1, &texture);
152 if (!texture)
153 return AllocatedSurface();
155 // We don't want to allow anything more than triple buffering.
156 DCHECK_LT(allocated_count_, 4U);
158 unsigned int id =
159 gl->CreateGpuMemoryBufferImageCHROMIUM(size_.width(),
160 size_.height(),
161 internalformat_,
162 GL_SCANOUT_CHROMIUM);
163 if (!id) {
164 LOG(ERROR) << "Failed to allocate backing image surface";
165 gl->DeleteTextures(1, &texture);
166 return AllocatedSurface();
168 allocated_count_++;
169 gl->BindTexture(GL_TEXTURE_2D, texture);
170 gl->BindTexImage2DCHROMIUM(GL_TEXTURE_2D, id);
171 return AllocatedSurface(texture, id, gfx::Rect(size_));
174 } // namespace content