• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "content/browser/compositor/buffer_queue.h"
6 
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"
14 
15 namespace content {
16 
BufferQueue(scoped_refptr<cc::ContextProvider> context_provider,unsigned int internalformat)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) {
23 }
24 
~BufferQueue()25 BufferQueue::~BufferQueue() {
26   FreeAllSurfaces();
27 
28   gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
29   if (fbo_)
30     gl->DeleteFramebuffers(1, &fbo_);
31 }
32 
Initialize()33 bool BufferQueue::Initialize() {
34   gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
35   gl->GenFramebuffers(1, &fbo_);
36   return fbo_ != 0;
37 }
38 
BindFramebuffer()39 void BufferQueue::BindFramebuffer() {
40   gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
41   gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_);
42 
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);
50   }
51 }
52 
CopyBufferDamage(int texture,int source_texture,const gfx::Rect & new_damage,const gfx::Rect & old_damage)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())));
68 }
69 
UpdateBufferDamage(const gfx::Rect & damage)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);
78 }
79 
SwapBuffers(const gfx::Rect & 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);
88   }
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;
94 }
95 
Reshape(const gfx::Size & size,float scale_factor)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;
101 
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);
107 
108   FreeAllSurfaces();
109 }
110 
PageFlipComplete()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();
115   }
116 }
117 
FreeAllSurfaces()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();
123   }
124   for (size_t i = 0; i < available_surfaces_.size(); i++)
125     FreeSurface(&available_surfaces_[i]);
126   available_surfaces_.clear();
127 }
128 
FreeSurface(AllocatedSurface * surface)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_--;
139   }
140 }
141 
GetNextSurface()142 BufferQueue::AllocatedSurface BufferQueue::GetNextSurface() {
143   if (!available_surfaces_.empty()) {
144     AllocatedSurface surface = available_surfaces_.back();
145     available_surfaces_.pop_back();
146     return surface;
147   }
148 
149   unsigned int texture = 0;
150   gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
151   gl->GenTextures(1, &texture);
152   if (!texture)
153     return AllocatedSurface();
154 
155   // We don't want to allow anything more than triple buffering.
156   DCHECK_LT(allocated_count_, 4U);
157 
158   unsigned int id = gl->CreateImageCHROMIUM(
159       size_.width(),
160       size_.height(),
161       internalformat_,
162       GL_IMAGE_SCANOUT_CHROMIUM);
163   if (!id) {
164     LOG(ERROR) << "Failed to allocate backing CreateImageCHROMIUM surface";
165     gl->DeleteTextures(1, &texture);
166     return AllocatedSurface();
167   }
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_));
172 }
173 
174 }  // namespace content
175