blob: 37e6eaedc2ea0c115e19b4c83c062670c41d77e8 [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "cc/test/test_context_provider.h"
#include <stddef.h>
#include <stdint.h>
#include <set>
#include <vector>
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "cc/output/context_cache_controller.h"
#include "cc/test/test_gles2_interface.h"
#include "cc/test/test_web_graphics_context_3d.h"
#include "third_party/skia/include/gpu/GrContext.h"
#include "third_party/skia/include/gpu/gl/GrGLInterface.h"
namespace cc {
// static
scoped_refptr<TestContextProvider> TestContextProvider::Create() {
return new TestContextProvider(base::MakeUnique<TestContextSupport>(),
base::MakeUnique<TestGLES2Interface>(),
TestWebGraphicsContext3D::Create());
}
// static
scoped_refptr<TestContextProvider> TestContextProvider::CreateWorker() {
scoped_refptr<TestContextProvider> worker_context_provider(
new TestContextProvider(base::MakeUnique<TestContextSupport>(),
base::MakeUnique<TestGLES2Interface>(),
TestWebGraphicsContext3D::Create()));
// Worker contexts are bound to the thread they are created on.
if (!worker_context_provider->BindToCurrentThread())
return nullptr;
return worker_context_provider;
}
// static
scoped_refptr<TestContextProvider> TestContextProvider::Create(
std::unique_ptr<TestWebGraphicsContext3D> context) {
DCHECK(context);
return new TestContextProvider(base::MakeUnique<TestContextSupport>(),
base::MakeUnique<TestGLES2Interface>(),
std::move(context));
}
// static
scoped_refptr<TestContextProvider> TestContextProvider::Create(
std::unique_ptr<TestGLES2Interface> gl) {
DCHECK(gl);
return new TestContextProvider(base::MakeUnique<TestContextSupport>(),
std::move(gl),
TestWebGraphicsContext3D::Create());
}
// static
scoped_refptr<TestContextProvider> TestContextProvider::Create(
std::unique_ptr<TestWebGraphicsContext3D> context,
std::unique_ptr<TestContextSupport> support) {
DCHECK(context);
DCHECK(support);
return new TestContextProvider(std::move(support),
base::MakeUnique<TestGLES2Interface>(),
std::move(context));
}
TestContextProvider::TestContextProvider(
std::unique_ptr<TestContextSupport> support,
std::unique_ptr<TestGLES2Interface> gl,
std::unique_ptr<TestWebGraphicsContext3D> context)
: support_(std::move(support)),
context3d_(std::move(context)),
context_gl_(std::move(gl)),
weak_ptr_factory_(this) {
DCHECK(main_thread_checker_.CalledOnValidThread());
DCHECK(context3d_);
DCHECK(context_gl_);
context_thread_checker_.DetachFromThread();
context_gl_->set_test_context(context3d_.get());
context3d_->set_test_support(support_.get());
// Just pass nullptr to the ContextCacheController for its task runner. Idle
// handling is tested directly in ContextCacheController's unittests, and
// isn't needed here.
cache_controller_.reset(new ContextCacheController(support_.get(), nullptr));
}
TestContextProvider::~TestContextProvider() {
DCHECK(main_thread_checker_.CalledOnValidThread() ||
context_thread_checker_.CalledOnValidThread());
}
bool TestContextProvider::BindToCurrentThread() {
// This is called on the thread the context will be used.
DCHECK(context_thread_checker_.CalledOnValidThread());
if (bound_)
return true;
if (context_gl_->GetGraphicsResetStatusKHR() != GL_NO_ERROR) {
return false;
}
bound_ = true;
context3d_->set_context_lost_callback(
base::Bind(&TestContextProvider::OnLostContext,
base::Unretained(this)));
return true;
}
void TestContextProvider::DetachFromThread() {
context_thread_checker_.DetachFromThread();
}
gpu::Capabilities TestContextProvider::ContextCapabilities() {
DCHECK(bound_);
DCHECK(context_thread_checker_.CalledOnValidThread());
return context3d_->test_capabilities();
}
gpu::gles2::GLES2Interface* TestContextProvider::ContextGL() {
DCHECK(context3d_);
DCHECK(bound_);
DCHECK(context_thread_checker_.CalledOnValidThread());
return context_gl_.get();
}
gpu::ContextSupport* TestContextProvider::ContextSupport() {
return support();
}
class GrContext* TestContextProvider::GrContext() {
DCHECK(bound_);
DCHECK(context_thread_checker_.CalledOnValidThread());
if (gr_context_)
return gr_context_.get();
sk_sp<const GrGLInterface> gl_interface(GrGLCreateNullInterface());
gr_context_ = sk_sp<::GrContext>(GrContext::Create(
kOpenGL_GrBackend,
reinterpret_cast<GrBackendContext>(gl_interface.get())));
cache_controller_->SetGrContext(gr_context_.get());
// If GlContext is already lost, also abandon the new GrContext.
if (ContextGL()->GetGraphicsResetStatusKHR() != GL_NO_ERROR)
gr_context_->abandonContext();
return gr_context_.get();
}
ContextCacheController* TestContextProvider::CacheController() {
DCHECK(context_thread_checker_.CalledOnValidThread());
return cache_controller_.get();
}
void TestContextProvider::InvalidateGrContext(uint32_t state) {
DCHECK(bound_);
DCHECK(context_thread_checker_.CalledOnValidThread());
if (gr_context_)
gr_context_.get()->resetContext(state);
}
base::Lock* TestContextProvider::GetLock() {
return &context_lock_;
}
void TestContextProvider::OnLostContext() {
DCHECK(context_thread_checker_.CalledOnValidThread());
if (!lost_context_callback_.is_null())
lost_context_callback_.Run();
if (gr_context_)
gr_context_->abandonContext();
}
TestWebGraphicsContext3D* TestContextProvider::TestContext3d() {
DCHECK(bound_);
DCHECK(context_thread_checker_.CalledOnValidThread());
return context3d_.get();
}
TestWebGraphicsContext3D* TestContextProvider::UnboundTestContext3d() {
return context3d_.get();
}
void TestContextProvider::SetLostContextCallback(
const LostContextCallback& cb) {
DCHECK(context_thread_checker_.CalledOnValidThread());
DCHECK(lost_context_callback_.is_null() || cb.is_null());
lost_context_callback_ = cb;
}
} // namespace cc