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"
20 BufferQueue::BufferQueue(
21 scoped_refptr
<cc::ContextProvider
> context_provider
,
22 unsigned int internalformat
,
24 BrowserGpuMemoryBufferManager
* gpu_memory_buffer_manager
,
26 : context_provider_(context_provider
),
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() {
38 gpu::gles2::GLES2Interface
* gl
= context_provider_
->ContextGL();
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
,
57 current_surface_
.texture
,
62 void BufferQueue::CopyBufferDamage(int texture
,
64 const gfx::Rect
& new_damage
,
65 const gfx::Rect
& old_damage
) {
66 gl_helper_
->CopySubBufferDamage(
69 SkRegion(SkIRect::MakeXYWH(new_damage
.x(),
72 new_damage
.height())),
73 SkRegion(SkIRect::MakeXYWH(old_damage
.x(),
76 old_damage
.height())));
79 void BufferQueue::UpdateBufferDamage(const gfx::Rect
& damage
) {
80 for (size_t i
= 0; i
< available_surfaces_
.size(); i
++)
81 available_surfaces_
[i
].damage
.Union(damage
);
82 for (std::deque
<AllocatedSurface
>::iterator it
=
83 in_flight_surfaces_
.begin();
84 it
!= in_flight_surfaces_
.end();
86 it
->damage
.Union(damage
);
89 void BufferQueue::SwapBuffers(const gfx::Rect
& damage
) {
90 if (damage
!= gfx::Rect(size_
)) {
91 // We must have a frame available to copy from.
92 DCHECK(!in_flight_surfaces_
.empty());
93 CopyBufferDamage(current_surface_
.texture
,
94 in_flight_surfaces_
.back().texture
,
96 current_surface_
.damage
);
98 UpdateBufferDamage(damage
);
99 current_surface_
.damage
= gfx::Rect();
100 in_flight_surfaces_
.push_back(current_surface_
);
101 current_surface_
.texture
= 0;
102 current_surface_
.image
= 0;
103 // Some things reset the framebuffer (CopySubBufferDamage, some GLRenderer
104 // paths), so ensure we restore it here.
105 context_provider_
->ContextGL()->BindFramebuffer(GL_FRAMEBUFFER
, fbo_
);
108 void BufferQueue::Reshape(const gfx::Size
& size
, float scale_factor
) {
109 DCHECK(!current_surface_
.texture
);
114 // TODO: add stencil buffer when needed.
115 gpu::gles2::GLES2Interface
* gl
= context_provider_
->ContextGL();
116 gl
->BindFramebuffer(GL_FRAMEBUFFER
, fbo_
);
117 gl
->FramebufferTexture2D(
118 GL_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
, GL_TEXTURE_2D
, 0, 0);
123 void BufferQueue::PageFlipComplete() {
124 if (in_flight_surfaces_
.size() > 1) {
125 available_surfaces_
.push_back(in_flight_surfaces_
.front());
126 in_flight_surfaces_
.pop_front();
130 void BufferQueue::FreeAllSurfaces() {
131 FreeSurface(¤t_surface_
);
132 while (!in_flight_surfaces_
.empty()) {
133 FreeSurface(&in_flight_surfaces_
.front());
134 in_flight_surfaces_
.pop_front();
136 for (size_t i
= 0; i
< available_surfaces_
.size(); i
++)
137 FreeSurface(&available_surfaces_
[i
]);
138 available_surfaces_
.clear();
141 void BufferQueue::FreeSurface(AllocatedSurface
* surface
) {
142 if (surface
->texture
) {
143 gpu::gles2::GLES2Interface
* gl
= context_provider_
->ContextGL();
144 gl
->BindTexture(GL_TEXTURE_2D
, surface
->texture
);
145 gl
->ReleaseTexImage2DCHROMIUM(GL_TEXTURE_2D
, surface
->image
);
146 gl
->DeleteTextures(1, &surface
->texture
);
147 gl
->DestroyImageCHROMIUM(surface
->image
);
149 surface
->texture
= 0;
154 BufferQueue::AllocatedSurface
BufferQueue::GetNextSurface() {
155 if (!available_surfaces_
.empty()) {
156 AllocatedSurface surface
= available_surfaces_
.back();
157 available_surfaces_
.pop_back();
161 unsigned int texture
= 0;
162 gpu::gles2::GLES2Interface
* gl
= context_provider_
->ContextGL();
163 gl
->GenTextures(1, &texture
);
165 return AllocatedSurface();
167 // We don't want to allow anything more than triple buffering.
168 DCHECK_LT(allocated_count_
, 4U);
170 scoped_ptr
<gfx::GpuMemoryBuffer
> buffer(
171 gpu_memory_buffer_manager_
->AllocateGpuMemoryBufferForScanout(
172 size_
, gpu::ImageFactory::ImageFormatToGpuMemoryBufferFormat(
176 gl
->DeleteTextures(1, &texture
);
177 DLOG(ERROR
) << "Failed to allocate GPU memory buffer";
178 return AllocatedSurface();
181 unsigned int id
= gl
->CreateImageCHROMIUM(
182 buffer
->AsClientBuffer(), size_
.width(), size_
.height(), internalformat_
);
185 LOG(ERROR
) << "Failed to allocate backing image surface";
186 gl
->DeleteTextures(1, &texture
);
187 return AllocatedSurface();
190 gl
->BindTexture(GL_TEXTURE_2D
, texture
);
191 gl
->BindTexImage2DCHROMIUM(GL_TEXTURE_2D
, id
);
192 return AllocatedSurface(texture
, id
, gfx::Rect(size_
));
195 } // namespace content