1// Copyright (c) 2012 The Chromium Authors. 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 "ui/gl/gl_context.h"
6
7#include "base/android/sys_utils.h"
8#include "base/logging.h"
9#include "base/memory/ref_counted.h"
10#include "base/sys_info.h"
11#include "ui/gl/gl_bindings.h"
12#include "ui/gl/gl_context_egl.h"
13#include "ui/gl/gl_context_stub.h"
14#include "ui/gl/gl_implementation.h"
15#include "ui/gl/gl_surface.h"
16
17namespace gfx {
18
19namespace {
20
21// Used to render into an already current context+surface,
22// that we do not have ownership of (draw callback).
23// TODO(boliu): Make this inherit from GLContextEGL.
24class GLNonOwnedContext : public GLContextReal {
25 public:
26  GLNonOwnedContext(GLShareGroup* share_group);
27
28  // Implement GLContext.
29  virtual bool Initialize(GLSurface* compatible_surface,
30                          GpuPreference gpu_preference) OVERRIDE;
31  virtual void Destroy() OVERRIDE {}
32  virtual bool MakeCurrent(GLSurface* surface) OVERRIDE;
33  virtual void ReleaseCurrent(GLSurface* surface) OVERRIDE {}
34  virtual bool IsCurrent(GLSurface* surface) OVERRIDE { return true; }
35  virtual void* GetHandle() OVERRIDE { return NULL; }
36  virtual void SetSwapInterval(int interval) OVERRIDE {}
37  virtual std::string GetExtensions() OVERRIDE;
38
39 protected:
40  virtual ~GLNonOwnedContext() {}
41
42 private:
43  DISALLOW_COPY_AND_ASSIGN(GLNonOwnedContext);
44
45  EGLDisplay display_;
46};
47
48GLNonOwnedContext::GLNonOwnedContext(GLShareGroup* share_group)
49  : GLContextReal(share_group), display_(NULL) {}
50
51bool GLNonOwnedContext::Initialize(GLSurface* compatible_surface,
52                        GpuPreference gpu_preference) {
53  display_ = eglGetDisplay(EGL_DEFAULT_DISPLAY);
54  return true;
55}
56
57bool GLNonOwnedContext::MakeCurrent(GLSurface* surface) {
58  SetCurrent(surface);
59  SetRealGLApi();
60  return true;
61}
62
63std::string GLNonOwnedContext::GetExtensions() {
64  const char* extensions = eglQueryString(display_, EGL_EXTENSIONS);
65  if (!extensions)
66    return GLContext::GetExtensions();
67
68  return GLContext::GetExtensions() + " " + extensions;
69}
70
71}  // anonymous namespace
72
73// static
74scoped_refptr<GLContext> GLContext::CreateGLContext(
75    GLShareGroup* share_group,
76    GLSurface* compatible_surface,
77    GpuPreference gpu_preference) {
78  if (GetGLImplementation() == kGLImplementationMockGL)
79    return scoped_refptr<GLContext>(new GLContextStub());
80
81  scoped_refptr<GLContext> context;
82  if (compatible_surface->GetHandle())
83    context = new GLContextEGL(share_group);
84  else
85    context = new GLNonOwnedContext(share_group);
86  if (!context->Initialize(compatible_surface, gpu_preference))
87    return NULL;
88  return context;
89}
90
91bool GLContextEGL::GetTotalGpuMemory(size_t* bytes) {
92  DCHECK(bytes);
93  *bytes = 0;
94
95  // We can't query available GPU memory from the system on Android.
96  // Physical memory is also mis-reported sometimes (eg. Nexus 10 reports
97  // 1262MB when it actually has 2GB, while Razr M has 1GB but only reports
98  // 128MB java heap size). First we estimate physical memory using both.
99  size_t dalvik_mb = base::SysInfo::DalvikHeapSizeMB();
100  size_t physical_mb = base::SysInfo::AmountOfPhysicalMemoryMB();
101  size_t physical_memory_mb = 0;
102  if (dalvik_mb >= 256)
103    physical_memory_mb = dalvik_mb * 4;
104  else
105    physical_memory_mb = std::max(dalvik_mb * 4,
106                                  (physical_mb * 4) / 3);
107
108  // Now we take a default of 1/8th of memory on high-memory devices,
109  // and gradually scale that back for low-memory devices (to be nicer
110  // to other apps so they don't get killed). Examples:
111  // Nexus 4/10(2GB)    256MB
112  // Droid Razr M(1GB)  91MB
113  // Galaxy Nexus(1GB)  85MB
114  // Xoom(1GB)          85MB
115  // Nexus S(low-end)   8MB
116  static size_t limit_bytes = 0;
117  if (limit_bytes == 0) {
118    if (!base::android::SysUtils::IsLowEndDevice()) {
119      if (physical_memory_mb >= 1536)
120        limit_bytes = physical_memory_mb / 8;
121      else if (physical_memory_mb >= 1152)
122        limit_bytes = physical_memory_mb / 10;
123      else if (physical_memory_mb >= 768)
124        limit_bytes = physical_memory_mb / 12;
125      else
126        limit_bytes = physical_memory_mb / 16;
127    } else {
128      // Low-end devices have 512MB or less memory by definition
129      // so we hard code the limit rather than relying on the heuristics
130      // above. Low-end devices use 4444 textures so we can use a lower limit.
131      limit_bytes = 8;
132    }
133    limit_bytes = limit_bytes * 1024 * 1024;
134  }
135  *bytes = limit_bytes;
136  return true;
137}
138
139}
140