12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/common/gpu/client/context_provider_command_buffer.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch#include "base/callback_helpers.h"
890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "webkit/common/gpu/grcontext_for_webgraphicscontext3d.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace content {
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class ContextProviderCommandBuffer::LostContextCallbackProxy
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : public WebKit::WebGraphicsContext3D::WebGraphicsContextLostCallback {
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  explicit LostContextCallbackProxy(ContextProviderCommandBuffer* provider)
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : provider_(provider) {
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    provider_->context3d_->setContextLostCallback(this);
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  virtual ~LostContextCallbackProxy() {
217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    provider_->context3d_->setContextLostCallback(NULL);
227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void onContextLost() {
25fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch    provider_->OnLostContext();
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ContextProviderCommandBuffer* provider_;
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class ContextProviderCommandBuffer::MemoryAllocationCallbackProxy
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : public WebKit::WebGraphicsContext3D::
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          WebGraphicsMemoryAllocationChangedCallbackCHROMIUM {
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  explicit MemoryAllocationCallbackProxy(ContextProviderCommandBuffer* provider)
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : provider_(provider) {
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    provider_->context3d_->setMemoryAllocationChangedCallbackCHROMIUM(this);
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  virtual ~MemoryAllocationCallbackProxy() {
427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    provider_->context3d_->setMemoryAllocationChangedCallbackCHROMIUM(NULL);
437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void onMemoryAllocationChanged(
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      WebKit::WebGraphicsMemoryAllocation alloc) {
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    provider_->OnMemoryAllocationChanged(!!alloc.gpuResourceSizeInBytes);
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ContextProviderCommandBuffer* provider_;
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
54fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdochscoped_refptr<ContextProviderCommandBuffer>
55fb250657ef40d7500f20882d5c9909c1013367d3Ben MurdochContextProviderCommandBuffer::Create(const CreateCallback& create_callback) {
56fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch  scoped_refptr<ContextProviderCommandBuffer> provider =
57fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch      new ContextProviderCommandBuffer;
58fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch  if (!provider->InitializeOnMainThread(create_callback))
59fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch    return NULL;
60fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch  return provider;
61fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch}
62fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ContextProviderCommandBuffer::ContextProviderCommandBuffer()
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : leak_on_destroy_(false),
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      destroyed_(false) {
66fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch  DCHECK(main_thread_checker_.CalledOnValidThread());
67fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch  context_thread_checker_.DetachFromThread();
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ContextProviderCommandBuffer::~ContextProviderCommandBuffer() {
71fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch  DCHECK(main_thread_checker_.CalledOnValidThread() ||
72fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch         context_thread_checker_.CalledOnValidThread());
73fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::AutoLock lock(main_thread_lock_);
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (leak_on_destroy_) {
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    WebGraphicsContext3DCommandBufferImpl* context3d ALLOW_UNUSED =
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        context3d_.release();
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    webkit::gpu::GrContextForWebGraphicsContext3D* gr_context ALLOW_UNUSED =
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        gr_context_.release();
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
83fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdochbool ContextProviderCommandBuffer::InitializeOnMainThread(
84fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch    const CreateCallback& create_callback) {
85fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch  DCHECK(main_thread_checker_.CalledOnValidThread());
86fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!context3d_);
88fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch  DCHECK(!create_callback.is_null());
89fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch  context3d_ = create_callback.Run();
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return !!context3d_;
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ContextProviderCommandBuffer::BindToCurrentThread() {
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(context3d_);
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
96fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch  // This is called on the thread the context will be used.
97fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch  DCHECK(context_thread_checker_.CalledOnValidThread());
98fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (lost_context_callback_proxy_)
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!context3d_->makeContextCurrent())
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  lost_context_callback_proxy_.reset(new LostContextCallbackProxy(this));
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)WebGraphicsContext3DCommandBufferImpl*
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ContextProviderCommandBuffer::Context3d() {
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(context3d_);
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(lost_context_callback_proxy_);  // Is bound to thread.
113fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch  DCHECK(context_thread_checker_.CalledOnValidThread());
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return context3d_.get();
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class GrContext* ContextProviderCommandBuffer::GrContext() {
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(context3d_);
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(lost_context_callback_proxy_);  // Is bound to thread.
121fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch  DCHECK(context_thread_checker_.CalledOnValidThread());
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (gr_context_)
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return gr_context_->get();
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gr_context_.reset(
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      new webkit::gpu::GrContextForWebGraphicsContext3D(context3d_.get()));
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  memory_allocation_callback_proxy_.reset(
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      new MemoryAllocationCallbackProxy(this));
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return gr_context_->get();
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ContextProviderCommandBuffer::VerifyContexts() {
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(context3d_);
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(lost_context_callback_proxy_);  // Is bound to thread.
136fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch  DCHECK(context_thread_checker_.CalledOnValidThread());
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (context3d_->isContextLost())
139fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch    OnLostContext();
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
142fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdochvoid ContextProviderCommandBuffer::OnLostContext() {
143fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch  DCHECK(context_thread_checker_.CalledOnValidThread());
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  {
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::AutoLock lock(main_thread_lock_);
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (destroyed_)
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    destroyed_ = true;
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
150fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch  if (!lost_context_callback_.is_null())
151fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch    base::ResetAndReturn(&lost_context_callback_).Run();
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ContextProviderCommandBuffer::DestroyedOnMainThread() {
155fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch  DCHECK(main_thread_checker_.CalledOnValidThread());
156fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::AutoLock lock(main_thread_lock_);
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return destroyed_;
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
161fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdochvoid ContextProviderCommandBuffer::SetLostContextCallback(
162fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch    const LostContextCallback& lost_context_callback) {
163fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch  DCHECK(context_thread_checker_.CalledOnValidThread());
164fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch  DCHECK(lost_context_callback_.is_null());
165fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch  lost_context_callback_ = lost_context_callback;
166fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch}
167fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ContextProviderCommandBuffer::OnMemoryAllocationChanged(
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool nonzero_allocation) {
170fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch  DCHECK(context_thread_checker_.CalledOnValidThread());
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (gr_context_)
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    gr_context_->SetMemoryLimit(nonzero_allocation);
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace content
176