[M49_2623] Chromium upversion to m49_2623 branch.
[platform/framework/web/chromium-efl.git] / tizen_src / chromium_impl / content / browser / renderer_host / context_factory_efl.cc
1 // Copyright 2015 Samsung Electronics. 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/renderer_host/context_factory_efl.h"
6
7 #include "base/bind.h"
8 #include "base/cancelable_callback.h"
9 #include "base/memory/ref_counted.h"
10 #include "base/thread_task_runner_handle.h"
11 #include "base/threading/simple_thread.h"
12 #include "build/tizen_version.h"
13 #include "cc/blink/context_provider_web_context.h"
14 #include "cc/output/gl_frame_data.h"
15 #include "cc/output/compositor_frame.h"
16 #include "cc/output/output_surface.h"
17 #include "cc/output/output_surface_client.h"
18 #include "cc/raster/single_thread_task_graph_runner.h"
19 #include "cc/resources/resource_format.h"
20 #include "cc/resources/resource_provider.h"
21 #include "cc/surfaces/surface_id_allocator.h"
22 #include "cc/raster/task_graph_runner.h"
23 #include "cc/resources/transferable_resource.h"
24 #include "content/public/common/content_switches.h"
25 #include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
26 #include "content/browser/gpu/gpu_surface_tracker.h"
27 #include "content/browser/renderer_host/render_widget_host_impl.h"
28 #include "content/browser/gpu/browser_gpu_channel_host_factory.h"
29 #include "content/browser/gpu/browser_gpu_channel_host_factory.h"
30 #if defined(TIZEN_DISABLE_GPU_THREAD)
31 #include "content/browser/gpu/gpu_data_manager_impl.h"
32 #endif
33 #include "content/common/gpu/gpu_process_launch_causes.h"
34 #include "content/common/gpu/client/command_buffer_proxy_impl.h"
35 #include "content/common/gpu/client/context_provider_command_buffer.h"
36 #include "content/common/host_shared_bitmap_manager.h"
37 #include "ui/gl/gl_shared_context_efl.h"
38 #include "gpu/command_buffer/client/context_support.h"
39 #include "gpu/command_buffer/client/gles2_interface.h"
40 #include "ui/compositor/reflector.h"
41
42 using gpu::gles2::GLES2Interface;
43
44 namespace {
45
46 #if defined(TIZEN_DISABLE_GPU_THREAD)
47 class NativeOutputSurfaceEfl : public cc::OutputSurface {
48  public:
49   NativeOutputSurfaceEfl(
50       const scoped_refptr<cc::ContextProvider>& context_provider)
51       : cc::OutputSurface(context_provider),
52         swap_buffers_completion_callback_(
53             base::Bind(&NativeOutputSurfaceEfl::OnSwapBuffersCompleted,
54                        base::Unretained(this))) {
55     capabilities_.max_frames_pending = 1;
56     capabilities_.uses_default_gl_framebuffer = false;
57     capabilities_.adjust_deadline_for_parent = false;
58   }
59
60   virtual ~NativeOutputSurfaceEfl() {
61   }
62
63   void Reshape(const gfx::Size& size, float scale_factor) {
64     if (size == surface_size_)
65       return;
66
67     surface_size_ = size;
68     device_scale_factor_ = scale_factor;
69   }
70
71   void BindFramebuffer() {
72   }
73
74   void OnSwapAck(scoped_ptr<cc::GLFrameData> gl_frame_data) {
75     client_->DidSwapBuffersComplete();
76   }
77
78   virtual void SwapBuffers(cc::CompositorFrame* frame) override {
79     // Using glFinish call instead of glFlush it fixes black screen issue with
80     // static pages and IE Fish page. (black screen issue was seen on Tizen TV
81     context_provider_->ContextGL()->Flush();
82
83     uint32 sync_point =
84         context_provider_->ContextGL()->InsertSyncPointCHROMIUM();
85
86     frame->gl_frame_data->sync_token = gpu::SyncToken(sync_point);
87
88     base::Closure closure =
89         base::Bind(&NativeOutputSurfaceEfl::OnSwapAck, base::Unretained(this),
90                    base::Passed(&frame->gl_frame_data));
91
92     context_provider()->ContextSupport()->SignalSyncPoint(sync_point, closure);
93
94     client_->DidSwapBuffers();
95   }
96
97   virtual bool BindToClient(cc::OutputSurfaceClient* client) override {
98     if (!OutputSurface::BindToClient(client))
99       return false;
100     GetCommandBufferProxy()->SetSwapBuffersCompletionCallback(
101         swap_buffers_completion_callback_.callback());
102     return true;
103   }
104
105   size_t GetNumAcksPending() {
106     return 0;
107   }
108
109  private:
110   content::CommandBufferProxyImpl* GetCommandBufferProxy() {
111     content::ContextProviderCommandBuffer* provider_command_buffer =
112         static_cast<content::ContextProviderCommandBuffer*>(
113             context_provider_.get());
114     content::CommandBufferProxyImpl* command_buffer_proxy =
115         provider_command_buffer->GetCommandBufferProxy();
116     DCHECK(command_buffer_proxy);
117     return command_buffer_proxy;
118   }
119
120   void OnSwapBuffersCompleted(
121       const std::vector<ui::LatencyInfo>& latency_info) {
122     content::RenderWidgetHostImpl::CompositorFrameDrawn(latency_info);
123     OutputSurface::OnSwapBuffersComplete();
124   }
125   base::CancelableCallback<void(const std::vector<ui::LatencyInfo>&)>
126       swap_buffers_completion_callback_;
127 };
128 #endif
129
130 // TODO(venu.musham): Move this class into separate file.
131 class MailboxOutputSurfaceEfl : public cc::OutputSurface {
132  public:
133   MailboxOutputSurfaceEfl(
134       const scoped_refptr<cc::ContextProvider>& context_provider,
135       base::WeakPtr<ui::ContextFactoryEfl> context_factory_efl,
136       cc::ResourceFormat format)
137       : cc::OutputSurface(context_provider),
138         swap_buffers_completion_callback_(
139             base::Bind(&MailboxOutputSurfaceEfl::OnSwapBuffersCompleted,
140                        base::Unretained(this))),
141         context_factory_efl_(context_factory_efl),
142         fbo_(0),
143         is_backbuffer_discarded_(false),
144         texture_upload_pending_(false),
145         format_(format) {
146     capabilities_.max_frames_pending = 1;
147     capabilities_.uses_default_gl_framebuffer = false;
148     capabilities_.adjust_deadline_for_parent = false;
149   }
150
151   virtual ~MailboxOutputSurfaceEfl() {}
152
153   void DetachFromClient() override {
154     DiscardBackbuffer();
155     while (!pending_textures_.empty()) {
156       if (pending_textures_.front().texture_id) {
157         context_provider_->ContextGL()->DeleteTextures(
158             1, &pending_textures_.front().texture_id);
159       }
160       pending_textures_.pop_front();
161     }
162     cc::OutputSurface::DetachFromClient();
163   }
164   virtual void EnsureBackbuffer() override {
165     is_backbuffer_discarded_ = false;
166
167     GLES2Interface* gl = context_provider_->ContextGL();
168
169     if (!current_backing_.texture_id) {
170       // Find a texture of matching size to recycle.
171       while (!returned_textures_.empty()) {
172         TransferableFrame& texture = returned_textures_.front();
173         if (texture.size == surface_size_) {
174           current_backing_ = texture;
175           if (current_backing_.sync_token.HasData())
176             gl->WaitSyncTokenCHROMIUM(
177                 current_backing_.sync_token.GetConstData());
178           returned_textures_.pop();
179           break;
180         }
181
182         gl->DeleteTextures(1, &texture.texture_id);
183         returned_textures_.pop();
184       }
185
186       if (!current_backing_.texture_id) {
187         gl->GenTextures(1, &current_backing_.texture_id);
188         current_backing_.size = surface_size_;
189         gl->BindTexture(GL_TEXTURE_2D, current_backing_.texture_id);
190         gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
191         gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
192         gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
193         gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
194         gl->TexImage2D(GL_TEXTURE_2D, 0, GLInternalFormat(format_),
195                        surface_size_.width(), surface_size_.height(), 0,
196                        GLDataFormat(format_), GLDataType(format_), NULL);
197         gl->GenMailboxCHROMIUM(current_backing_.mailbox.name);
198         gl->ProduceTextureCHROMIUM(GL_TEXTURE_2D,
199                                    current_backing_.mailbox.name);
200         texture_upload_pending_ = true;
201       }
202     }
203   }
204
205   virtual void DiscardBackbuffer() override {
206     is_backbuffer_discarded_ = true;
207
208     GLES2Interface* gl = context_provider_->ContextGL();
209
210     if (current_backing_.texture_id) {
211       gl->DeleteTextures(1, &current_backing_.texture_id);
212       current_backing_ = TransferableFrame();
213     }
214
215     while (!returned_textures_.empty()) {
216       const TransferableFrame& frame = returned_textures_.front();
217       gl->DeleteTextures(1, &frame.texture_id);
218       returned_textures_.pop();
219     }
220
221     if (fbo_) {
222       gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_);
223       gl->DeleteFramebuffers(1, &fbo_);
224       fbo_ = 0;
225     }
226   }
227
228   void Reshape(const gfx::Size& size, float scale_factor) {
229     if (size == surface_size_)
230       return;
231
232     surface_size_ = size;
233     device_scale_factor_ = scale_factor;
234     DiscardBackbuffer();
235     EnsureBackbuffer();
236   }
237
238   void BindFramebuffer() {
239     EnsureBackbuffer();
240     DCHECK(current_backing_.texture_id);
241
242     GLES2Interface* gl = context_provider_->ContextGL();
243
244     if (!fbo_)
245       gl->GenFramebuffers(1, &fbo_);
246     gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_);
247     gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
248                              GL_TEXTURE_2D, current_backing_.texture_id, 0);
249   }
250
251   void DrawTexture(scoped_ptr<cc::GLFrameData> gl_frame_data) {
252     // Draw texture on RWHV
253     if (gl_frame_data) {
254       context_factory_efl_->GetFrameFromMailbox(&gl_frame_data->mailbox,
255                                                 surface_size_);
256     }
257   }
258
259   void OnSwapAck(scoped_ptr<cc::GLFrameData> gl_frame_data) {
260     // Ignore message if it's a stale one coming from a different output surface
261     // (e.g. after a lost context).
262     if (!gl_frame_data->mailbox.IsZero()) {
263       DCHECK(!gl_frame_data->size.IsEmpty());
264       // The browser could be returning the oldest or any other pending texture
265       // if it decided to skip a frame.
266       std::deque<TransferableFrame>::iterator it;
267       for (it = pending_textures_.begin(); it != pending_textures_.end();
268            it++) {
269         DCHECK(!it->mailbox.IsZero());
270         if (!memcmp(it->mailbox.name, gl_frame_data->mailbox.name,
271                     sizeof(it->mailbox.name))) {
272           DCHECK(it->size == gl_frame_data->size);
273           break;
274         }
275       }
276       DCHECK(it != pending_textures_.end());
277       it->sync_token = gl_frame_data->sync_token;
278
279       if (!is_backbuffer_discarded_) {
280         returned_textures_.push(*it);
281       } else {
282         context_provider_->ContextGL()->DeleteTextures(1, &it->texture_id);
283       }
284
285       pending_textures_.erase(it);
286     } else {
287       DCHECK(!pending_textures_.empty());
288       // The browser always keeps one texture as the frontbuffer.
289       // If it does not return a mailbox, it discarded the frontbuffer which is
290       // the oldest texture we sent.
291       uint32_t texture_id = pending_textures_.front().texture_id;
292       if (texture_id)
293         context_provider_->ContextGL()->DeleteTextures(1, &texture_id);
294       pending_textures_.pop_front();
295     }
296
297     if (gl_frame_data) {
298       base::Closure closure =
299           base::Bind(&MailboxOutputSurfaceEfl::DrawTexture,
300                      base::Unretained(this), base::Passed(&gl_frame_data));
301       base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, closure);
302     }
303     client_->DidSwapBuffersComplete();
304   }
305
306   virtual void SwapBuffers(cc::CompositorFrame* frame) override {
307     DCHECK(frame->gl_frame_data);
308     DCHECK(!surface_size_.IsEmpty());
309     DCHECK(surface_size_ == current_backing_.size);
310     DCHECK(frame->gl_frame_data->size == current_backing_.size);
311     DCHECK(!current_backing_.mailbox.IsZero() ||
312            context_provider_->ContextGL()->GetGraphicsResetStatusKHR() !=
313                GL_NO_ERROR);
314
315     frame->gl_frame_data->mailbox = current_backing_.mailbox;
316
317     // Using glFinish call instead of glFlush, fixes black screen issue with
318     // static pages and IE Fish page.
319
320     // Black screen issue is seen on page in Tizen 2.4 product TV.
321 #if TIZEN_VERSION_EQ(2,4,0) && defined(OS_TIZEN_TV)
322     context_provider_->ContextGL()->Finish();
323 #else
324     if (texture_upload_pending_) {
325       context_provider_->ContextGL()->Finish();
326       texture_upload_pending_ = false;
327     } else {
328       context_provider_->ContextGL()->Flush();
329     }
330 #endif
331
332     uint32_t sync_point =
333         context_provider_->ContextGL()->InsertSyncPointCHROMIUM();
334
335     frame->gl_frame_data->sync_token = gpu::SyncToken(sync_point);
336
337     base::Closure closure =
338         base::Bind(&MailboxOutputSurfaceEfl::OnSwapAck, base::Unretained(this),
339                    base::Passed(&frame->gl_frame_data));
340
341     context_provider()->ContextSupport()->SignalSyncPoint(sync_point, closure);
342
343     client_->DidSwapBuffers();
344
345     pending_textures_.push_back(current_backing_);
346     current_backing_ = TransferableFrame();
347   }
348
349   virtual bool BindToClient(cc::OutputSurfaceClient* client) override {
350     if (!OutputSurface::BindToClient(client))
351       return false;
352     GetCommandBufferProxy()->SetSwapBuffersCompletionCallback(
353         swap_buffers_completion_callback_.callback());
354     return true;
355   }
356
357   size_t GetNumAcksPending() {
358     DCHECK(pending_textures_.size());
359     return pending_textures_.size() - 1;
360   }
361
362  private:
363   struct TransferableFrame {
364     TransferableFrame() : texture_id(0) {}
365
366     TransferableFrame(uint32_t texture_id,
367                       const gpu::Mailbox& mailbox,
368                       const gfx::Size size)
369         : texture_id(texture_id), mailbox(mailbox), size(size) {}
370
371     uint32_t texture_id;
372     gpu::Mailbox mailbox;
373     gfx::Size size;
374     gpu::SyncToken sync_token;
375   };
376   content::CommandBufferProxyImpl* GetCommandBufferProxy() {
377     content::ContextProviderCommandBuffer* provider_command_buffer =
378         static_cast<content::ContextProviderCommandBuffer*>(
379             context_provider_.get());
380     content::CommandBufferProxyImpl* command_buffer_proxy =
381         provider_command_buffer->GetCommandBufferProxy();
382     DCHECK(command_buffer_proxy);
383     return command_buffer_proxy;
384   }
385
386   void OnSwapBuffersCompleted(
387       const std::vector<ui::LatencyInfo>& latency_info,
388       gfx::SwapResult result) {
389     content::RenderWidgetHostImpl::CompositorFrameDrawn(latency_info);
390     OutputSurface::OnSwapBuffersComplete();
391   }
392   base::CancelableCallback<void(const std::vector<ui::LatencyInfo>&,
393                                 gfx::SwapResult)>
394       swap_buffers_completion_callback_;
395
396   base::WeakPtr<ui::ContextFactoryEfl> context_factory_efl_;
397
398   TransferableFrame current_backing_;
399   std::deque<TransferableFrame> pending_textures_;
400   std::queue<TransferableFrame> returned_textures_;
401
402   uint32_t fbo_;
403   bool is_backbuffer_discarded_;
404   bool texture_upload_pending_;
405   cc::ResourceFormat format_;
406 };
407 }  // namespace
408
409 namespace content {
410
411 static scoped_ptr<WebGraphicsContext3DCommandBufferImpl>
412 CreateGpuProcessViewContext(
413     const scoped_refptr<GpuChannelHost>& gpu_channel_host,
414     const blink::WebGraphicsContext3D::Attributes attributes,
415     int surface_id) {
416   DCHECK(gpu_channel_host.get());
417
418   GURL url("chrome://gpu/Compositor::createContext3D");
419   bool lose_context_when_out_of_memory = true;
420   return make_scoped_ptr(new WebGraphicsContext3DCommandBufferImpl(
421       surface_id, url, gpu_channel_host.get(), attributes,
422       lose_context_when_out_of_memory,
423       WebGraphicsContext3DCommandBufferImpl::SharedMemoryLimits(), NULL));
424 }
425 }  // namespace content
426
427 namespace ui {
428 namespace {
429
430 class FakeReflector : public Reflector {
431  public:
432   FakeReflector() {}
433   ~FakeReflector() override {}
434   void OnMirroringCompositorResized() override {}
435   void AddMirroringLayer(Layer* layer) override {}
436   void RemoveMirroringLayer(Layer* layer) override {}
437 };
438
439 class SingleThreadTaskGraphRunner : public cc::SingleThreadTaskGraphRunner {
440  public:
441   SingleThreadTaskGraphRunner() {
442     Start("CompositorTileWorker1", base::SimpleThread::Options());
443   }
444
445   ~SingleThreadTaskGraphRunner() override { Shutdown(); }
446 };
447 base::LazyInstance<SingleThreadTaskGraphRunner> g_task_graph_runner = LAZY_INSTANCE_INITIALIZER;
448
449 }
450
451
452 ContextFactoryEfl::ContextFactoryEfl(content::ContextFactoryDelegate* delegate)
453     : delegate_(delegate),
454       next_surface_id_namespace_(1),
455       schedule_draw_factory_(this) {
456 }
457
458 void ContextFactoryEfl::GetFrameFromMailbox(gpu::Mailbox* mailbox,
459                                             gfx::Size size) {
460   delegate_->GetTextureFromMailbox(mailbox, size);
461 }
462
463 void ContextFactoryEfl::CreateOutputSurface(base::WeakPtr<Compositor> compositor) {
464   blink::WebGraphicsContext3D::Attributes attrs;
465   attrs.depth = false;
466   attrs.stencil = false;
467   attrs.antialias = false;
468   attrs.shareResources = true;
469   attrs.noAutomaticFlushes = true;
470
471   scoped_refptr<content::ContextProviderCommandBuffer> context_provider;
472   content::BrowserGpuChannelHostFactory* factory =
473       content::BrowserGpuChannelHostFactory::instance();
474   content::CauseForGpuLaunch cause = content::
475       CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE;
476   scoped_refptr<content::GpuChannelHost> gpu_channel_host(
477       factory->EstablishGpuChannelSync(cause));
478   if (gpu_channel_host.get() && !gpu_channel_host->IsLost()) {
479     context_provider = content::ContextProviderCommandBuffer::Create(
480         CreateGpuProcessViewContext(gpu_channel_host, attrs, 0),
481         content::BROWSER_COMPOSITOR_ONSCREEN_CONTEXT);
482   }
483   if (!context_provider.get()) {
484     LOG(ERROR) << "Failed to create 3D context for compositor.";
485     compositor->SetOutputSurface(scoped_ptr<cc::OutputSurface>());
486   }
487
488   cc::ResourceFormat format = cc::RGBA_8888;
489
490 #if defined(TIZEN_DISABLE_GPU_THREAD)
491   if (content::GpuDataManagerImpl::GetInstance()->GpuThreadDisabled()) {
492     compositor->SetOutputSurface(make_scoped_ptr(new NativeOutputSurfaceEfl(
493         context_provider)));
494   } else {
495     compositor->SetOutputSurface(make_scoped_ptr(new MailboxOutputSurfaceEfl(
496         context_provider, schedule_draw_factory_.GetWeakPtr(), format)));
497   }
498 #else
499   compositor->SetOutputSurface(make_scoped_ptr(new MailboxOutputSurfaceEfl(
500       context_provider, schedule_draw_factory_.GetWeakPtr(), format)));
501 #endif
502 }
503
504 scoped_ptr<Reflector> ContextFactoryEfl::CreateReflector(
505     Compositor* mirrored_compositor,
506     Layer* mirroring_layer) {
507   return make_scoped_ptr(new FakeReflector);
508 }
509
510 void ContextFactoryEfl::RemoveReflector(Reflector* reflector) {
511 }
512
513 void ContextFactoryEfl::OnLostMainThreadSharedContextInsideCallback() {
514 }
515
516 scoped_refptr<cc::ContextProvider>
517 ContextFactoryEfl::SharedMainThreadContextProvider() {
518   if (shared_main_thread_contexts_.get())
519     return shared_main_thread_contexts_;
520
521   blink::WebGraphicsContext3D::Attributes attrs;
522   attrs.depth = false;
523   attrs.stencil = false;
524   attrs.antialias = false;
525   attrs.shareResources = true;
526   attrs.noAutomaticFlushes = true;
527
528   scoped_refptr<content::ContextProviderCommandBuffer> context_provider;
529   content::BrowserGpuChannelHostFactory* factory =
530       content::BrowserGpuChannelHostFactory::instance();
531   content::CauseForGpuLaunch cause = content::
532       CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE;
533   scoped_refptr<content::GpuChannelHost> gpu_channel_host(
534       factory->EstablishGpuChannelSync(cause));
535   if (gpu_channel_host.get() && !gpu_channel_host->IsLost()) {
536   shared_main_thread_contexts_ = content::ContextProviderCommandBuffer::Create(
537         CreateGpuProcessViewContext(gpu_channel_host, attrs, 0),
538         content::BROWSER_OFFSCREEN_MAINTHREAD_CONTEXT);
539   }
540
541   if (!shared_main_thread_contexts_->BindToCurrentThread())
542     shared_main_thread_contexts_ = NULL;
543   return shared_main_thread_contexts_;
544 }
545
546 void ContextFactoryEfl::RemoveCompositor(Compositor* compositor) {
547 }
548
549 bool ContextFactoryEfl::DoesCreateTestContexts() {
550   return false;
551 }
552
553 uint32_t ContextFactoryEfl::GetImageTextureTarget(gfx::BufferFormat format,
554                                                 gfx::BufferUsage usage) {
555   return GL_TEXTURE_2D;
556 }
557
558 cc::SharedBitmapManager* ContextFactoryEfl::GetSharedBitmapManager() {
559   return content::HostSharedBitmapManager::current();
560 }
561
562 gpu::GpuMemoryBufferManager* ContextFactoryEfl::GetGpuMemoryBufferManager() {
563   return content::BrowserGpuMemoryBufferManager::current();
564 }
565
566 cc::TaskGraphRunner* ContextFactoryEfl::GetTaskGraphRunner() {
567   return g_task_graph_runner.Pointer();
568 }
569
570 scoped_ptr<cc::SurfaceIdAllocator>
571 ContextFactoryEfl::CreateSurfaceIdAllocator() {
572   return make_scoped_ptr(
573       new cc::SurfaceIdAllocator(next_surface_id_namespace_++));
574 }
575
576 }  // namespace ui