1/*
2 * Copyright (C) 2013 Intel Corporation. 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 "GraphicsSurface.h"
28
29#if USE(GRAPHICS_SURFACE)
30
31#include "GLPlatformContext.h"
32#include "GLTransportSurface.h"
33#include "NotImplemented.h"
34#include "TextureMapperGL.h"
35
36namespace WebCore {
37
38struct GraphicsSurfacePrivate {
39
40    GraphicsSurfacePrivate()
41    {
42    }
43
44    GraphicsSurfacePrivate(PlatformBufferHandle winId, const IntSize& size, GraphicsSurface::Flags flags)
45        : m_flags(0)
46        , m_rect(FloatPoint::zero(), size)
47        , m_size(size)
48        , m_sharedHandle(winId)
49    {
50        if (flags & GraphicsSurface::SupportsAlpha)
51            m_flags |= TextureMapperGL::ShouldBlend;
52    }
53
54    ~GraphicsSurfacePrivate()
55    {
56    }
57
58    void destroy()
59    {
60        if (m_client)
61            m_client->destroy();
62
63        if (m_sharedContext && m_sharedContext->handle() && m_sharedSurface)
64            makeContextCurrent();
65
66        if (m_sharedSurface)
67            m_sharedSurface->destroy();
68
69        if (m_sharedContext) {
70            m_sharedContext->destroy();
71            m_sharedContext->releaseCurrent();
72        }
73    }
74
75    bool initializeTransportSurface(const IntSize& size, GraphicsSurface::Flags flags, const PlatformGraphicsContext3D shareContext)
76    {
77        GLPlatformSurface::SurfaceAttributes sharedSurfaceAttributes = GLPlatformSurface::Default;
78        m_size = size;
79
80        if (flags & GraphicsSurface::SupportsAlpha)
81            sharedSurfaceAttributes = GLPlatformSurface::SupportAlpha;
82
83        m_sharedSurface = GLTransportSurface::createTransportSurface(size, sharedSurfaceAttributes);
84        if (!m_sharedSurface)
85            return false;
86
87        m_sharedContext = GLPlatformContext::createContext(GraphicsContext3D::RenderOffscreen);
88        if (!m_sharedContext)
89            return false;
90
91        if (!m_sharedContext->initialize(m_sharedSurface.get(), static_cast<PlatformContext>(shareContext)))
92            return false;
93
94        if (!makeContextCurrent())
95            return false;
96
97        return true;
98    }
99
100    bool makeContextCurrent() const
101    {
102        return m_sharedContext->makeCurrent(m_sharedSurface.get());
103    }
104
105    void copyFromTexture(GLuint textureId)
106    {
107        if (!makeContextCurrent())
108            return;
109
110        m_sharedSurface->updateContents(textureId);
111    }
112
113    PlatformBufferHandle handle() const
114    {
115        return m_sharedSurface->handle();
116    }
117
118    // Client
119    void updateClientBuffer()
120    {
121        if (!m_client)
122            return;
123
124        m_client->prepareTexture();
125    }
126
127    TextureMapperGL::Flags flags() const { return m_flags; }
128
129    const FloatRect& rect() const { return m_rect; }
130    const IntSize& size() const { return m_size; }
131
132    GLuint textureId() const
133    {
134        if (!m_client)
135            const_cast<GraphicsSurfacePrivate*>(this)->initializeClient();
136
137        return m_client ? m_client->texture() : 0;
138    }
139
140private:
141    void initializeClient()
142    {
143        m_client = GLTransportSurfaceClient::createTransportSurfaceClient(m_sharedHandle, m_size, m_flags & TextureMapperGL::ShouldBlend);
144
145        if (!m_client)
146            return;
147    }
148
149    TextureMapperGL::Flags m_flags;
150    FloatRect m_rect;
151    IntSize m_size;
152    PlatformBufferHandle m_sharedHandle;
153    OwnPtr<GLTransportSurfaceClient> m_client;
154    std::unique_ptr<GLPlatformContext> m_sharedContext;
155    OwnPtr<GLTransportSurface> m_sharedSurface;
156};
157
158GraphicsSurfaceToken GraphicsSurface::platformExport()
159{
160    return m_private->handle();
161}
162
163uint32_t GraphicsSurface::platformGetTextureID()
164{
165    return m_private->textureId();
166}
167
168void GraphicsSurface::platformCopyToGLTexture(uint32_t /*target*/, uint32_t /*id*/, const IntRect& /*targetRect*/, const IntPoint& /*offset*/)
169{
170    notImplemented();
171}
172
173void GraphicsSurface::platformCopyFromTexture(uint32_t textureId, const IntRect&)
174{
175    if (!m_private)
176        return;
177
178    m_private->copyFromTexture(textureId);
179}
180
181void GraphicsSurface::platformPaintToTextureMapper(TextureMapper* textureMapper, const FloatRect& targetRect, const TransformationMatrix& transform, float opacity)
182{
183    uint32_t texture = platformGetTextureID();
184    if (!texture)
185        return;
186
187    TransformationMatrix adjustedTransform = transform;
188    adjustedTransform.multiply(TransformationMatrix::rectToRect(m_private->rect(), targetRect));
189    static_cast<TextureMapperGL*>(textureMapper)->drawTexture(texture, m_private->flags(), m_private->size(), m_private->rect(), adjustedTransform, opacity);
190}
191
192uint32_t GraphicsSurface::platformFrontBuffer() const
193{
194    return 0;
195}
196
197uint32_t GraphicsSurface::platformSwapBuffers()
198{
199    m_private->updateClientBuffer();
200    return 0;
201}
202
203IntSize GraphicsSurface::platformSize() const
204{
205    return m_private->size();
206}
207
208PassRefPtr<GraphicsSurface> GraphicsSurface::platformCreate(const IntSize& size, Flags flags, const PlatformGraphicsContext3D shareContext)
209{
210    // GraphicsSurface doesn't yet support copyToTexture or singlebuffered surface.
211    if (flags & SupportsCopyToTexture || flags & SupportsSingleBuffered)
212        return PassRefPtr<GraphicsSurface>();
213
214    RefPtr<GraphicsSurface> surface = adoptRef(new GraphicsSurface(size, flags));
215    surface->m_private = new GraphicsSurfacePrivate();
216
217    if (surface->m_private->initializeTransportSurface(size, flags, shareContext))
218        return surface;
219
220    return PassRefPtr<GraphicsSurface>();
221}
222
223PassRefPtr<GraphicsSurface> GraphicsSurface::platformImport(const IntSize& size, Flags flags, const GraphicsSurfaceToken& token)
224{
225    // GraphicsSurface doesn't yet support copyToTexture or singlebuffered surface.
226    if (flags & SupportsCopyToTexture || flags & SupportsSingleBuffered)
227        return PassRefPtr<GraphicsSurface>();
228
229    RefPtr<GraphicsSurface> surface = adoptRef(new GraphicsSurface(size, flags));
230    surface->m_private = new GraphicsSurfacePrivate(token.frontBufferHandle, size, flags);
231    return surface;
232}
233
234char* GraphicsSurface::platformLock(const IntRect&, int* /*outputStride*/, LockOptions)
235{
236    // GraphicsSurface is currently only being used for WebGL, which does not require this locking mechanism.
237    return 0;
238}
239
240void GraphicsSurface::platformUnlock()
241{
242    // GraphicsSurface is currently only being used for WebGL, which does not require this locking mechanism.
243}
244
245void GraphicsSurface::platformDestroy()
246{
247    if (!m_private)
248        return;
249
250    m_private->destroy();
251
252    delete m_private;
253    m_private = 0;
254}
255
256std::unique_ptr<GraphicsContext> GraphicsSurface::platformBeginPaint(const IntSize&, char*, int)
257{
258    notImplemented();
259    return nullptr;
260}
261
262PassRefPtr<Image> GraphicsSurface::createReadOnlyImage(const IntRect&)
263{
264    notImplemented();
265    return 0;
266}
267
268}
269
270#endif
271