1/*
2 * Copyright (C) 2009 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. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27
28#if ENABLE(WEBGL)
29
30#import "WebGLLayer.h"
31
32#import "GraphicsContext3D.h"
33#import "GraphicsLayer.h"
34#if !PLATFORM(IOS)
35#import <OpenGL/OpenGL.h>
36#import <OpenGL/gl.h>
37#endif
38#import <wtf/FastMalloc.h>
39#import <wtf/RetainPtr.h>
40
41using namespace WebCore;
42
43@implementation WebGLLayer
44
45@synthesize context=_context;
46
47-(id)initWithGraphicsContext3D:(GraphicsContext3D*)context
48{
49    _context = context;
50    self = [super init];
51    return self;
52}
53
54#if !PLATFORM(IOS)
55-(CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask
56{
57    // FIXME: The mask param tells you which display (on a multi-display system)
58    // is to be used. But since we are now getting the pixel format from the
59    // Canvas CGL context, we don't use it. This seems to do the right thing on
60    // one multi-display system. But there may be cases where this is not the case.
61    // If needed we will have to set the display mask in the Canvas CGLContext and
62    // make sure it matches.
63    UNUSED_PARAM(mask);
64    return CGLRetainPixelFormat(CGLGetPixelFormat(_context->platformGraphicsContext3D()));
65}
66
67-(CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat
68{
69    CGLContextObj contextObj;
70    CGLCreateContext(pixelFormat, _context->platformGraphicsContext3D(), &contextObj);
71    return contextObj;
72}
73
74-(void)drawInCGLContext:(CGLContextObj)glContext pixelFormat:(CGLPixelFormatObj)pixelFormat forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp
75{
76    if (!_context)
77        return;
78
79    _context->prepareTexture();
80
81    CGLSetCurrentContext(glContext);
82
83    CGRect frame = [self frame];
84
85    // draw the FBO into the layer
86    glViewport(0, 0, frame.size.width, frame.size.height);
87    glMatrixMode(GL_PROJECTION);
88    glLoadIdentity();
89    glOrtho(-1, 1, -1, 1, -1, 1);
90    glMatrixMode(GL_MODELVIEW);
91    glLoadIdentity();
92
93    glEnable(GL_TEXTURE_2D);
94    glBindTexture(GL_TEXTURE_2D, _context->platformTexture());
95
96    glBegin(GL_TRIANGLE_FAN);
97        glTexCoord2f(0, 0);
98        glVertex2f(-1, -1);
99        glTexCoord2f(1, 0);
100        glVertex2f(1, -1);
101        glTexCoord2f(1, 1);
102        glVertex2f(1, 1);
103        glTexCoord2f(0, 1);
104        glVertex2f(-1, 1);
105    glEnd();
106
107    glBindTexture(GL_TEXTURE_2D, 0);
108    glDisable(GL_TEXTURE_2D);
109
110    // Call super to finalize the drawing. By default all it does is call glFlush().
111    [super drawInCGLContext:glContext pixelFormat:pixelFormat forLayerTime:timeInterval displayTime:timeStamp];
112}
113
114static void freeData(void *, const void *data, size_t /* size */)
115{
116    fastFree(const_cast<void *>(data));
117}
118#endif
119
120-(CGImageRef)copyImageSnapshotWithColorSpace:(CGColorSpaceRef)colorSpace
121{
122    if (!_context)
123        return nullptr;
124
125#if PLATFORM(IOS)
126    UNUSED_PARAM(colorSpace);
127    return nullptr;
128#else
129    CGLSetCurrentContext(_context->platformGraphicsContext3D());
130
131    RetainPtr<CGColorSpaceRef> imageColorSpace = colorSpace;
132    if (!imageColorSpace)
133        imageColorSpace = adoptCF(CGColorSpaceCreateDeviceRGB());
134
135    CGRect layerBounds = CGRectIntegral([self bounds]);
136
137    size_t width = layerBounds.size.width;
138    size_t height = layerBounds.size.height;
139
140    size_t rowBytes = (width * 4 + 15) & ~15;
141    size_t dataSize = rowBytes * height;
142    void* data = fastMalloc(dataSize);
143    if (!data)
144        return nullptr;
145
146    glPixelStorei(GL_PACK_ROW_LENGTH, rowBytes / 4);
147    glReadPixels(0, 0, width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, data);
148
149    CGDataProviderRef provider = CGDataProviderCreateWithData(0, data, dataSize, freeData);
150    CGImageRef image = CGImageCreate(width, height, 8, 32, rowBytes, imageColorSpace.get(),
151                                                 kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,
152                                                 provider, 0, true,
153                                                 kCGRenderingIntentDefault);
154    CGDataProviderRelease(provider);
155    return image;
156#endif
157}
158
159- (void)display
160{
161    if (!_context)
162        return;
163
164#if PLATFORM(IOS)
165    _context->endPaint();
166#else
167    [super display];
168#endif
169    _context->markLayerComposited();
170}
171
172@end
173
174#endif // ENABLE(WEBGL)
175