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.
5 #include "content/browser/renderer_host/context_factory_efl.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"
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"
42 using gpu::gles2::GLES2Interface;
46 #if defined(TIZEN_DISABLE_GPU_THREAD)
47 class NativeOutputSurfaceEfl : public cc::OutputSurface {
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;
60 virtual ~NativeOutputSurfaceEfl() {
63 void Reshape(const gfx::Size& size, float scale_factor) {
64 if (size == surface_size_)
68 device_scale_factor_ = scale_factor;
71 void BindFramebuffer() {
74 void OnSwapAck(scoped_ptr<cc::GLFrameData> gl_frame_data) {
75 client_->DidSwapBuffersComplete();
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();
84 context_provider_->ContextGL()->InsertSyncPointCHROMIUM();
86 frame->gl_frame_data->sync_token = gpu::SyncToken(sync_point);
88 base::Closure closure =
89 base::Bind(&NativeOutputSurfaceEfl::OnSwapAck, base::Unretained(this),
90 base::Passed(&frame->gl_frame_data));
92 context_provider()->ContextSupport()->SignalSyncPoint(sync_point, closure);
94 client_->DidSwapBuffers();
97 virtual bool BindToClient(cc::OutputSurfaceClient* client) override {
98 if (!OutputSurface::BindToClient(client))
100 GetCommandBufferProxy()->SetSwapBuffersCompletionCallback(
101 swap_buffers_completion_callback_.callback());
105 size_t GetNumAcksPending() {
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;
120 void OnSwapBuffersCompleted(
121 const std::vector<ui::LatencyInfo>& latency_info) {
122 content::RenderWidgetHostImpl::CompositorFrameDrawn(latency_info);
123 OutputSurface::OnSwapBuffersComplete();
125 base::CancelableCallback<void(const std::vector<ui::LatencyInfo>&)>
126 swap_buffers_completion_callback_;
130 // TODO(venu.musham): Move this class into separate file.
131 class MailboxOutputSurfaceEfl : public cc::OutputSurface {
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),
143 is_backbuffer_discarded_(false),
144 texture_upload_pending_(false),
146 capabilities_.max_frames_pending = 1;
147 capabilities_.uses_default_gl_framebuffer = false;
148 capabilities_.adjust_deadline_for_parent = false;
151 virtual ~MailboxOutputSurfaceEfl() {}
153 void DetachFromClient() override {
155 while (!pending_textures_.empty()) {
156 if (pending_textures_.front().texture_id) {
157 context_provider_->ContextGL()->DeleteTextures(
158 1, &pending_textures_.front().texture_id);
160 pending_textures_.pop_front();
162 cc::OutputSurface::DetachFromClient();
164 virtual void EnsureBackbuffer() override {
165 is_backbuffer_discarded_ = false;
167 GLES2Interface* gl = context_provider_->ContextGL();
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();
182 gl->DeleteTextures(1, &texture.texture_id);
183 returned_textures_.pop();
186 if (!current_backing_.texture_id) {
187 gl->GenTextures(1, ¤t_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;
205 virtual void DiscardBackbuffer() override {
206 is_backbuffer_discarded_ = true;
208 GLES2Interface* gl = context_provider_->ContextGL();
210 if (current_backing_.texture_id) {
211 gl->DeleteTextures(1, ¤t_backing_.texture_id);
212 current_backing_ = TransferableFrame();
215 while (!returned_textures_.empty()) {
216 const TransferableFrame& frame = returned_textures_.front();
217 gl->DeleteTextures(1, &frame.texture_id);
218 returned_textures_.pop();
222 gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_);
223 gl->DeleteFramebuffers(1, &fbo_);
228 void Reshape(const gfx::Size& size, float scale_factor) {
229 if (size == surface_size_)
232 surface_size_ = size;
233 device_scale_factor_ = scale_factor;
238 void BindFramebuffer() {
240 DCHECK(current_backing_.texture_id);
242 GLES2Interface* gl = context_provider_->ContextGL();
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);
251 void DrawTexture(scoped_ptr<cc::GLFrameData> gl_frame_data) {
252 // Draw texture on RWHV
254 context_factory_efl_->GetFrameFromMailbox(&gl_frame_data->mailbox,
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();
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);
276 DCHECK(it != pending_textures_.end());
277 it->sync_token = gl_frame_data->sync_token;
279 if (!is_backbuffer_discarded_) {
280 returned_textures_.push(*it);
282 context_provider_->ContextGL()->DeleteTextures(1, &it->texture_id);
285 pending_textures_.erase(it);
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;
293 context_provider_->ContextGL()->DeleteTextures(1, &texture_id);
294 pending_textures_.pop_front();
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);
303 client_->DidSwapBuffersComplete();
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() !=
315 frame->gl_frame_data->mailbox = current_backing_.mailbox;
317 // Using glFinish call instead of glFlush, fixes black screen issue with
318 // static pages and IE Fish page.
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();
324 if (texture_upload_pending_) {
325 context_provider_->ContextGL()->Finish();
326 texture_upload_pending_ = false;
328 context_provider_->ContextGL()->Flush();
332 uint32_t sync_point =
333 context_provider_->ContextGL()->InsertSyncPointCHROMIUM();
335 frame->gl_frame_data->sync_token = gpu::SyncToken(sync_point);
337 base::Closure closure =
338 base::Bind(&MailboxOutputSurfaceEfl::OnSwapAck, base::Unretained(this),
339 base::Passed(&frame->gl_frame_data));
341 context_provider()->ContextSupport()->SignalSyncPoint(sync_point, closure);
343 client_->DidSwapBuffers();
345 pending_textures_.push_back(current_backing_);
346 current_backing_ = TransferableFrame();
349 virtual bool BindToClient(cc::OutputSurfaceClient* client) override {
350 if (!OutputSurface::BindToClient(client))
352 GetCommandBufferProxy()->SetSwapBuffersCompletionCallback(
353 swap_buffers_completion_callback_.callback());
357 size_t GetNumAcksPending() {
358 DCHECK(pending_textures_.size());
359 return pending_textures_.size() - 1;
363 struct TransferableFrame {
364 TransferableFrame() : texture_id(0) {}
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) {}
372 gpu::Mailbox mailbox;
374 gpu::SyncToken sync_token;
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;
386 void OnSwapBuffersCompleted(
387 const std::vector<ui::LatencyInfo>& latency_info,
388 gfx::SwapResult result) {
389 content::RenderWidgetHostImpl::CompositorFrameDrawn(latency_info);
390 OutputSurface::OnSwapBuffersComplete();
392 base::CancelableCallback<void(const std::vector<ui::LatencyInfo>&,
394 swap_buffers_completion_callback_;
396 base::WeakPtr<ui::ContextFactoryEfl> context_factory_efl_;
398 TransferableFrame current_backing_;
399 std::deque<TransferableFrame> pending_textures_;
400 std::queue<TransferableFrame> returned_textures_;
403 bool is_backbuffer_discarded_;
404 bool texture_upload_pending_;
405 cc::ResourceFormat format_;
411 static scoped_ptr<WebGraphicsContext3DCommandBufferImpl>
412 CreateGpuProcessViewContext(
413 const scoped_refptr<GpuChannelHost>& gpu_channel_host,
414 const blink::WebGraphicsContext3D::Attributes attributes,
416 DCHECK(gpu_channel_host.get());
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));
425 } // namespace content
430 class FakeReflector : public Reflector {
433 ~FakeReflector() override {}
434 void OnMirroringCompositorResized() override {}
435 void AddMirroringLayer(Layer* layer) override {}
436 void RemoveMirroringLayer(Layer* layer) override {}
439 class SingleThreadTaskGraphRunner : public cc::SingleThreadTaskGraphRunner {
441 SingleThreadTaskGraphRunner() {
442 Start("CompositorTileWorker1", base::SimpleThread::Options());
445 ~SingleThreadTaskGraphRunner() override { Shutdown(); }
447 base::LazyInstance<SingleThreadTaskGraphRunner> g_task_graph_runner = LAZY_INSTANCE_INITIALIZER;
452 ContextFactoryEfl::ContextFactoryEfl(content::ContextFactoryDelegate* delegate)
453 : delegate_(delegate),
454 next_surface_id_namespace_(1),
455 schedule_draw_factory_(this) {
458 void ContextFactoryEfl::GetFrameFromMailbox(gpu::Mailbox* mailbox,
460 delegate_->GetTextureFromMailbox(mailbox, size);
463 void ContextFactoryEfl::CreateOutputSurface(base::WeakPtr<Compositor> compositor) {
464 blink::WebGraphicsContext3D::Attributes attrs;
466 attrs.stencil = false;
467 attrs.antialias = false;
468 attrs.shareResources = true;
469 attrs.noAutomaticFlushes = true;
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);
483 if (!context_provider.get()) {
484 LOG(ERROR) << "Failed to create 3D context for compositor.";
485 compositor->SetOutputSurface(scoped_ptr<cc::OutputSurface>());
488 cc::ResourceFormat format = cc::RGBA_8888;
490 #if defined(TIZEN_DISABLE_GPU_THREAD)
491 if (content::GpuDataManagerImpl::GetInstance()->GpuThreadDisabled()) {
492 compositor->SetOutputSurface(make_scoped_ptr(new NativeOutputSurfaceEfl(
495 compositor->SetOutputSurface(make_scoped_ptr(new MailboxOutputSurfaceEfl(
496 context_provider, schedule_draw_factory_.GetWeakPtr(), format)));
499 compositor->SetOutputSurface(make_scoped_ptr(new MailboxOutputSurfaceEfl(
500 context_provider, schedule_draw_factory_.GetWeakPtr(), format)));
504 scoped_ptr<Reflector> ContextFactoryEfl::CreateReflector(
505 Compositor* mirrored_compositor,
506 Layer* mirroring_layer) {
507 return make_scoped_ptr(new FakeReflector);
510 void ContextFactoryEfl::RemoveReflector(Reflector* reflector) {
513 void ContextFactoryEfl::OnLostMainThreadSharedContextInsideCallback() {
516 scoped_refptr<cc::ContextProvider>
517 ContextFactoryEfl::SharedMainThreadContextProvider() {
518 if (shared_main_thread_contexts_.get())
519 return shared_main_thread_contexts_;
521 blink::WebGraphicsContext3D::Attributes attrs;
523 attrs.stencil = false;
524 attrs.antialias = false;
525 attrs.shareResources = true;
526 attrs.noAutomaticFlushes = true;
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);
541 if (!shared_main_thread_contexts_->BindToCurrentThread())
542 shared_main_thread_contexts_ = NULL;
543 return shared_main_thread_contexts_;
546 void ContextFactoryEfl::RemoveCompositor(Compositor* compositor) {
549 bool ContextFactoryEfl::DoesCreateTestContexts() {
553 uint32_t ContextFactoryEfl::GetImageTextureTarget(gfx::BufferFormat format,
554 gfx::BufferUsage usage) {
555 return GL_TEXTURE_2D;
558 cc::SharedBitmapManager* ContextFactoryEfl::GetSharedBitmapManager() {
559 return content::HostSharedBitmapManager::current();
562 gpu::GpuMemoryBufferManager* ContextFactoryEfl::GetGpuMemoryBufferManager() {
563 return content::BrowserGpuMemoryBufferManager::current();
566 cc::TaskGraphRunner* ContextFactoryEfl::GetTaskGraphRunner() {
567 return g_task_graph_runner.Pointer();
570 scoped_ptr<cc::SurfaceIdAllocator>
571 ContextFactoryEfl::CreateSurfaceIdAllocator() {
572 return make_scoped_ptr(
573 new cc::SurfaceIdAllocator(next_surface_id_namespace_++));