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 "GLTransportSurface.h"
28
29#if USE(ACCELERATED_COMPOSITING)
30
31#include "FloatRect.h"
32
33#if USE(GLX)
34#include "GLXSurface.h"
35#endif
36
37#if USE(EGL)
38#include "EGLSurface.h"
39#endif
40
41#include <texmap/TextureMapperShaderProgram.h>
42
43namespace WebCore {
44
45static const GLfloat vertices[] = { 0, 0, 1, 0, 1, 1, 0, 1 };
46static bool vertexArrayObjectSupported = false;
47
48PassOwnPtr<GLTransportSurface> GLTransportSurface::createTransportSurface(const IntSize& size, SurfaceAttributes attributes)
49{
50    OwnPtr<GLTransportSurface> surface;
51#if USE(GLX)
52    surface = adoptPtr(new GLXTransportSurface(size, attributes));
53#elif USE(EGL)
54    surface = EGLTransportSurface::createTransportSurface(size, attributes);
55#endif
56
57    if (surface && surface->handle() && surface->drawable())
58        return surface.release();
59
60    return nullptr;
61}
62
63GLTransportSurface::GLTransportSurface(const IntSize& size, SurfaceAttributes attributes)
64    : GLPlatformSurface(attributes)
65    , m_vbo(0)
66    , m_vertexHandle(0)
67    , m_boundTexture(0)
68{
69    m_rect = IntRect(IntPoint(), size);
70}
71
72GLTransportSurface::~GLTransportSurface()
73{
74}
75
76void GLTransportSurface::updateContents(const uint32_t texture)
77{
78    if (!m_shaderProgram)
79        initializeShaderProgram();
80
81    draw(texture);
82    swapBuffers();
83}
84
85void GLTransportSurface::setGeometry(const IntRect& newRect)
86{
87    m_rect = newRect;
88
89    if (!m_shaderProgram)
90        return;
91
92    updateTransformationMatrix();
93}
94
95void GLTransportSurface::destroy()
96{
97    m_rect = IntRect();
98
99    if (!m_shaderProgram || !m_context3D)
100        return;
101
102    ::glBindFramebuffer(GL_FRAMEBUFFER, 0);
103    ::glBindTexture(GL_TEXTURE_2D, 0);
104    ::glBindBuffer(GL_ARRAY_BUFFER, 0);
105
106    if (m_vbo)
107        ::glDeleteBuffers(1, &m_vbo);
108
109    if (m_vertexHandle) {
110        m_context3D->getExtensions()->bindVertexArrayOES(0);
111        m_context3D->getExtensions()->deleteVertexArrayOES(m_vertexHandle);
112    } else if (m_shaderProgram)
113        ::glDisableVertexAttribArray(m_shaderProgram->vertexLocation());
114
115    ::glUseProgram(0);
116
117    m_shaderProgram = nullptr;
118    m_context3D = nullptr;
119    m_boundTexture = 0;
120}
121
122void GLTransportSurface::draw(const uint32_t texture)
123{
124    if (!m_vertexHandle)
125        bindArrayBuffer();
126
127    if (m_boundTexture != texture) {
128        ::glBindTexture(GL_TEXTURE_2D, texture);
129        m_boundTexture = texture;
130    }
131
132    ::glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
133}
134
135void GLTransportSurface::bindArrayBuffer() const
136{
137    ::glEnableVertexAttribArray(m_shaderProgram->vertexLocation());
138    ::glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
139    ::glVertexAttribPointer(m_shaderProgram->vertexLocation(), 2, GraphicsContext3D::FLOAT, false, 0, 0);
140}
141
142void GLTransportSurface::updateTransformationMatrix()
143{
144    if (!m_shaderProgram)
145        return;
146
147    ::glViewport(m_rect.x(), m_rect.y(), m_rect.width(), m_rect.height());
148    m_boundTexture = 0;
149
150    FloatRect targetRect = FloatRect(m_rect);
151    TransformationMatrix identityMatrix;
152    TransformationMatrix matrix = TransformationMatrix(identityMatrix).multiply(TransformationMatrix::rectToRect(FloatRect(0, 0, 1, 1), targetRect));
153    m_shaderProgram->setMatrix(m_shaderProgram->modelViewMatrixLocation(), matrix);
154
155    // Taken from TextureMapperGL.
156    const float nearValue = 9999999;
157    const float farValue = -99999;
158
159    TransformationMatrix projectionMatrix = TransformationMatrix(2.0 / float(m_rect.width()), 0, 0, 0,
160        0, (-2.0) / float(m_rect.height()), 0, 0,
161        0, 0, -2.f / (farValue - nearValue), 0,
162        -1, 1, -(farValue + nearValue) / (farValue - nearValue), 1);
163
164    m_shaderProgram->setMatrix(m_shaderProgram->projectionMatrixLocation(), projectionMatrix);
165}
166
167void GLTransportSurface::initializeShaderProgram()
168{
169    if (!m_context3D)
170        m_context3D = GraphicsContext3D::createForCurrentGLContext();
171
172    vertexArrayObjectSupported = m_context3D->getExtensions()->supports("GL_OES_vertex_array_object");
173
174    TextureMapperShaderProgram::Options options = TextureMapperShaderProgram::Texture;
175    m_shaderProgram = TextureMapperShaderProgram::create(m_context3D, options);
176
177    ::glUseProgram(m_shaderProgram->programID());
178    ::glUniform1i(m_shaderProgram->samplerLocation(), 0);
179    ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
180    ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
181    ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
182    ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
183
184    TransformationMatrix flipTransform;
185    flipTransform.flipY();
186    flipTransform.translate(0, -1);
187    m_shaderProgram->setMatrix(m_shaderProgram->textureSpaceMatrixLocation(), flipTransform);
188
189    ::glUniform1f(m_shaderProgram->opacityLocation(), 1.0);
190
191    if (!m_vbo) {
192        ::glGenBuffers(1, &m_vbo);
193        ::glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
194        ::glBufferData(GL_ARRAY_BUFFER, sizeof(GC3Dfloat) * 8, vertices, GL_STATIC_DRAW);
195    }
196
197    // Create and set-up vertex array object.
198    if (vertexArrayObjectSupported) {
199        m_vertexHandle = m_context3D->getExtensions()->createVertexArrayOES();
200
201        if (m_vertexHandle) {
202            m_context3D->getExtensions()->bindVertexArrayOES(m_vertexHandle);
203            bindArrayBuffer();
204        }
205    }
206
207    updateTransformationMatrix();
208}
209
210PassOwnPtr<GLTransportSurfaceClient> GLTransportSurfaceClient::createTransportSurfaceClient(const PlatformBufferHandle handle, const IntSize& size, bool hasAlpha)
211{
212    OwnPtr<GLTransportSurfaceClient> client;
213#if USE(GLX)
214    client = adoptPtr(new GLXTransportSurfaceClient(handle, hasAlpha));
215    UNUSED_PARAM(size);
216#else
217    client = EGLTransportSurface::createTransportSurfaceClient(handle, size, hasAlpha);
218#endif
219
220    if (!client || !client->texture()) {
221        LOG_ERROR("Failed to Create Transport Surface client.");
222        return nullptr;
223    }
224
225    return client.release();
226}
227
228
229GLTransportSurfaceClient::GLTransportSurfaceClient()
230    : m_texture(0)
231{
232}
233
234GLTransportSurfaceClient::~GLTransportSurfaceClient()
235{
236}
237
238void GLTransportSurfaceClient::destroy()
239{
240    if (m_texture) {
241        glBindTexture(GL_TEXTURE_2D, 0);
242        glDeleteTextures(1, &m_texture);
243        m_texture = 0;
244    }
245}
246
247void GLTransportSurfaceClient::prepareTexture()
248{
249}
250
251void GLTransportSurfaceClient::createTexture()
252{
253    ::glGenTextures(1, &m_texture);
254    ::glBindTexture(GL_TEXTURE_2D, m_texture);
255    ::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
256    ::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
257    ::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
258    ::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
259}
260
261}
262
263#endif
264