| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) | |
| 3 | |
| 4 This library is free software; you can redistribute it and/or | |
| 5 modify it under the terms of the GNU Library General Public | |
| 6 License as published by the Free Software Foundation; either | |
| 7 version 2 of the License, or (at your option) any later version. | |
| 8 | |
| 9 This library is distributed in the hope that it will be useful, | |
| 10 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 12 Library General Public License for more details. | |
| 13 | |
| 14 You should have received a copy of the GNU Library General Public License | |
| 15 along with this library; see the file COPYING.LIB. If not, write to | |
| 16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | |
| 17 Boston, MA 02110-1301, USA. | |
| 18 */ | |
| 19 | |
| 20 #include "config.h" | |
| 21 #include "GraphicsSurface.h" | |
| 22 | |
| 23 #if USE(GRAPHICS_SURFACE) && OS(DARWIN) | |
| 24 #include "TextureMapperGL.h" | |
| 25 #include <CFNumber.h> | |
| 26 #include <CGLContext.h> | |
| 27 #include <CGLCurrent.h> | |
| 28 #include <CGLIOSurface.h> | |
| 29 #include <IOSurface/IOSurface.h> | |
| 30 #include <OpenGL/OpenGL.h> | |
| 31 #include <OpenGL/gl.h> | |
| 32 #include <mach/mach.h> | |
| 33 | |
| 34 namespace WebCore { | |
| 35 | |
| 36 static uint32_t createTexture(IOSurfaceRef handle) | |
| 37 { | |
| 38 GLuint texture = 0; | |
| 39 GLuint format = GL_BGRA; | |
| 40 GLuint type = GL_UNSIGNED_INT_8_8_8_8_REV; | |
| 41 GLuint internalFormat = GL_RGBA; | |
| 42 CGLContextObj context = CGLGetCurrentContext(); | |
| 43 if (!context) | |
| 44 return 0; | |
| 45 | |
| 46 GLint prevTexture; | |
| 47 glGetIntegerv(GL_TEXTURE_RECTANGLE_ARB, &prevTexture); | |
| 48 | |
| 49 glGenTextures(1, &texture); | |
| 50 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture); | |
| 51 CGLError error = CGLTexImageIOSurface2D(context, GL_TEXTURE_RECTANGLE_ARB, i
nternalFormat, IOSurfaceGetWidth(handle), IOSurfaceGetHeight(handle), format, ty
pe, handle, 0); | |
| 52 if (error) { | |
| 53 glDeleteTextures(1, &texture); | |
| 54 texture = 0; | |
| 55 } | |
| 56 | |
| 57 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, prevTexture); | |
| 58 | |
| 59 return texture; | |
| 60 } | |
| 61 | |
| 62 struct GraphicsSurfacePrivate { | |
| 63 public: | |
| 64 GraphicsSurfacePrivate(const GraphicsSurfaceToken& token, const IntSize& siz
e) | |
| 65 : m_context(0) | |
| 66 , m_size(size) | |
| 67 , m_token(token) | |
| 68 , m_frontBufferTexture(0) | |
| 69 , m_frontBufferReadTexture(0) | |
| 70 , m_backBufferTexture(0) | |
| 71 , m_backBufferReadTexture(0) | |
| 72 , m_readFbo(0) | |
| 73 , m_drawFbo(0) | |
| 74 { | |
| 75 m_frontBuffer = IOSurfaceLookupFromMachPort(m_token.frontBufferHandle); | |
| 76 m_backBuffer = IOSurfaceLookupFromMachPort(m_token.backBufferHandle); | |
| 77 } | |
| 78 | |
| 79 GraphicsSurfacePrivate(const PlatformGraphicsContext3D shareContext, const I
ntSize& size, GraphicsSurface::Flags flags) | |
| 80 : m_context(0) | |
| 81 , m_size(size) | |
| 82 , m_frontBufferTexture(0) | |
| 83 , m_frontBufferReadTexture(0) | |
| 84 , m_backBufferTexture(0) | |
| 85 , m_backBufferReadTexture(0) | |
| 86 , m_readFbo(0) | |
| 87 , m_drawFbo(0) | |
| 88 { | |
| 89 unsigned pixelFormat = 'BGRA'; | |
| 90 unsigned bytesPerElement = 4; | |
| 91 int width = m_size.width(); | |
| 92 int height = m_size.height(); | |
| 93 | |
| 94 unsigned long bytesPerRow = IOSurfaceAlignProperty(kIOSurfaceBytesPerRow
, width * bytesPerElement); | |
| 95 if (!bytesPerRow) | |
| 96 return; | |
| 97 | |
| 98 unsigned long allocSize = IOSurfaceAlignProperty(kIOSurfaceAllocSize, he
ight * bytesPerRow); | |
| 99 if (!allocSize) | |
| 100 return; | |
| 101 | |
| 102 const void *keys[6]; | |
| 103 const void *values[6]; | |
| 104 keys[0] = kIOSurfaceWidth; | |
| 105 values[0] = CFNumberCreate(0, kCFNumberIntType, &width); | |
| 106 keys[1] = kIOSurfaceHeight; | |
| 107 values[1] = CFNumberCreate(0, kCFNumberIntType, &height); | |
| 108 keys[2] = kIOSurfacePixelFormat; | |
| 109 values[2] = CFNumberCreate(0, kCFNumberIntType, &pixelFormat); | |
| 110 keys[3] = kIOSurfaceBytesPerElement; | |
| 111 values[3] = CFNumberCreate(0, kCFNumberIntType, &bytesPerElement); | |
| 112 keys[4] = kIOSurfaceBytesPerRow; | |
| 113 values[4] = CFNumberCreate(0, kCFNumberLongType, &bytesPerRow); | |
| 114 keys[5] = kIOSurfaceAllocSize; | |
| 115 values[5] = CFNumberCreate(0, kCFNumberLongType, &allocSize); | |
| 116 | |
| 117 CFDictionaryRef dict = CFDictionaryCreate(0, keys, values, 6, &kCFTypeDi
ctionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | |
| 118 for (unsigned i = 0; i < 6; i++) | |
| 119 CFRelease(values[i]); | |
| 120 | |
| 121 m_frontBuffer = IOSurfaceCreate(dict); | |
| 122 m_backBuffer = IOSurfaceCreate(dict); | |
| 123 | |
| 124 if (!(flags & GraphicsSurface::SupportsSharing)) | |
| 125 return; | |
| 126 | |
| 127 m_token = GraphicsSurfaceToken(IOSurfaceCreateMachPort(m_frontBuffer), I
OSurfaceCreateMachPort(m_backBuffer)); | |
| 128 } | |
| 129 | |
| 130 ~GraphicsSurfacePrivate() | |
| 131 { | |
| 132 if (m_frontBufferTexture) | |
| 133 glDeleteTextures(1, &m_frontBufferTexture); | |
| 134 | |
| 135 if (m_frontBufferReadTexture) | |
| 136 glDeleteTextures(1, &m_frontBufferReadTexture); | |
| 137 | |
| 138 if (m_backBufferTexture) | |
| 139 glDeleteTextures(1, &m_backBufferTexture); | |
| 140 | |
| 141 if (m_backBufferReadTexture) | |
| 142 glDeleteTextures(1, &m_backBufferReadTexture); | |
| 143 | |
| 144 if (m_frontBuffer) | |
| 145 CFRelease(IOSurfaceRef(m_frontBuffer)); | |
| 146 | |
| 147 if (m_backBuffer) | |
| 148 CFRelease(IOSurfaceRef(m_backBuffer)); | |
| 149 | |
| 150 if (m_readFbo) | |
| 151 glDeleteFramebuffers(1, &m_readFbo); | |
| 152 | |
| 153 if (m_drawFbo) | |
| 154 glDeleteFramebuffers(1, &m_drawFbo); | |
| 155 | |
| 156 if (m_context) | |
| 157 CGLReleaseContext(m_context); | |
| 158 | |
| 159 if (m_token.frontBufferHandle) | |
| 160 mach_port_deallocate(mach_task_self(), m_token.frontBufferHandle); | |
| 161 if (m_token.backBufferHandle) | |
| 162 mach_port_deallocate(mach_task_self(), m_token.backBufferHandle); | |
| 163 | |
| 164 } | |
| 165 | |
| 166 uint32_t swapBuffers() | |
| 167 { | |
| 168 std::swap(m_frontBuffer, m_backBuffer); | |
| 169 std::swap(m_frontBufferTexture, m_backBufferTexture); | |
| 170 std::swap(m_frontBufferReadTexture, m_backBufferReadTexture); | |
| 171 | |
| 172 return IOSurfaceGetID(m_frontBuffer); | |
| 173 } | |
| 174 | |
| 175 void makeCurrent() | |
| 176 { | |
| 177 m_detachedContext = CGLGetCurrentContext(); | |
| 178 | |
| 179 if (m_context) | |
| 180 CGLSetCurrentContext(m_context); | |
| 181 } | |
| 182 | |
| 183 void doneCurrent() | |
| 184 { | |
| 185 CGLSetCurrentContext(m_detachedContext); | |
| 186 m_detachedContext = 0; | |
| 187 } | |
| 188 | |
| 189 void copyFromTexture(uint32_t texture, const IntRect& sourceRect) | |
| 190 { | |
| 191 // FIXME: The following glFlush can possibly be replaced by using the GL
_ARB_sync extension. | |
| 192 glFlush(); // Make sure the texture has actually been completely written
in the original context. | |
| 193 | |
| 194 makeCurrent(); | |
| 195 | |
| 196 int x = sourceRect.x(); | |
| 197 int y = sourceRect.y(); | |
| 198 int width = sourceRect.width(); | |
| 199 int height = sourceRect.height(); | |
| 200 | |
| 201 glPushAttrib(GL_ALL_ATTRIB_BITS); | |
| 202 GLint previousFBO; | |
| 203 glGetIntegerv(GL_FRAMEBUFFER_BINDING, &previousFBO); | |
| 204 | |
| 205 if (!m_drawFbo) | |
| 206 glGenFramebuffers(1, &m_drawFbo); | |
| 207 | |
| 208 if (!m_readFbo) | |
| 209 glGenFramebuffers(1, &m_readFbo); | |
| 210 | |
| 211 glBindFramebuffer(GL_READ_FRAMEBUFFER, m_readFbo); | |
| 212 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEX
TURE_2D, texture, 0); | |
| 213 | |
| 214 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_drawFbo); | |
| 215 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEX
TURE_RECTANGLE_ARB, backBufferTextureID(), 0); | |
| 216 glBlitFramebuffer(x, y, width, height, x, x+height, y+width, y, GL_COLOR
_BUFFER_BIT, GL_LINEAR); // Flip the texture upside down. | |
| 217 | |
| 218 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEX
TURE_RECTANGLE_ARB, 0, 0); | |
| 219 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEX
TURE_2D, 0, 0); | |
| 220 glBindFramebuffer(GL_FRAMEBUFFER, previousFBO); | |
| 221 glPopAttrib(); | |
| 222 | |
| 223 // Flushing the gl command buffer is necessary to ensure the texture has
correctly been bound to the IOSurface. | |
| 224 glFlush(); | |
| 225 | |
| 226 swapBuffers(); | |
| 227 doneCurrent(); | |
| 228 } | |
| 229 | |
| 230 GraphicsSurfaceToken token() const | |
| 231 { | |
| 232 return m_token; | |
| 233 } | |
| 234 | |
| 235 uint32_t frontBufferTextureID() | |
| 236 { | |
| 237 if (!m_frontBufferReadTexture) | |
| 238 m_frontBufferReadTexture = createTexture(m_frontBuffer); | |
| 239 | |
| 240 return m_frontBufferReadTexture; | |
| 241 } | |
| 242 | |
| 243 uint32_t backBufferTextureID() | |
| 244 { | |
| 245 if (!m_backBufferTexture) | |
| 246 m_backBufferTexture = createTexture(m_backBuffer); | |
| 247 | |
| 248 return m_backBufferTexture; | |
| 249 } | |
| 250 | |
| 251 PlatformGraphicsSurface frontBuffer() const | |
| 252 { | |
| 253 return m_frontBuffer; | |
| 254 } | |
| 255 | |
| 256 PlatformGraphicsSurface backBuffer() const | |
| 257 { | |
| 258 return m_backBuffer; | |
| 259 } | |
| 260 | |
| 261 IntSize size() const | |
| 262 { | |
| 263 return m_size; | |
| 264 } | |
| 265 | |
| 266 private: | |
| 267 CGLContextObj m_context; | |
| 268 IntSize m_size; | |
| 269 CGLContextObj m_detachedContext; | |
| 270 PlatformGraphicsSurface m_frontBuffer; | |
| 271 PlatformGraphicsSurface m_backBuffer; | |
| 272 uint32_t m_frontBufferTexture; | |
| 273 uint32_t m_frontBufferReadTexture; | |
| 274 uint32_t m_backBufferTexture; | |
| 275 uint32_t m_backBufferReadTexture; | |
| 276 uint32_t m_readFbo; | |
| 277 uint32_t m_drawFbo; | |
| 278 GraphicsSurfaceToken m_token; | |
| 279 }; | |
| 280 | |
| 281 GraphicsSurfaceToken GraphicsSurface::platformExport() | |
| 282 { | |
| 283 return m_private->token(); | |
| 284 } | |
| 285 | |
| 286 uint32_t GraphicsSurface::platformGetTextureID() | |
| 287 { | |
| 288 return m_private->frontBufferTextureID(); | |
| 289 } | |
| 290 | |
| 291 void GraphicsSurface::platformCopyToGLTexture(uint32_t target, uint32_t id, cons
t IntRect& targetRect, const IntPoint& offset) | |
| 292 { | |
| 293 glPushAttrib(GL_ALL_ATTRIB_BITS); | |
| 294 if (!m_fbo) | |
| 295 glGenFramebuffers(1, &m_fbo); | |
| 296 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); | |
| 297 glBindTexture(target, id); | |
| 298 glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo); | |
| 299 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE
_RECTANGLE_ARB, m_private->frontBufferTextureID(), 0); | |
| 300 glCopyTexSubImage2D(target, 0, targetRect.x(), targetRect.y(), offset.x(), o
ffset.y(), targetRect.width(), targetRect.height()); | |
| 301 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE
_RECTANGLE_ARB, 0, 0); | |
| 302 glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); | |
| 303 glPopAttrib(); | |
| 304 | |
| 305 // According to IOSurface's documentation, glBindFramebuffer is the one trig
gering an update of the surface's cache. | |
| 306 // If the web process starts rendering and unlocks the surface before this h
appens, we might copy contents | |
| 307 // of the currently rendering frame on our texture instead of the previously
completed frame. | |
| 308 // Flush the command buffer to reduce the odds of this happening, this would
not be necessary with double buffering. | |
| 309 glFlush(); | |
| 310 } | |
| 311 | |
| 312 void GraphicsSurface::platformCopyFromTexture(uint32_t texture, const IntRect& s
ourceRect) | |
| 313 { | |
| 314 m_private->copyFromTexture(texture, sourceRect); | |
| 315 } | |
| 316 | |
| 317 void GraphicsSurface::platformPaintToTextureMapper(TextureMapper* textureMapper,
const FloatRect& targetRect, const TransformationMatrix& transform, float opaci
ty) | |
| 318 { | |
| 319 IntSize size = m_private->size(); | |
| 320 FloatRect rectOnContents(FloatPoint::zero(), size); | |
| 321 TransformationMatrix adjustedTransform = transform; | |
| 322 adjustedTransform.multiply(TransformationMatrix::rectToRect(rectOnContents,
targetRect)); | |
| 323 static_cast<TextureMapperGL*>(textureMapper)->drawTexture(m_private->frontBu
fferTextureID(), TextureMapperGL::ShouldBlend | TextureMapperGL::ShouldUseARBTex
tureRect, size, rectOnContents, adjustedTransform, opacity); | |
| 324 } | |
| 325 | |
| 326 uint32_t GraphicsSurface::platformFrontBuffer() const | |
| 327 { | |
| 328 return IOSurfaceGetID(m_private->frontBuffer()); | |
| 329 } | |
| 330 | |
| 331 uint32_t GraphicsSurface::platformSwapBuffers() | |
| 332 { | |
| 333 return m_private->swapBuffers(); | |
| 334 } | |
| 335 | |
| 336 IntSize GraphicsSurface::platformSize() const | |
| 337 { | |
| 338 return m_private->size(); | |
| 339 } | |
| 340 | |
| 341 PassRefPtr<GraphicsSurface> GraphicsSurface::platformCreate(const IntSize& size,
Flags flags, const PlatformGraphicsContext3D shareContext) | |
| 342 { | |
| 343 // We currently disable support for CopyToTexture on Mac, because this is us
ed for single buffered Tiles. | |
| 344 // The single buffered nature of this requires a call to glFlush, as describ
ed in platformCopyToTexture. | |
| 345 // This call blocks the GPU for about 40ms, which makes smooth animations im
possible. | |
| 346 if (flags & SupportsCopyToTexture || flags & SupportsSingleBuffered) | |
| 347 return PassRefPtr<GraphicsSurface>(); | |
| 348 | |
| 349 RefPtr<GraphicsSurface> surface = adoptRef(new GraphicsSurface(size, flags))
; | |
| 350 surface->m_private = new GraphicsSurfacePrivate(shareContext, size, flags); | |
| 351 | |
| 352 if (!surface->m_private->frontBuffer() || !surface->m_private->backBuffer()) | |
| 353 return PassRefPtr<GraphicsSurface>(); | |
| 354 | |
| 355 return surface; | |
| 356 } | |
| 357 | |
| 358 PassRefPtr<GraphicsSurface> GraphicsSurface::platformImport(const IntSize& size,
Flags flags, const GraphicsSurfaceToken& token) | |
| 359 { | |
| 360 // We currently disable support for CopyToTexture on Mac, because this is us
ed for single buffered Tiles. | |
| 361 // The single buffered nature of this requires a call to glFlush, as describ
ed in platformCopyToTexture. | |
| 362 // This call blocks the GPU for about 40ms, which makes smooth animations im
possible. | |
| 363 if (flags & SupportsCopyToTexture || flags & SupportsSingleBuffered) | |
| 364 return PassRefPtr<GraphicsSurface>(); | |
| 365 | |
| 366 RefPtr<GraphicsSurface> surface = adoptRef(new GraphicsSurface(size, flags))
; | |
| 367 surface->m_private = new GraphicsSurfacePrivate(token, size); | |
| 368 | |
| 369 if (!surface->m_private->frontBuffer() || !surface->m_private->backBuffer()) | |
| 370 return PassRefPtr<GraphicsSurface>(); | |
| 371 | |
| 372 return surface; | |
| 373 } | |
| 374 | |
| 375 static int ioSurfaceLockOptions(int lockOptions) | |
| 376 { | |
| 377 int options = 0; | |
| 378 if (lockOptions & GraphicsSurface::ReadOnly) | |
| 379 options |= kIOSurfaceLockReadOnly; | |
| 380 if (!(lockOptions & GraphicsSurface::RetainPixels)) | |
| 381 options |= kIOSurfaceLockAvoidSync; | |
| 382 | |
| 383 return options; | |
| 384 } | |
| 385 | |
| 386 char* GraphicsSurface::platformLock(const IntRect& rect, int* outputStride, Lock
Options lockOptions) | |
| 387 { | |
| 388 // Locking is only necessary for single buffered use. | |
| 389 // In this case we only have a front buffer, so we only lock this one. | |
| 390 m_lockOptions = lockOptions; | |
| 391 IOReturn status = IOSurfaceLock(m_private->frontBuffer(), ioSurfaceLockOptio
ns(m_lockOptions), 0); | |
| 392 if (status == kIOReturnCannotLock) { | |
| 393 m_lockOptions |= RetainPixels; | |
| 394 IOSurfaceLock(m_private->frontBuffer(), ioSurfaceLockOptions(m_lockOptio
ns), 0); | |
| 395 } | |
| 396 | |
| 397 int stride = IOSurfaceGetBytesPerRow(m_private->frontBuffer()); | |
| 398 if (outputStride) | |
| 399 *outputStride = stride; | |
| 400 | |
| 401 char* base = static_cast<char*>(IOSurfaceGetBaseAddress(m_private->frontBuff
er())); | |
| 402 | |
| 403 return base + stride * rect.y() + rect.x() * 4; | |
| 404 } | |
| 405 | |
| 406 void GraphicsSurface::platformUnlock() | |
| 407 { | |
| 408 IOSurfaceUnlock(m_private->frontBuffer(), ioSurfaceLockOptions(m_lockOptions
), 0); | |
| 409 } | |
| 410 | |
| 411 void GraphicsSurface::platformDestroy() | |
| 412 { | |
| 413 if (m_fbo) | |
| 414 glDeleteFramebuffers(1, &m_fbo); | |
| 415 if (m_private) | |
| 416 delete m_private; | |
| 417 m_private = 0; | |
| 418 } | |
| 419 | |
| 420 } | |
| 421 #endif | |
| OLD | NEW |