Commit cafa295e authored by epenner@chromium.org's avatar epenner@chromium.org

gpu: Fix Vivante's "hisilicon" GPUs

This fixes "Hisilicon" GPUs, which is an instance of a
Vivante's GPU design. This involves enabling virtual
contexts, since they don't support share-groups, and further
adds a work-around for switching surfaces. Without the work-
around the view surface "inherits" the size of the last
bound surface (which for Chrome tends to be a 1x1 pbuffer)
resulting in a black screen. The following steps "repair"
the view surface every time it is made current:

    - Make it current.
    - Bind the default frame-buffer.
    - Make it not current.
    - Destroy/recreate it from the native handle.
    - Make it current again.

NOTE: The "Recreate" function is added to surface because
the Destroy/Initialize may be intercepted or modified by
wrapper surface classes. Recreate is similar to resize,
which after being forwarded by a wrapper can call
Destroy/Initialize on the 'real' surface.

BUG=179250, 229643
NOTRY=true

No try, since it's Android only and already tested.

Review URL: https://chromiumcodereview.appspot.com/13140006

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@194737 0039d316-1c4b-4281-b951-d872f2087c98
parent 1270ea67
......@@ -507,6 +507,18 @@ void GpuCommandBufferStub::OnInitialize(
return;
}
// TODO(epenner): If we can initialize the feature-info earlier,
// this code can be removed and done only during surface creation.
// This code is only needed for the very first surface, which is
// created before the ContextGroup is initialized.
if (context_group_->feature_info()->workarounds()
.makecurrent_recreates_surfaces) {
// This only works with virtual contexts!
DCHECK(CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableVirtualGLContexts));
surface_->SetRecreateOnMakeCurrent(true);
}
if (CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableGPUServiceLogging)) {
decoder_->set_log_commands(true);
......
......@@ -29,6 +29,15 @@ scoped_refptr<gfx::GLSurface> ImageTransportSurface::CreateNativeSurface(
if (!initialize_success)
return scoped_refptr<gfx::GLSurface>();
if (stub->decoder()
->GetContextGroup()
->feature_info()
->workarounds()
.makecurrent_recreates_surfaces) {
static_cast<gfx::NativeViewGLSurfaceEGL*>
(surface.get())->SetRecreateOnMakeCurrent(true);
}
return scoped_refptr<gfx::GLSurface>(new PassThroughImageTransportSurface(
manager, stub, surface.get(), false));
}
......
......@@ -74,6 +74,7 @@ bool CollectBasicGraphicsInfo(content::GPUInfo* gpu_info) {
bool is_arm = vendor.find("arm") != std::string::npos;
bool is_qualcomm = vendor.find("qualcomm") != std::string::npos;
bool is_mali_t604 = is_arm && renderer.find("mali-t604") != std::string::npos;
bool is_hisilicon = vendor.find("hisilicon") != std::string::npos;
base::android::BuildInfo* build_info =
base::android::BuildInfo::GetInstance();
......@@ -91,7 +92,8 @@ bool CollectBasicGraphicsInfo(content::GPUInfo* gpu_info) {
// IMG: avoid context switching perf problems, crashes with share groups
// Mali-T604: http://crbug.com/154715
// QualComm, NVIDIA: Crashes with share groups
if (is_img || is_mali_t604 || is_nexus7 || (is_qualcomm && sdk_int != 16)) {
if (is_hisilicon || is_img || is_mali_t604 || is_nexus7
|| (is_qualcomm && sdk_int != 16)) {
CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableVirtualGLContexts);
}
......
......@@ -191,6 +191,7 @@ void FeatureInfo::AddFeatures(const CommandLine& command_line) {
bool is_qualcomm = false;
bool is_imagination = false;
bool is_arm = false;
bool is_hisilicon = false;
const char* gl_strings[2];
gl_strings[0] = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
gl_strings[1] = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
......@@ -208,6 +209,7 @@ void FeatureInfo::AddFeatures(const CommandLine& command_line) {
is_qualcomm |= string_set.Contains("qualcomm");
is_imagination |= string_set.Contains("imagination");
is_arm |= string_set.Contains("arm");
is_hisilicon |= string_set.Contains("hisilicon");
}
}
......@@ -221,6 +223,9 @@ void FeatureInfo::AddFeatures(const CommandLine& command_line) {
workarounds_.flush_on_context_switch = true;
workarounds_.delete_instead_of_resize_fbo = true;
}
if (is_hisilicon) {
workarounds_.makecurrent_recreates_surfaces = true;
}
#if defined(OS_MACOSX)
workarounds_.needs_offscreen_buffer_workaround = is_nvidia;
workarounds_.needs_glsl_built_in_function_emulation = is_amd;
......
......@@ -28,6 +28,8 @@
exit_on_context_lost) \
GPU_OP(FLUSH_ON_CONTEXT_SWITCH, \
flush_on_context_switch) \
GPU_OP(MAKECURRENT_RECREATES_SURFACES, \
makecurrent_recreates_surfaces) \
GPU_OP(MAX_CUBE_MAP_TEXTURE_SIZE_LIMIT_1024, \
max_cube_map_texture_size_limit_1024) \
GPU_OP(MAX_CUBE_MAP_TEXTURE_SIZE_LIMIT_4096, \
......
......@@ -112,6 +112,9 @@ bool GLContextEGL::MakeCurrent(GLSurface* surface) {
return false;
}
if (!RecreateSurfaceIfNeeded(surface))
return false;
if (!surface->OnMakeCurrent(this)) {
LOG(ERROR) << "Could not make current.";
return false;
......@@ -121,6 +124,39 @@ bool GLContextEGL::MakeCurrent(GLSurface* surface) {
return true;
}
bool GLContextEGL::RecreateSurfaceIfNeeded(GLSurface* surface) {
if (!surface || !surface->RecreateOnMakeCurrent())
return true;
// This is specifically needed for Vivante GPU's on Android.
// A native view surface will not be configured correctly
// unless we do all of the following steps after making the
// surface current.
GLint fbo = 0;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fbo);
glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
eglMakeCurrent(display_,
EGL_NO_SURFACE,
EGL_NO_SURFACE,
EGL_NO_CONTEXT);
if (!surface->Recreate()) {
LOG(ERROR) << "Failed to recreate surface";
return false;
}
if (!eglMakeCurrent(display_,
surface->GetHandle(),
surface->GetHandle(),
context_)) {
LOG(ERROR) << "eglMakeCurrent failed with error "
<< GetLastEGLErrorString();
return false;
}
glBindFramebufferEXT(GL_FRAMEBUFFER, fbo);
return true;
}
void GLContextEGL::ReleaseCurrent(GLSurface* surface) {
if (!IsCurrent(surface))
return;
......
......@@ -36,6 +36,8 @@ class GLContextEGL : public GLContext {
virtual bool WasAllocatedUsingRobustnessExtension() OVERRIDE;
virtual bool GetTotalGpuMemory(size_t* bytes) OVERRIDE;
bool RecreateSurfaceIfNeeded(GLSurface* surface);
protected:
virtual ~GLContextEGL();
......
......@@ -84,6 +84,11 @@ bool GLSurface::Resize(const gfx::Size& size) {
return false;
}
bool GLSurface::Recreate() {
NOTIMPLEMENTED();
return false;
}
bool GLSurface::DeferDraws() {
return false;
}
......@@ -145,6 +150,13 @@ VSyncProvider* GLSurface::GetVSyncProvider() {
return NULL;
}
bool GLSurface::RecreateOnMakeCurrent() {
return false;
}
void GLSurface::SetRecreateOnMakeCurrent(bool recreate) {
}
GLSurface* GLSurface::GetCurrent() {
return current_surface_.Pointer()->Get();
}
......@@ -185,6 +197,10 @@ bool GLSurfaceAdapter::Resize(const gfx::Size& size) {
return surface_->Resize(size);
}
bool GLSurfaceAdapter::Recreate() {
return surface_->Recreate();
}
bool GLSurfaceAdapter::DeferDraws() {
return surface_->DeferDraws();
}
......@@ -249,6 +265,14 @@ VSyncProvider* GLSurfaceAdapter::GetVSyncProvider() {
return surface_->GetVSyncProvider();
}
bool GLSurfaceAdapter::RecreateOnMakeCurrent() {
return surface_->RecreateOnMakeCurrent();
}
void GLSurfaceAdapter::SetRecreateOnMakeCurrent(bool recreate) {
surface_->SetRecreateOnMakeCurrent(recreate);
}
GLSurfaceAdapter::~GLSurfaceAdapter() {}
} // namespace gfx
......@@ -39,6 +39,9 @@ class GL_EXPORT GLSurface : public base::RefCounted<GLSurface> {
virtual bool Resize(const gfx::Size& size);
// Recreate the surface without changing the size.
virtual bool Recreate();
// Unschedule the GpuScheduler and return true to abort the processing of
// a GL draw call to this surface and defer it until the GpuScheduler is
// rescheduled.
......@@ -102,6 +105,11 @@ class GL_EXPORT GLSurface : public base::RefCounted<GLSurface> {
// of screen refresh. If unavailable, returns NULL.
virtual VSyncProvider* GetVSyncProvider();
// Certain surfaces need to be destroyed and recreated
// every time they are made the current surface.
virtual bool RecreateOnMakeCurrent();
virtual void SetRecreateOnMakeCurrent(bool recreate);
// Create a GL surface that renders directly to a view.
static scoped_refptr<GLSurface> CreateViewGLSurface(
bool software,
......@@ -137,6 +145,7 @@ class GL_EXPORT GLSurfaceAdapter : public GLSurface {
virtual bool Initialize() OVERRIDE;
virtual void Destroy() OVERRIDE;
virtual bool Resize(const gfx::Size& size) OVERRIDE;
virtual bool Recreate() OVERRIDE;
virtual bool DeferDraws() OVERRIDE;
virtual bool IsOffscreen() OVERRIDE;
virtual bool SwapBuffers() OVERRIDE;
......@@ -153,6 +162,8 @@ class GL_EXPORT GLSurfaceAdapter : public GLSurface {
virtual void* GetConfig() OVERRIDE;
virtual unsigned GetFormat() OVERRIDE;
virtual VSyncProvider* GetVSyncProvider() OVERRIDE;
virtual bool RecreateOnMakeCurrent() OVERRIDE;
virtual void SetRecreateOnMakeCurrent(bool recreate) OVERRIDE;
GLSurface* surface() const { return surface_.get(); }
......
......@@ -399,18 +399,30 @@ bool NativeViewGLSurfaceEGL::Resize(const gfx::Size& size) {
if (was_current)
current_context->ReleaseCurrent(this);
Destroy();
Recreate();
if (was_current)
return current_context->MakeCurrent(this);
return true;
}
bool NativeViewGLSurfaceEGL::Recreate() {
Destroy();
if (!Initialize()) {
LOG(ERROR) << "Failed to resize pbuffer.";
LOG(ERROR) << "Failed to create surface.";
return false;
}
if (was_current)
return current_context->MakeCurrent(this);
return true;
}
bool NativeViewGLSurfaceEGL::RecreateOnMakeCurrent() {
return recreate_on_make_current_;
}
void NativeViewGLSurfaceEGL::SetRecreateOnMakeCurrent(bool recreate) {
recreate_on_make_current_ = recreate;
}
EGLSurface NativeViewGLSurfaceEGL::GetHandle() {
return surface_;
}
......
......@@ -60,6 +60,7 @@ class GL_EXPORT NativeViewGLSurfaceEGL : public GLSurfaceEGL {
virtual bool Initialize() OVERRIDE;
virtual void Destroy() OVERRIDE;
virtual bool Resize(const gfx::Size& size) OVERRIDE;
virtual bool Recreate() OVERRIDE;
virtual bool IsOffscreen() OVERRIDE;
virtual bool SwapBuffers() OVERRIDE;
virtual gfx::Size GetSize() OVERRIDE;
......@@ -67,6 +68,8 @@ class GL_EXPORT NativeViewGLSurfaceEGL : public GLSurfaceEGL {
virtual std::string GetExtensions() OVERRIDE;
virtual bool PostSubBuffer(int x, int y, int width, int height) OVERRIDE;
virtual VSyncProvider* GetVSyncProvider() OVERRIDE;
virtual bool RecreateOnMakeCurrent() OVERRIDE;
virtual void SetRecreateOnMakeCurrent(bool recreate) OVERRIDE;
protected:
virtual ~NativeViewGLSurfaceEGL();
......@@ -77,6 +80,7 @@ class GL_EXPORT NativeViewGLSurfaceEGL : public GLSurfaceEGL {
EGLSurface surface_;
bool supports_post_sub_buffer_;
EGLConfig config_;
bool recreate_on_make_current_;
scoped_ptr<VSyncProvider> vsync_provider_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment