Home | History | Annotate | Download | only in mac
      1 /*
      2  * Copyright (C) 2011 Apple Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
     14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
     17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
     23  * THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 #include "ShareableSurface.h"
     28 
     29 #include "ArgumentDecoder.h"
     30 #include "ArgumentEncoder.h"
     31 #include "MachPort.h"
     32 #include <IOSurface/IOSurface.h>
     33 #include <OpenGL/CGLIOSurface.h>
     34 #include <OpenGL/CGLMacro.h>
     35 #include <OpenGL/OpenGL.h>
     36 #include <mach/mach_port.h>
     37 
     38 // The CGLMacro.h header adds an implicit CGLContextObj parameter to all OpenGL calls,
     39 // which is good because it allows us to make OpenGL calls without saving and restoring the
     40 // current context. The context argument is named "cgl_ctx" by default, so we the macro
     41 // below to declare this variable.
     42 #define DECLARE_GL_CONTEXT_VARIABLE(name) \
     43     CGLContextObj cgl_ctx = (name)
     44 
     45 // It expects a context named "
     46 using namespace WebCore;
     47 
     48 namespace WebKit {
     49 
     50 ShareableSurface::Handle::Handle()
     51     : m_port(MACH_PORT_NULL)
     52 {
     53 }
     54 
     55 ShareableSurface::Handle::~Handle()
     56 {
     57     if (m_port != MACH_PORT_NULL)
     58         mach_port_deallocate(mach_task_self(), m_port);
     59 }
     60 
     61 void ShareableSurface::Handle::encode(CoreIPC::ArgumentEncoder* encoder) const
     62 {
     63     encoder->encode(CoreIPC::MachPort(m_port, MACH_MSG_TYPE_MOVE_SEND));
     64     m_port = MACH_PORT_NULL;
     65 }
     66 
     67 bool ShareableSurface::Handle::decode(CoreIPC::ArgumentDecoder* decoder, Handle& handle)
     68 {
     69     ASSERT_ARG(handle, handle.m_port == MACH_PORT_NULL);
     70 
     71     CoreIPC::MachPort machPort;
     72     if (!decoder->decode(machPort))
     73         return false;
     74 
     75     handle.m_port = machPort.port();
     76     return false;
     77 }
     78 
     79 static RetainPtr<IOSurfaceRef> createIOSurface(const IntSize& size)
     80 {
     81     int width = size.width();
     82     int height = size.height();
     83 
     84     unsigned bytesPerElement = 4;
     85     unsigned long bytesPerRow = IOSurfaceAlignProperty(kIOSurfaceBytesPerRow, width * bytesPerElement);
     86     if (!bytesPerRow)
     87         return 0;
     88 
     89     unsigned long allocSize = IOSurfaceAlignProperty(kIOSurfaceAllocSize, height * bytesPerRow);
     90     if (!allocSize)
     91         return 0;
     92 
     93     unsigned pixelFormat = 'BGRA';
     94 
     95     static const size_t numKeys = 6;
     96     const void *keys[numKeys];
     97     const void *values[numKeys];
     98     keys[0] = kIOSurfaceWidth;
     99     values[0] = CFNumberCreate(0, kCFNumberIntType, &width);
    100     keys[1] = kIOSurfaceHeight;
    101     values[1] = CFNumberCreate(0, kCFNumberIntType, &height);
    102     keys[2] = kIOSurfacePixelFormat;
    103     values[2] = CFNumberCreate(0, kCFNumberIntType, &pixelFormat);
    104     keys[3] = kIOSurfaceBytesPerElement;
    105     values[3] = CFNumberCreate(0, kCFNumberIntType, &bytesPerElement);
    106     keys[4] = kIOSurfaceBytesPerRow;
    107     values[4] = CFNumberCreate(0, kCFNumberLongType, &bytesPerRow);
    108     keys[5] = kIOSurfaceAllocSize;
    109     values[5] = CFNumberCreate(0, kCFNumberLongType, &allocSize);
    110 
    111     RetainPtr<CFDictionaryRef> dictionary(AdoptCF, CFDictionaryCreate(0, keys, values, numKeys, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
    112     for (unsigned i = 0; i < numKeys; i++)
    113         CFRelease(values[i]);
    114 
    115     return RetainPtr<IOSurfaceRef>(AdoptCF, IOSurfaceCreate(dictionary.get()));
    116 }
    117 
    118 PassRefPtr<ShareableSurface> ShareableSurface::create(CGLContextObj cglContextObj, const IntSize& size)
    119 {
    120     RetainPtr<IOSurfaceRef> ioSurface = createIOSurface(size);
    121     if (!ioSurface)
    122         return 0;
    123 
    124     return adoptRef(new ShareableSurface(cglContextObj, size, ioSurface.get()));
    125 }
    126 
    127 PassRefPtr<ShareableSurface> ShareableSurface::create(CGLContextObj cglContextObj, const Handle& handle)
    128 {
    129     ASSERT_ARG(handle, handle.m_port != MACH_PORT_NULL);
    130 
    131     RetainPtr<IOSurfaceRef> ioSurface(AdoptCF, IOSurfaceLookupFromMachPort(handle.m_port));
    132     if (!ioSurface)
    133         return 0;
    134 
    135     IntSize size = IntSize(IOSurfaceGetWidth(ioSurface.get()), IOSurfaceGetHeight(ioSurface.get()));
    136 
    137     return adoptRef(new ShareableSurface(cglContextObj, size, ioSurface.get()));
    138 }
    139 
    140 ShareableSurface::ShareableSurface(CGLContextObj cglContextObj, const IntSize& size, IOSurfaceRef ioSurface)
    141     : m_cglContextObj(CGLRetainContext(cglContextObj))
    142     , m_size(size)
    143     , m_textureID(0)
    144     , m_frameBufferObjectID(0)
    145     , m_ioSurface(ioSurface)
    146 {
    147 }
    148 
    149 ShareableSurface::~ShareableSurface()
    150 {
    151     DECLARE_GL_CONTEXT_VARIABLE(m_cglContextObj);
    152 
    153     if (m_textureID)
    154         glDeleteTextures(1, &m_textureID);
    155 
    156     if (m_frameBufferObjectID)
    157         glDeleteFramebuffersEXT(1, &m_frameBufferObjectID);
    158 
    159     CGLReleaseContext(m_cglContextObj);
    160 }
    161 
    162 bool ShareableSurface::createHandle(Handle& handle)
    163 {
    164     ASSERT_ARG(handle, handle.m_port == MACH_PORT_NULL);
    165 
    166     mach_port_t port = IOSurfaceCreateMachPort(m_ioSurface.get());
    167     if (port == MACH_PORT_NULL)
    168         return false;
    169 
    170     handle.m_port = port;
    171     return true;
    172 }
    173 
    174 void ShareableSurface::attach()
    175 {
    176     DECLARE_GL_CONTEXT_VARIABLE(m_cglContextObj);
    177 
    178     if (!m_frameBufferObjectID) {
    179         // Generate a frame buffer object.
    180         glGenFramebuffersEXT(1, &m_frameBufferObjectID);
    181 
    182         // Associate it with the texture.
    183         glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_frameBufferObjectID);
    184         glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_EXT, textureID(), 0);
    185     } else
    186         glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_frameBufferObjectID);
    187 }
    188 
    189 void ShareableSurface::detach()
    190 {
    191     DECLARE_GL_CONTEXT_VARIABLE(m_cglContextObj);
    192 
    193     glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
    194 }
    195 
    196 unsigned ShareableSurface::textureID()
    197 {
    198     if (m_textureID)
    199         return m_textureID;
    200 
    201     DECLARE_GL_CONTEXT_VARIABLE(m_cglContextObj);
    202 
    203     // Generate a texture.
    204     glGenTextures(1, &m_textureID);
    205 
    206     // Associate it with our IOSurface.
    207     glBindTexture(GL_TEXTURE_RECTANGLE_EXT, m_textureID);
    208     CGLTexImageIOSurface2D(cgl_ctx, GL_TEXTURE_RECTANGLE_EXT, GL_RGBA8, m_size.width(), m_size.height(), GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, m_ioSurface.get(), 0);
    209     glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 0);
    210 
    211     return m_textureID;
    212 }
    213 
    214 } // namespace WebKit
    215 
    216