1 // Copyright (c) 2012 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/renderer/gpu/mailbox_output_surface.h"
7 #include "base/logging.h"
8 #include "cc/output/compositor_frame.h"
9 #include "cc/output/compositor_frame_ack.h"
10 #include "cc/output/gl_frame_data.h"
11 #include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
12 #include "third_party/khronos/GLES2/gl2.h"
13 #include "third_party/khronos/GLES2/gl2ext.h"
15 using cc::CompositorFrame
;
16 using cc::GLFrameData
;
21 MailboxOutputSurface::MailboxOutputSurface(
23 WebGraphicsContext3DCommandBufferImpl
* context3D
,
24 cc::SoftwareOutputDevice
* software_device
)
25 : CompositorOutputSurface(routing_id
, context3D
, software_device
, true),
27 is_backbuffer_discarded_(false) {
28 pending_textures_
.push_back(TransferableFrame());
29 capabilities_
.max_frames_pending
= 1;
32 MailboxOutputSurface::~MailboxOutputSurface() {
34 while (!pending_textures_
.empty()) {
35 if (pending_textures_
.front().texture_id
)
36 context3d_
->deleteTexture(pending_textures_
.front().texture_id
);
37 pending_textures_
.pop_front();
41 void MailboxOutputSurface::EnsureBackbuffer() {
42 is_backbuffer_discarded_
= false;
44 if (!current_backing_
.texture_id
) {
45 // Find a texture of matching size to recycle.
46 while (!returned_textures_
.empty()) {
47 TransferableFrame
& texture
= returned_textures_
.front();
48 if (texture
.size
== surface_size_
) {
49 current_backing_
= texture
;
50 if (current_backing_
.sync_point
)
51 context3d_
->waitSyncPoint(current_backing_
.sync_point
);
52 returned_textures_
.pop();
56 context3d_
->deleteTexture(texture
.texture_id
);
57 returned_textures_
.pop();
60 if (!current_backing_
.texture_id
) {
61 current_backing_
.texture_id
= context3d_
->createTexture();
62 current_backing_
.size
= surface_size_
;
63 context3d_
->bindTexture(GL_TEXTURE_2D
, current_backing_
.texture_id
);
64 context3d_
->texParameteri(
65 GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
66 context3d_
->texParameteri(
67 GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
68 context3d_
->texParameteri(
69 GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
70 context3d_
->texParameteri(
71 GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
72 context3d_
->texImage2D(
73 GL_TEXTURE_2D
, 0, GL_RGBA
,
74 surface_size_
.width(), surface_size_
.height(), 0,
75 GL_RGBA
, GL_UNSIGNED_BYTE
, NULL
);
76 context3d_
->genMailboxCHROMIUM(current_backing_
.mailbox
.name
);
77 context3d_
->produceTextureCHROMIUM(
78 GL_TEXTURE_2D
, current_backing_
.mailbox
.name
);
83 void MailboxOutputSurface::DiscardBackbuffer() {
84 is_backbuffer_discarded_
= true;
86 if (current_backing_
.texture_id
) {
87 context3d_
->deleteTexture(current_backing_
.texture_id
);
88 current_backing_
= TransferableFrame();
91 while (!returned_textures_
.empty()) {
92 const TransferableFrame
& frame
= returned_textures_
.front();
93 context3d_
->deleteTexture(frame
.texture_id
);
94 returned_textures_
.pop();
98 context3d_
->bindFramebuffer(GL_FRAMEBUFFER
, fbo_
);
99 context3d_
->deleteFramebuffer(fbo_
);
104 void MailboxOutputSurface::Reshape(gfx::Size size
, float scale_factor
) {
105 if (size
== surface_size_
)
108 surface_size_
= size
;
109 device_scale_factor_
= scale_factor
;
114 void MailboxOutputSurface::BindFramebuffer() {
116 DCHECK(current_backing_
.texture_id
);
119 fbo_
= context3d_
->createFramebuffer();
120 context3d_
->bindFramebuffer(GL_FRAMEBUFFER
, fbo_
);
121 context3d_
->framebufferTexture2D(
122 GL_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
, GL_TEXTURE_2D
,
123 current_backing_
.texture_id
, 0);
126 void MailboxOutputSurface::OnSwapAck(const cc::CompositorFrameAck
& ack
) {
127 if (!ack
.gl_frame_data
->mailbox
.IsZero()) {
128 DCHECK(!ack
.gl_frame_data
->size
.IsEmpty());
129 // The browser could be returning the oldest or any other pending texture
130 // if it decided to skip a frame.
131 std::deque
<TransferableFrame
>::iterator it
;
132 for (it
= pending_textures_
.begin(); it
!= pending_textures_
.end(); it
++) {
133 DCHECK(!it
->mailbox
.IsZero());
134 if (!memcmp(it
->mailbox
.name
,
135 ack
.gl_frame_data
->mailbox
.name
,
136 sizeof(it
->mailbox
.name
))) {
137 DCHECK(it
->size
== ack
.gl_frame_data
->size
);
141 DCHECK(it
!= pending_textures_
.end());
142 it
->sync_point
= ack
.gl_frame_data
->sync_point
;
144 if (!is_backbuffer_discarded_
) {
145 returned_textures_
.push(*it
);
147 context3d_
->deleteTexture(it
->texture_id
);
150 pending_textures_
.erase(it
);
152 DCHECK(!pending_textures_
.empty());
153 // The browser always keeps one texture as the frontbuffer.
154 // If it does not return a mailbox, it discarded the frontbuffer which is
155 // the oldest texture we sent.
156 uint32 texture_id
= pending_textures_
.front().texture_id
;
158 context3d_
->deleteTexture(texture_id
);
159 pending_textures_
.pop_front();
161 CompositorOutputSurface::OnSwapAck(ack
);
164 void MailboxOutputSurface::SwapBuffers(cc::CompositorFrame
* frame
) {
165 DCHECK(frame
->gl_frame_data
);
166 DCHECK(!surface_size_
.IsEmpty());
167 DCHECK(surface_size_
== current_backing_
.size
);
168 DCHECK(frame
->gl_frame_data
->size
== current_backing_
.size
);
169 DCHECK(!current_backing_
.mailbox
.IsZero());
171 frame
->gl_frame_data
->mailbox
= current_backing_
.mailbox
;
173 frame
->gl_frame_data
->sync_point
= context3d_
->insertSyncPoint();
174 CompositorOutputSurface::SwapBuffers(frame
);
176 pending_textures_
.push_back(current_backing_
);
177 current_backing_
= TransferableFrame();
180 size_t MailboxOutputSurface::GetNumAcksPending() {
181 DCHECK(pending_textures_
.size());
182 return pending_textures_
.size() - 1;
185 } // namespace content