| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "app/surface/accelerated_surface_mac.h" | 5 #include "app/surface/accelerated_surface_mac.h" |
| 6 | 6 |
| 7 #include "app/gfx/gl/gl_bindings.h" | 7 #include "app/gfx/gl/gl_bindings.h" |
| 8 #include "app/surface/io_surface_support_mac.h" | 8 #include "app/surface/io_surface_support_mac.h" |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "gfx/rect.h" | 10 #include "gfx/rect.h" |
| 11 | 11 |
| 12 AcceleratedSurface::AcceleratedSurface() | 12 AcceleratedSurface::AcceleratedSurface() |
| 13 : gl_context_(NULL), | 13 : allocate_fbo_(false), |
| 14 pbuffer_(NULL), | |
| 15 allocate_fbo_(false), | |
| 16 texture_(0), | 14 texture_(0), |
| 17 fbo_(0), | 15 fbo_(0), |
| 18 depth_stencil_renderbuffer_(0) { | 16 depth_stencil_renderbuffer_(0) { |
| 19 } | 17 } |
| 20 | 18 |
| 21 bool AcceleratedSurface::Initialize(CGLContextObj share_context, | 19 bool AcceleratedSurface::Initialize(gfx::GLContext* share_context, |
| 22 bool allocate_fbo) { | 20 bool allocate_fbo) { |
| 23 allocate_fbo_ = allocate_fbo; | 21 allocate_fbo_ = allocate_fbo; |
| 24 | 22 |
| 25 // TODO(kbr): we should reuse the code for PbufferGLContext here instead | 23 gl_context_.reset(gfx::GLContext::CreateOffscreenGLContext(share_context)); |
| 26 // of duplicating it. However, in order to do so, we need to move the | 24 if (!gl_context_.get()) |
| 27 // GLContext classes out of gpu/ and into gfx/. | 25 return false; |
| 28 | 26 |
| 29 // Create a 1x1 pbuffer and associated context to bootstrap things | 27 // Now we're ready to handle SetSurfaceSize calls, which will |
| 30 static const CGLPixelFormatAttribute attribs[] = { | |
| 31 (CGLPixelFormatAttribute) kCGLPFAPBuffer, | |
| 32 (CGLPixelFormatAttribute) 0 | |
| 33 }; | |
| 34 CGLPixelFormatObj pixel_format; | |
| 35 GLint num_pixel_formats; | |
| 36 if (CGLChoosePixelFormat(attribs, | |
| 37 &pixel_format, | |
| 38 &num_pixel_formats) != kCGLNoError) { | |
| 39 DLOG(ERROR) << "Error choosing pixel format."; | |
| 40 return false; | |
| 41 } | |
| 42 if (!pixel_format) { | |
| 43 return false; | |
| 44 } | |
| 45 CGLContextObj context; | |
| 46 CGLError res = CGLCreateContext(pixel_format, share_context, &context); | |
| 47 CGLDestroyPixelFormat(pixel_format); | |
| 48 if (res != kCGLNoError) { | |
| 49 DLOG(ERROR) << "Error creating context."; | |
| 50 return false; | |
| 51 } | |
| 52 CGLPBufferObj pbuffer; | |
| 53 if (CGLCreatePBuffer(1, 1, | |
| 54 GL_TEXTURE_2D, GL_RGBA, | |
| 55 0, &pbuffer) != kCGLNoError) { | |
| 56 CGLDestroyContext(context); | |
| 57 DLOG(ERROR) << "Error creating pbuffer."; | |
| 58 return false; | |
| 59 } | |
| 60 if (CGLSetPBuffer(context, pbuffer, 0, 0, 0) != kCGLNoError) { | |
| 61 CGLDestroyContext(context); | |
| 62 CGLDestroyPBuffer(pbuffer); | |
| 63 DLOG(ERROR) << "Error attaching pbuffer to context."; | |
| 64 return false; | |
| 65 } | |
| 66 gl_context_ = context; | |
| 67 pbuffer_ = pbuffer; | |
| 68 // Now we're ready to handle SetWindowSize calls, which will | |
| 69 // allocate and/or reallocate the IOSurface and associated offscreen | 28 // allocate and/or reallocate the IOSurface and associated offscreen |
| 70 // OpenGL structures for rendering. | 29 // OpenGL structures for rendering. |
| 71 return true; | 30 return true; |
| 72 } | 31 } |
| 73 | 32 |
| 74 void AcceleratedSurface::Destroy() { | 33 void AcceleratedSurface::Destroy() { |
| 75 // The FBO and texture objects will be destroyed when the OpenGL context, | 34 // The FBO and texture objects will be destroyed when the OpenGL context, |
| 76 // and any other contexts sharing resources with it, is. We don't want to | 35 // and any other contexts sharing resources with it, is. We don't want to |
| 77 // make the context current one last time here just in order to delete | 36 // make the context current one last time here just in order to delete |
| 78 // these objects. | 37 // these objects. |
| 79 | 38 |
| 80 // Release the old TransportDIB in the browser. | 39 // Release the old TransportDIB in the browser. |
| 81 if (dib_free_callback_.get() && transport_dib_.get()) { | 40 if (dib_free_callback_.get() && transport_dib_.get()) { |
| 82 dib_free_callback_->Run(transport_dib_->id()); | 41 dib_free_callback_->Run(transport_dib_->id()); |
| 83 } | 42 } |
| 84 transport_dib_.reset(); | 43 transport_dib_.reset(); |
| 85 if (gl_context_) | 44 |
| 86 CGLDestroyContext(gl_context_); | 45 if (gl_context_.get()) |
| 87 if (pbuffer_) | 46 gl_context_->Destroy(); |
| 88 CGLDestroyPBuffer(pbuffer_); | 47 gl_context_.reset(); |
| 89 } | 48 } |
| 90 | 49 |
| 91 // Call after making changes to the surface which require a visual update. | 50 // Call after making changes to the surface which require a visual update. |
| 92 // Makes the rendering show up in other processes. | 51 // Makes the rendering show up in other processes. |
| 93 void AcceleratedSurface::SwapBuffers() { | 52 void AcceleratedSurface::SwapBuffers() { |
| 94 if (io_surface_.get() != NULL) { | 53 if (io_surface_.get() != NULL) { |
| 95 if (allocate_fbo_) { | 54 if (allocate_fbo_) { |
| 96 // Bind and unbind the framebuffer to make changes to the | 55 // Bind and unbind the framebuffer to make changes to the |
| 97 // IOSurface show up in the other process. | 56 // IOSurface show up in the other process. |
| 98 glFlush(); | 57 glFlush(); |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 191 if (fbo_status == GL_FRAMEBUFFER_COMPLETE_EXT) { | 150 if (fbo_status == GL_FRAMEBUFFER_COMPLETE_EXT) { |
| 192 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, | 151 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, |
| 193 GL_DEPTH_ATTACHMENT_EXT, | 152 GL_DEPTH_ATTACHMENT_EXT, |
| 194 GL_RENDERBUFFER_EXT, | 153 GL_RENDERBUFFER_EXT, |
| 195 depth_stencil_renderbuffer_); | 154 depth_stencil_renderbuffer_); |
| 196 fbo_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); | 155 fbo_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); |
| 197 } | 156 } |
| 198 // Attach the depth and stencil buffer. | 157 // Attach the depth and stencil buffer. |
| 199 if (fbo_status == GL_FRAMEBUFFER_COMPLETE_EXT) { | 158 if (fbo_status == GL_FRAMEBUFFER_COMPLETE_EXT) { |
| 200 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, | 159 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, |
| 201 0x8D20, // GL_STENCIL_ATTACHMENT, | 160 0x8D20, // GL_STENCIL_ATTACHMENT, |
| 202 GL_RENDERBUFFER_EXT, | 161 GL_RENDERBUFFER_EXT, |
| 203 depth_stencil_renderbuffer_); | 162 depth_stencil_renderbuffer_); |
| 204 fbo_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); | 163 fbo_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); |
| 205 } | 164 } |
| 206 return fbo_status == GL_FRAMEBUFFER_COMPLETE_EXT; | 165 return fbo_status == GL_FRAMEBUFFER_COMPLETE_EXT; |
| 207 } | 166 } |
| 208 | 167 |
| 209 bool AcceleratedSurface::MakeCurrent() { | 168 bool AcceleratedSurface::MakeCurrent() { |
| 210 if (CGLGetCurrentContext() != gl_context_) { | 169 if (!gl_context_.get()) |
| 211 if (CGLSetCurrentContext(gl_context_) != kCGLNoError) { | 170 return false; |
| 212 DLOG(ERROR) << "Unable to make gl context current."; | 171 return gl_context_->MakeCurrent(); |
| 213 return false; | |
| 214 } | |
| 215 } | |
| 216 return true; | |
| 217 } | 172 } |
| 218 | 173 |
| 219 void AcceleratedSurface::Clear(const gfx::Rect& rect) { | 174 void AcceleratedSurface::Clear(const gfx::Rect& rect) { |
| 175 DCHECK(gl_context_->IsCurrent()); |
| 220 glClearColor(0, 0, 0, 0); | 176 glClearColor(0, 0, 0, 0); |
| 221 glViewport(0, 0, rect.width(), rect.height()); | 177 glViewport(0, 0, rect.width(), rect.height()); |
| 222 glMatrixMode(GL_PROJECTION); | 178 glMatrixMode(GL_PROJECTION); |
| 223 glLoadIdentity(); | 179 glLoadIdentity(); |
| 224 glOrtho(0, rect.width(), 0, rect.height(), -1, 1); | 180 glOrtho(0, rect.width(), 0, rect.height(), -1, 1); |
| 225 glClear(GL_COLOR_BUFFER_BIT); | 181 glClear(GL_COLOR_BUFFER_BIT); |
| 226 } | 182 } |
| 227 | 183 |
| 228 uint64 AcceleratedSurface::SetSurfaceSize(const gfx::Size& size) { | 184 uint64 AcceleratedSurface::SetSurfaceSize(const gfx::Size& size) { |
| 229 if (surface_size_ == size) { | 185 if (surface_size_ == size) { |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 267 io_surface_support->GetKIOSurfaceBytesPerElement(), 4); | 223 io_surface_support->GetKIOSurfaceBytesPerElement(), 4); |
| 268 AddBooleanValue(properties, | 224 AddBooleanValue(properties, |
| 269 io_surface_support->GetKIOSurfaceIsGlobal(), true); | 225 io_surface_support->GetKIOSurfaceIsGlobal(), true); |
| 270 // I believe we should be able to unreference the IOSurfaces without | 226 // I believe we should be able to unreference the IOSurfaces without |
| 271 // synchronizing with the browser process because they are | 227 // synchronizing with the browser process because they are |
| 272 // ultimately reference counted by the operating system. | 228 // ultimately reference counted by the operating system. |
| 273 io_surface_.reset(io_surface_support->IOSurfaceCreate(properties)); | 229 io_surface_.reset(io_surface_support->IOSurfaceCreate(properties)); |
| 274 | 230 |
| 275 // Don't think we need to identify a plane. | 231 // Don't think we need to identify a plane. |
| 276 GLuint plane = 0; | 232 GLuint plane = 0; |
| 277 io_surface_support->CGLTexImageIOSurface2D(gl_context_, | 233 io_surface_support->CGLTexImageIOSurface2D( |
| 278 target, | 234 static_cast<CGLContextObj>(gl_context_->GetHandle()), |
| 279 GL_RGBA, | 235 target, |
| 280 size.width(), | 236 GL_RGBA, |
| 281 size.height(), | 237 size.width(), |
| 282 GL_BGRA, | 238 size.height(), |
| 283 GL_UNSIGNED_INT_8_8_8_8_REV, | 239 GL_BGRA, |
| 284 io_surface_.get(), | 240 GL_UNSIGNED_INT_8_8_8_8_REV, |
| 285 plane); | 241 io_surface_.get(), |
| 242 plane); |
| 286 if (allocate_fbo_) { | 243 if (allocate_fbo_) { |
| 287 // Set up the frame buffer object. | 244 // Set up the frame buffer object. |
| 288 SetupFrameBufferObject(target); | 245 SetupFrameBufferObject(target); |
| 289 } | 246 } |
| 290 surface_size_ = size; | 247 surface_size_ = size; |
| 291 | 248 |
| 292 // Now send back an identifier for the IOSurface. We originally | 249 // Now send back an identifier for the IOSurface. We originally |
| 293 // intended to send back a mach port from IOSurfaceCreateMachPort | 250 // intended to send back a mach port from IOSurfaceCreateMachPort |
| 294 // but it looks like Chrome IPC would need to be modified to | 251 // but it looks like Chrome IPC would need to be modified to |
| 295 // properly send mach ports between processes. For the time being we | 252 // properly send mach ports between processes. For the time being we |
| (...skipping 30 matching lines...) Expand all Loading... |
| 326 return TransportDIB::DefaultHandleValue(); | 283 return TransportDIB::DefaultHandleValue(); |
| 327 } | 284 } |
| 328 transport_dib_.reset(TransportDIB::Map(dib_handle)); | 285 transport_dib_.reset(TransportDIB::Map(dib_handle)); |
| 329 if (transport_dib_.get() == NULL) { | 286 if (transport_dib_.get() == NULL) { |
| 330 // TODO(dspringer): if the Map() fails, should the deallocator be run so | 287 // TODO(dspringer): if the Map() fails, should the deallocator be run so |
| 331 // that the DIB is deallocated in the browser? | 288 // that the DIB is deallocated in the browser? |
| 332 return TransportDIB::DefaultHandleValue(); | 289 return TransportDIB::DefaultHandleValue(); |
| 333 } | 290 } |
| 334 | 291 |
| 335 if (allocate_fbo_) { | 292 if (allocate_fbo_) { |
| 293 DCHECK(gl_context_->IsCurrent()); |
| 336 // Set up the render buffers and reserve enough space on the card for the | 294 // Set up the render buffers and reserve enough space on the card for the |
| 337 // framebuffer texture. | 295 // framebuffer texture. |
| 338 GLenum target = GL_TEXTURE_RECTANGLE_ARB; | 296 GLenum target = GL_TEXTURE_RECTANGLE_ARB; |
| 339 AllocateRenderBuffers(target, size); | 297 AllocateRenderBuffers(target, size); |
| 340 glTexImage2D(target, | 298 glTexImage2D(target, |
| 341 0, // mipmap level 0 | 299 0, // mipmap level 0 |
| 342 GL_RGBA8, // internal pixel format | 300 GL_RGBA8, // internal pixel format |
| 343 size.width(), | 301 size.width(), |
| 344 size.height(), | 302 size.height(), |
| 345 0, // 0 border | 303 0, // 0 border |
| 346 GL_BGRA, // Used for consistency | 304 GL_BGRA, // Used for consistency |
| 347 GL_UNSIGNED_INT_8_8_8_8_REV, | 305 GL_UNSIGNED_INT_8_8_8_8_REV, |
| 348 NULL); // No data, just reserve room on the card. | 306 NULL); // No data, just reserve room on the card. |
| 349 SetupFrameBufferObject(target); | 307 SetupFrameBufferObject(target); |
| 350 } | 308 } |
| 351 return transport_dib_->handle(); | 309 return transport_dib_->handle(); |
| 352 } | 310 } |
| 353 | 311 |
| 354 void AcceleratedSurface::SetTransportDIBAllocAndFree( | 312 void AcceleratedSurface::SetTransportDIBAllocAndFree( |
| 355 Callback2<size_t, TransportDIB::Handle*>::Type* allocator, | 313 Callback2<size_t, TransportDIB::Handle*>::Type* allocator, |
| 356 Callback1<TransportDIB::Id>::Type* deallocator) { | 314 Callback1<TransportDIB::Id>::Type* deallocator) { |
| 357 dib_alloc_callback_.reset(allocator); | 315 dib_alloc_callback_.reset(allocator); |
| 358 dib_free_callback_.reset(deallocator); | 316 dib_free_callback_.reset(deallocator); |
| 359 } | 317 } |
| OLD | NEW |