Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / content / renderer / gpu / mailbox_output_surface.cc
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.
4
5 #include "content/renderer/gpu/mailbox_output_surface.h"
6
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 "cc/resources/resource_provider.h"
12 #include "gpu/command_buffer/client/gles2_interface.h"
13 #include "third_party/khronos/GLES2/gl2.h"
14 #include "third_party/khronos/GLES2/gl2ext.h"
15
16 using cc::CompositorFrame;
17 using cc::GLFrameData;
18 using cc::ResourceProvider;
19 using gpu::Mailbox;
20 using gpu::gles2::GLES2Interface;
21
22 namespace content {
23
24 MailboxOutputSurface::MailboxOutputSurface(
25     int32 routing_id,
26     uint32 output_surface_id,
27     const scoped_refptr<ContextProviderCommandBuffer>& context_provider,
28     scoped_ptr<cc::SoftwareOutputDevice> software_device,
29     cc::ResourceFormat format)
30     : CompositorOutputSurface(routing_id,
31                               output_surface_id,
32                               context_provider,
33                               software_device.Pass(),
34                               true),
35       fbo_(0),
36       is_backbuffer_discarded_(false),
37       format_(format) {
38   pending_textures_.push_back(TransferableFrame());
39   capabilities_.max_frames_pending = 1;
40   capabilities_.uses_default_gl_framebuffer = false;
41 }
42
43 MailboxOutputSurface::~MailboxOutputSurface() {
44   DiscardBackbuffer();
45   while (!pending_textures_.empty()) {
46     if (pending_textures_.front().texture_id) {
47       context_provider_->ContextGL()->DeleteTextures(
48           1, &pending_textures_.front().texture_id);
49     }
50     pending_textures_.pop_front();
51   }
52 }
53
54 void MailboxOutputSurface::EnsureBackbuffer() {
55   is_backbuffer_discarded_ = false;
56
57   GLES2Interface* gl = context_provider_->ContextGL();
58
59   if (!current_backing_.texture_id) {
60     // Find a texture of matching size to recycle.
61     while (!returned_textures_.empty()) {
62       TransferableFrame& texture = returned_textures_.front();
63       if (texture.size == surface_size_) {
64         current_backing_ = texture;
65         if (current_backing_.sync_point)
66           gl->WaitSyncPointCHROMIUM(current_backing_.sync_point);
67         returned_textures_.pop();
68         break;
69       }
70
71       gl->DeleteTextures(1, &texture.texture_id);
72       returned_textures_.pop();
73     }
74
75     if (!current_backing_.texture_id) {
76       gl->GenTextures(1, &current_backing_.texture_id);
77       current_backing_.size = surface_size_;
78       gl->BindTexture(GL_TEXTURE_2D, current_backing_.texture_id);
79       gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
80       gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
81       gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
82       gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
83       gl->TexImage2D(GL_TEXTURE_2D,
84                      0,
85                      GLInternalFormat(format_),
86                      surface_size_.width(),
87                      surface_size_.height(),
88                      0,
89                      GLDataFormat(format_),
90                      GLDataType(format_),
91                      NULL);
92       gl->GenMailboxCHROMIUM(current_backing_.mailbox.name);
93       gl->ProduceTextureCHROMIUM(GL_TEXTURE_2D, current_backing_.mailbox.name);
94     }
95   }
96 }
97
98 void MailboxOutputSurface::DiscardBackbuffer() {
99   is_backbuffer_discarded_ = true;
100
101   GLES2Interface* gl = context_provider_->ContextGL();
102
103   if (current_backing_.texture_id) {
104     gl->DeleteTextures(1, &current_backing_.texture_id);
105     current_backing_ = TransferableFrame();
106   }
107
108   while (!returned_textures_.empty()) {
109     const TransferableFrame& frame = returned_textures_.front();
110     gl->DeleteTextures(1, &frame.texture_id);
111     returned_textures_.pop();
112   }
113
114   if (fbo_) {
115     gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_);
116     gl->DeleteFramebuffers(1, &fbo_);
117     fbo_ = 0;
118   }
119 }
120
121 void MailboxOutputSurface::Reshape(const gfx::Size& size, float scale_factor) {
122   if (size == surface_size_)
123     return;
124
125   surface_size_ = size;
126   device_scale_factor_ = scale_factor;
127   DiscardBackbuffer();
128   EnsureBackbuffer();
129 }
130
131 void MailboxOutputSurface::BindFramebuffer() {
132   EnsureBackbuffer();
133   DCHECK(current_backing_.texture_id);
134
135   GLES2Interface* gl = context_provider_->ContextGL();
136
137   if (!fbo_)
138     gl->GenFramebuffers(1, &fbo_);
139   gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_);
140   gl->FramebufferTexture2D(GL_FRAMEBUFFER,
141                            GL_COLOR_ATTACHMENT0,
142                            GL_TEXTURE_2D,
143                            current_backing_.texture_id,
144                            0);
145 }
146
147 void MailboxOutputSurface::OnSwapAck(uint32 output_surface_id,
148                                      const cc::CompositorFrameAck& ack) {
149   // Ignore message if it's a stale one coming from a different output surface
150   // (e.g. after a lost context).
151   if (output_surface_id != output_surface_id_) {
152     CompositorOutputSurface::OnSwapAck(output_surface_id, ack);
153     return;
154   }
155   if (!ack.gl_frame_data->mailbox.IsZero()) {
156     DCHECK(!ack.gl_frame_data->size.IsEmpty());
157     // The browser could be returning the oldest or any other pending texture
158     // if it decided to skip a frame.
159     std::deque<TransferableFrame>::iterator it;
160     for (it = pending_textures_.begin(); it != pending_textures_.end(); it++) {
161       DCHECK(!it->mailbox.IsZero());
162       if (!memcmp(it->mailbox.name,
163                   ack.gl_frame_data->mailbox.name,
164                   sizeof(it->mailbox.name))) {
165         DCHECK(it->size == ack.gl_frame_data->size);
166         break;
167       }
168     }
169     DCHECK(it != pending_textures_.end());
170     it->sync_point = ack.gl_frame_data->sync_point;
171
172     if (!is_backbuffer_discarded_) {
173       returned_textures_.push(*it);
174     } else {
175       context_provider_->ContextGL()->DeleteTextures(1, &it->texture_id);
176     }
177
178     pending_textures_.erase(it);
179   } else {
180     DCHECK(!pending_textures_.empty());
181     // The browser always keeps one texture as the frontbuffer.
182     // If it does not return a mailbox, it discarded the frontbuffer which is
183     // the oldest texture we sent.
184     uint32 texture_id = pending_textures_.front().texture_id;
185     if (texture_id)
186       context_provider_->ContextGL()->DeleteTextures(1, &texture_id);
187     pending_textures_.pop_front();
188   }
189   CompositorOutputSurface::OnSwapAck(output_surface_id, ack);
190 }
191
192 void MailboxOutputSurface::SwapBuffers(cc::CompositorFrame* frame) {
193   DCHECK(frame->gl_frame_data);
194   DCHECK(!surface_size_.IsEmpty());
195   DCHECK(surface_size_ == current_backing_.size);
196   DCHECK(frame->gl_frame_data->size == current_backing_.size);
197   DCHECK(!current_backing_.mailbox.IsZero() ||
198          context_provider_->IsContextLost());
199
200   frame->gl_frame_data->mailbox = current_backing_.mailbox;
201   context_provider_->ContextGL()->Flush();
202   frame->gl_frame_data->sync_point =
203       context_provider_->ContextGL()->InsertSyncPointCHROMIUM();
204   CompositorOutputSurface::SwapBuffers(frame);
205
206   pending_textures_.push_back(current_backing_);
207   current_backing_ = TransferableFrame();
208 }
209
210 size_t MailboxOutputSurface::GetNumAcksPending() {
211   DCHECK(pending_textures_.size());
212   return pending_textures_.size() - 1;
213 }
214
215 }  // namespace content