15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gl/gl_surface.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include <OpenGL/CGLRenderers.h>
8f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
9f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "base/basictypes.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/debug/trace_event.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
12f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "base/mac/mac_util.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gl/gl_bindings.h"
15f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "ui/gl/gl_context.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gl/gl_implementation.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gl/gl_surface_osmesa.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gl/gl_surface_stub.h"
19f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "ui/gl/gpu_switching_manager.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace gfx {
22f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)namespace {
23f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
24f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// A "no-op" surface. It is not required that a CGLContextObj have an
25f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// associated drawable (pbuffer or fullscreen context) in order to be
26f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// made current. Everywhere this surface type is used, we allocate an
27f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// FBO at the user level as the drawable of the associated context.
28f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)class GL_EXPORT NoOpGLSurface : public GLSurface {
29f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) public:
30f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  explicit NoOpGLSurface(const gfx::Size& size) : size_(size) {}
31f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
32f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Implement GLSurface.
33f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  virtual bool Initialize() OVERRIDE { return true; }
34f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  virtual void Destroy() OVERRIDE {}
35f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  virtual bool IsOffscreen() OVERRIDE { return true; }
36f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  virtual bool SwapBuffers() OVERRIDE {
37f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    NOTREACHED() << "Cannot call SwapBuffers on a NoOpGLSurface.";
38f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return false;
39f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
40f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  virtual gfx::Size GetSize() OVERRIDE { return size_; }
41f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  virtual void* GetHandle() OVERRIDE { return NULL; }
42f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  virtual void* GetDisplay() OVERRIDE { return NULL; }
43f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
44f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) protected:
45f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  virtual ~NoOpGLSurface() {}
46f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
47f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) private:
48f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  gfx::Size size_;
49f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
50f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(NoOpGLSurface);
51f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)};
52f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
53f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// static
54f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool InitializeOneOffForSandbox() {
55f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  static bool initialized = false;
56f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (initialized)
57f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return true;
58f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
59f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // This is called from the sandbox warmup code on Mac OS X.
60f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // GPU-related stuff is very slow without this, probably because
61f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // the sandbox prevents loading graphics drivers or some such.
62f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  std::vector<CGLPixelFormatAttribute> attribs;
63f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus()) {
64f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // Avoid switching to the discrete GPU just for this pixel
65f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // format selection.
66f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    attribs.push_back(kCGLPFAAllowOfflineRenderers);
67f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
68f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (GetGLImplementation() == kGLImplementationAppleGL) {
69f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    attribs.push_back(kCGLPFARendererID);
70f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    attribs.push_back(static_cast<CGLPixelFormatAttribute>(
71f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      kCGLRendererGenericFloatID));
72f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
73f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  attribs.push_back(static_cast<CGLPixelFormatAttribute>(0));
74f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
75f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  CGLPixelFormatObj format;
76f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  GLint num_pixel_formats;
77f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (CGLChoosePixelFormat(&attribs.front(),
78f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                           &format,
79f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                           &num_pixel_formats) != kCGLNoError) {
80f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    LOG(ERROR) << "Error choosing pixel format.";
81f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return false;
82f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
83f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!format) {
84f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    LOG(ERROR) << "format == 0.";
85f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return false;
86f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
87f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  CGLReleasePixelFormat(format);
88f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK_NE(num_pixel_formats, 0);
89f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  initialized = true;
90f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return true;
91f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
92f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
93f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}  // namespace
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GLSurface::InitializeOneOffInternal() {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (GetGLImplementation()) {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kGLImplementationDesktopGL:
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kGLImplementationAppleGL:
99f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      if (!InitializeOneOffForSandbox()) {
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        LOG(ERROR) << "GLSurfaceCGL::InitializeOneOff failed.";
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_refptr<GLSurface> GLSurface::CreateViewGLSurface(
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gfx::AcceleratedWidget window) {
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TRACE_EVENT0("gpu", "GLSurface::CreateViewGLSurface");
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (GetGLImplementation()) {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kGLImplementationDesktopGL:
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kGLImplementationAppleGL: {
116c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      NOTIMPLEMENTED() << "No onscreen support on Mac.";
117c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      return NULL;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    case kGLImplementationOSMesaGL: {
1201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      scoped_refptr<GLSurface> surface(new GLSurfaceOSMesaHeadless());
1211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      if (!surface->Initialize())
1221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        return NULL;
1231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      return surface;
1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kGLImplementationMockGL:
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return new GLSurfaceStub;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return NULL;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_refptr<GLSurface> GLSurface::CreateOffscreenGLSurface(
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const gfx::Size& size) {
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TRACE_EVENT0("gpu", "GLSurface::CreateOffscreenGLSurface");
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (GetGLImplementation()) {
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kGLImplementationOSMesaGL: {
13803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      scoped_refptr<GLSurface> surface(
13903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)          new GLSurfaceOSMesa(OSMesaSurfaceFormatRGBA, size));
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!surface->Initialize())
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return NULL;
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return surface;
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kGLImplementationDesktopGL:
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kGLImplementationAppleGL: {
147f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      scoped_refptr<GLSurface> surface(new NoOpGLSurface(size));
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!surface->Initialize())
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return NULL;
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return surface;
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kGLImplementationMockGL:
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return new GLSurfaceStub;
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return NULL;
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace gfx
162