Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 "content/browser/renderer_host/compositing_iosurface_mac.h" | |
| 6 | |
| 7 #include <OpenGL/OpenGL.h> | |
| 8 #include <vector> | |
| 9 | |
| 10 #include "base/command_line.h" | |
| 11 #include "base/debug/trace_event.h" | |
| 12 #include "content/browser/renderer_host/render_widget_host_view_mac.h" | |
| 13 #include "content/public/browser/browser_thread.h" | |
| 14 #include "ui/gfx/gl/gl_context.h" | |
| 15 #include "ui/gfx/gl/gl_switches.h" | |
| 16 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h" | |
| 17 #include "ui/gfx/surface/io_surface_support_mac.h" | |
| 18 | |
| 19 #ifdef NDEBUG | |
| 20 #define CHECK_GL_ERROR() | |
| 21 #else | |
| 22 #define CHECK_GL_ERROR() do { \ | |
| 23 GLenum gl_error = glGetError(); \ | |
| 24 LOG_IF(ERROR, gl_error != GL_NO_ERROR) << "GL Error :" << gl_error; \ | |
| 25 } while (0) | |
| 26 #endif | |
| 27 | |
| 28 CompositingIOSurfaceMac* CompositingIOSurfaceMac::Create() { | |
| 29 TRACE_EVENT0("browser", "CompositingIOSurfaceMac::Create"); | |
| 30 IOSurfaceSupport* io_surface_support = IOSurfaceSupport::Initialize(); | |
| 31 if (!io_surface_support) { | |
| 32 LOG(WARNING) << "No IOSurface support"; | |
| 33 return NULL; | |
| 34 } | |
| 35 | |
| 36 std::vector<NSOpenGLPixelFormatAttribute> attributes; | |
| 37 attributes.push_back(NSOpenGLPFADoubleBuffer); | |
| 38 // We don't need a depth buffer - try setting its size to 0... | |
| 39 attributes.push_back(NSOpenGLPFADepthSize); attributes.push_back(0); | |
| 40 if (gfx::GLContext::SupportsDualGpus()) | |
| 41 attributes.push_back(NSOpenGLPFAAllowOfflineRenderers); | |
| 42 attributes.push_back(0); | |
| 43 | |
| 44 scoped_nsobject<NSOpenGLPixelFormat> glPixelFormat( | |
| 45 [[NSOpenGLPixelFormat alloc] initWithAttributes:&attributes.front()]); | |
| 46 if (!glPixelFormat) { | |
| 47 LOG(ERROR) << "NSOpenGLPixelFormat initWithAttributes failed"; | |
| 48 return NULL; | |
| 49 } | |
| 50 | |
| 51 scoped_nsobject<NSOpenGLContext> glContext( | |
| 52 [[NSOpenGLContext alloc] initWithFormat:glPixelFormat | |
| 53 shareContext:nil]); | |
| 54 if (!glContext) { | |
| 55 LOG(ERROR) << "NSOpenGLContext initWithFormat failed"; | |
| 56 return NULL; | |
| 57 } | |
| 58 | |
| 59 // We "punch a hole" in the window, and have the WindowServer render the | |
| 60 // OpenGL surface underneath so we can draw over it. | |
| 61 GLint belowWindow = -1; | |
| 62 [glContext setValues:&belowWindow forParameter:NSOpenGLCPSurfaceOrder]; | |
| 63 | |
| 64 CGLContextObj cglContext = (CGLContextObj)[glContext CGLContextObj]; | |
| 65 if (!cglContext) { | |
| 66 LOG(ERROR) << "CGLContextObj failed"; | |
| 67 return NULL; | |
| 68 } | |
| 69 | |
| 70 // Draw at beam vsync. | |
| 71 GLint swapInterval; | |
| 72 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableGpuVsync)) | |
| 73 swapInterval = 0; | |
| 74 else | |
| 75 swapInterval = 1; | |
| 76 [glContext setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval]; | |
| 77 | |
| 78 return new CompositingIOSurfaceMac(io_surface_support, | |
| 79 glContext.release(), cglContext); | |
|
Ken Russell (switch to Gerrit)
2012/04/04 17:27:17
Indentation is off.
jbates
2012/04/04 19:21:50
Done.
| |
| 80 } | |
| 81 | |
| 82 CompositingIOSurfaceMac::CompositingIOSurfaceMac( | |
| 83 IOSurfaceSupport* io_surface_support, | |
| 84 NSOpenGLContext* glContext, | |
| 85 CGLContextObj cglContext) | |
| 86 : io_surface_support_(io_surface_support), | |
| 87 glContext_(glContext), | |
| 88 cglContext_(cglContext), | |
| 89 io_surface_handle_(0) { | |
| 90 } | |
| 91 | |
| 92 CompositingIOSurfaceMac::~CompositingIOSurfaceMac() { | |
| 93 UnrefIOSurface(); | |
| 94 } | |
| 95 | |
| 96 void CompositingIOSurfaceMac::SetIOSurface(uint64 io_surface_handle) { | |
| 97 CGLSetCurrentContext(cglContext_); | |
| 98 MapIOSurfaceToTexture(io_surface_handle); | |
| 99 CGLSetCurrentContext(0); | |
| 100 } | |
| 101 | |
| 102 void CompositingIOSurfaceMac::DrawIOSurface(uint64 io_surface_handle, | |
| 103 NSView* view) { | |
|
Ken Russell (switch to Gerrit)
2012/04/04 17:27:17
Indentation.
jbates
2012/04/04 19:21:50
Done.
| |
| 104 TRACE_EVENT0("browser", "CompositingIOSurfaceMac::DrawIOSurface"); | |
| 105 CGLSetCurrentContext(cglContext_); | |
| 106 | |
| 107 bool has_io_surface = MapIOSurfaceToTexture(io_surface_handle); | |
| 108 | |
| 109 [glContext_ setView:view]; | |
| 110 NSSize window_size = [view frame].size; | |
| 111 glViewport(0, 0, window_size.width, window_size.height); | |
| 112 | |
| 113 glMatrixMode(GL_PROJECTION); | |
| 114 glLoadIdentity(); | |
| 115 glOrtho(0, window_size.width, window_size.height, 0, -1, 1); | |
| 116 glMatrixMode(GL_MODELVIEW); | |
| 117 glLoadIdentity(); | |
| 118 | |
| 119 glDisable(GL_DEPTH_TEST); | |
| 120 glDisable(GL_BLEND); | |
| 121 | |
| 122 glColorMask(true, true, true, true); | |
| 123 // Should match the clear color of RenderWidgetHostViewMac. | |
| 124 glClearColor(1.0f, 1.0f, 1.0f, 1.0f); | |
| 125 // TODO(jbates): Just clear the right and bottom edges when the size doesn't | |
| 126 // match the window. Then use a shader to blit the texture without its alpha | |
| 127 // channel. | |
| 128 glClear(GL_COLOR_BUFFER_BIT); | |
| 129 | |
| 130 if (has_io_surface) { | |
| 131 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); | |
| 132 | |
| 133 // Draw only the color channels from the incoming texture. | |
| 134 glColorMask(true, true, true, false); | |
| 135 | |
| 136 // Draw the color channels from the incoming texture. | |
| 137 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture_); CHECK_GL_ERROR(); | |
| 138 glEnable(GL_TEXTURE_RECTANGLE_ARB); CHECK_GL_ERROR(); | |
| 139 | |
| 140 glEnableClientState(GL_VERTEX_ARRAY); CHECK_GL_ERROR(); | |
| 141 glEnableClientState(GL_TEXTURE_COORD_ARRAY); CHECK_GL_ERROR(); | |
| 142 | |
| 143 glVertexPointer(2, GL_FLOAT, sizeof(SurfaceVertex), &quad_.verts_[0].x_); | |
| 144 glTexCoordPointer(2, GL_FLOAT, sizeof(SurfaceVertex), &quad_.verts_[0].tx_); | |
| 145 glDrawArrays(GL_QUADS, 0, 4); CHECK_GL_ERROR(); | |
| 146 | |
| 147 glDisableClientState(GL_VERTEX_ARRAY); | |
| 148 glDisableClientState(GL_TEXTURE_COORD_ARRAY); | |
| 149 | |
| 150 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); CHECK_GL_ERROR(); | |
| 151 } | |
| 152 | |
| 153 CGLFlushDrawable(cglContext_); | |
| 154 | |
| 155 CGLSetCurrentContext(0); | |
| 156 } | |
| 157 | |
| 158 void CompositingIOSurfaceMac::DrawLastIOSurface(NSView* view) { | |
| 159 DrawIOSurface(io_surface_handle_, view); | |
| 160 } | |
| 161 | |
| 162 bool CompositingIOSurfaceMac::MapIOSurfaceToTexture( | |
| 163 uint64 io_surface_handle) { | |
| 164 if (io_surface_.get() && io_surface_handle == io_surface_handle_) | |
| 165 return true; | |
| 166 | |
| 167 TRACE_EVENT0("browser", "CompositingIOSurfaceMac::MapIOSurfaceToTexture"); | |
| 168 UnrefIOSurface(); | |
| 169 | |
| 170 io_surface_.reset(io_surface_support_->IOSurfaceLookup( | |
| 171 static_cast<uint32>(io_surface_handle))); | |
| 172 // Can fail if IOSurface with that ID was already released by the gpu | |
| 173 // process. | |
| 174 if (!io_surface_.get()) { | |
| 175 io_surface_handle_ = 0; | |
| 176 return false; | |
| 177 } | |
| 178 | |
| 179 io_surface_handle_ = io_surface_handle; | |
| 180 io_surface_size_.SetSize( | |
| 181 io_surface_support_->IOSurfaceGetWidth(io_surface_), | |
| 182 io_surface_support_->IOSurfaceGetHeight(io_surface_)); | |
| 183 | |
| 184 quad_.set_size(io_surface_size_); | |
| 185 | |
| 186 GLenum target = GL_TEXTURE_RECTANGLE_ARB; | |
| 187 glGenTextures(1, &texture_); | |
| 188 glBindTexture(target, texture_); | |
| 189 glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | |
| 190 glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); CHECK_GL_ERROR(); | |
| 191 GLuint plane = 0; | |
| 192 CGLError cglerror = | |
| 193 io_surface_support_->CGLTexImageIOSurface2D(cglContext_, | |
| 194 target, | |
| 195 GL_RGBA, | |
| 196 io_surface_size_.width(), | |
| 197 io_surface_size_.height(), | |
| 198 GL_BGRA, | |
| 199 GL_UNSIGNED_INT_8_8_8_8_REV, | |
| 200 io_surface_.get(), | |
| 201 plane); | |
| 202 CHECK_GL_ERROR(); | |
| 203 if (cglerror != kCGLNoError) { | |
| 204 LOG(ERROR) << "CGLTexImageIOSurface2D: " << cglerror; | |
| 205 return false; | |
| 206 } | |
| 207 | |
| 208 return true; | |
| 209 } | |
| 210 | |
| 211 void CompositingIOSurfaceMac::UnrefIOSurface() { | |
| 212 if (texture_) { | |
| 213 glDeleteTextures(1, &texture_); | |
| 214 texture_ = 0; | |
| 215 } | |
| 216 | |
| 217 io_surface_.reset(); | |
| 218 } | |
| 219 | |
| 220 void CompositingIOSurfaceMac::GlobalFrameDidChange() { | |
| 221 [glContext_ update]; | |
| 222 } | |
| 223 | |
| 224 void CompositingIOSurfaceMac::ClearDrawable() { | |
| 225 [glContext_ clearDrawable]; | |
| 226 UnrefIOSurface(); | |
| 227 } | |
| OLD | NEW |