1/*
2 Copyright (C) 2010 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 "TextureMapperGL.h"
22
23#include "GraphicsContext.h"
24#include "Image.h"
25#include "Timer.h"
26#include <wtf/HashMap.h>
27#include <wtf/PassRefPtr.h>
28#include <wtf/RefCounted.h>
29
30#if defined(TEXMAP_OPENGL_ES_2)
31#include <GLES2/gl2.h>
32#elif OS(MAC_OS_X)
33#include <AGL/agl.h>
34#include <gl.h>
35#else
36#if OS(UNIX)
37#include <GL/glx.h>
38#endif
39#include <GL/gl.h>
40#endif
41
42#ifndef TEXMAP_OPENGL_ES2
43extern "C" {
44    void glUniform1f(GLint, GLfloat);
45    void glUniform1i(GLint, GLint);
46    void glVertexAttribPointer(GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid*);
47    void glUniform4f(GLint, GLfloat, GLfloat, GLfloat, GLfloat);
48    void glShaderSource(GLuint, GLsizei, const char**, const GLint*);
49    GLuint glCreateShader(GLenum);
50    void glShaderSource(GLuint, GLsizei, const char**, const GLint*);
51    void glCompileShader(GLuint);
52    void glDeleteShader(GLuint);
53    void glUniformMatrix4fv(GLint, GLsizei, GLboolean, const GLfloat*);
54    GLuint glCreateProgram();
55    void glAttachShader(GLuint, GLuint);
56    void glLinkProgram(GLuint);
57    void glUseProgram(GLuint);
58    void glDisableVertexAttribArray(GLuint);
59    void glEnableVertexAttribArray(GLuint);
60    void glBindFramebuffer(GLenum target, GLuint framebuffer);
61    void glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers);
62    void glGenFramebuffers(GLsizei n, GLuint* framebuffers);
63    void glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
64    void glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params);
65    void glBindBuffer(GLenum, GLuint);
66    void glDeleteBuffers(GLsizei, const GLuint*);
67    void glGenBuffers(GLsizei, GLuint*);
68    void glBufferData(GLenum, GLsizeiptr, const GLvoid*, GLenum);
69    void glBufferSubData(GLenum, GLsizeiptr, GLsizeiptr, const GLvoid*);
70    void glGetProgramInfoLog(GLuint program, GLsizei, GLsizei*, GLchar*);
71
72#if !OS(MAC_OS_X)
73    GLint glGetUniformLocation(GLuint, const GLchar*);
74    GLint glBindAttribLocation(GLuint, GLuint, const GLchar*);
75#endif
76}
77#endif
78
79namespace WebCore {
80
81inline static void debugGLCommand(const char* command, int line)
82{
83    const GLenum err = glGetError();
84    if (!err)
85        return;
86    WTFReportError(__FILE__, line, WTF_PRETTY_FUNCTION, "[TextureMapper GL] Command failed: %s (%x)\n", command, err);
87}
88
89#define DEBUG_GL_COMMANDS
90
91#ifdef DEBUG_GL_COMMANDS
92#define GL_CMD(x) {x, debugGLCommand(#x, __LINE__); }
93#else
94#define GL_CMD(x) x
95#endif
96
97static const GLuint gInVertexAttributeIndex = 0;
98
99struct TextureMapperGLData {
100    static struct ShaderInfo {
101        enum ShaderProgramIndex {
102            SimpleProgram,
103            OpacityAndMaskProgram,
104            TargetProgram,
105
106            ProgramCount
107        };
108
109        enum ShaderVariableIndex {
110            InMatrixVariable,
111            InSourceMatrixVariable,
112            InMaskMatrixVariable,
113            OpacityVariable,
114            SourceTextureVariable,
115            MaskTextureVariable,
116
117            VariableCount
118        };
119
120        struct ProgramInfo {
121            GLuint id;
122            GLint vars[VariableCount];
123        };
124
125        GLint getUniformLocation(ShaderProgramIndex prog, ShaderVariableIndex var, const char* name)
126        {
127            return programs[prog].vars[var] = glGetUniformLocation(programs[prog].id, name);
128        }
129
130        void createShaderProgram(const char* vertexShaderSource, const char* fragmentShaderSource, ShaderProgramIndex index)
131        {
132            GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
133            GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
134            GL_CMD(glShaderSource(vertexShader, 1, &vertexShaderSource, 0))
135            GL_CMD(glShaderSource(fragmentShader, 1, &fragmentShaderSource, 0))
136            GLuint programID = glCreateProgram();
137            GL_CMD(glCompileShader(vertexShader))
138            GL_CMD(glCompileShader(fragmentShader))
139            GL_CMD(glAttachShader(programID, vertexShader))
140            GL_CMD(glAttachShader(programID, fragmentShader))
141            GL_CMD(glBindAttribLocation(programID, gInVertexAttributeIndex, "InVertex"))
142            GL_CMD(glLinkProgram(programID))
143            programs[index].id = programID;
144#ifdef PRINT_PROGRAM_INFO_LOG
145            char infoLog[1024];
146            int len;
147            GL_CMD(glGetProgramInfoLog(programID, 1024, &len, infoLog));
148            LOG(Graphics, "Compiled program for texture mapper. Log: %s\n", infoLog);
149#endif
150        }
151
152        ProgramInfo programs[ProgramCount];
153
154    } shaderInfo;
155
156    struct DirectlyCompositedImageRepository {
157        struct Entry {
158            GLuint texture;
159            int refCount;
160        };
161        HashMap<NativeImagePtr, Entry> imageToTexture;
162
163        GLuint findOrCreate(NativeImagePtr image, bool& found)
164        {
165            HashMap<NativeImagePtr, Entry>::iterator it = imageToTexture.find(image);
166            found = false;
167            if (it != imageToTexture.end()) {
168                it->second.refCount++;
169                found = true;
170                return it->second.texture;
171            }
172            Entry entry;
173            GL_CMD(glGenTextures(1, &entry.texture));
174            entry.refCount = 1;
175            imageToTexture.add(image, entry);
176            return entry.texture;
177        }
178
179        bool deref(NativeImagePtr image)
180        {
181            HashMap<NativeImagePtr, Entry>::iterator it = imageToTexture.find(image);
182            if (it != imageToTexture.end()) {
183                if (it->second.refCount < 2) {
184                    imageToTexture.remove(it);
185                    return false;
186                }
187            }
188            return true;
189        }
190
191        DirectlyCompositedImageRepository()
192        {
193        }
194
195        ~DirectlyCompositedImageRepository()
196        {
197            for (HashMap<NativeImagePtr, Entry>::iterator it = imageToTexture.begin(); it != imageToTexture.end(); ++it) {
198                GLuint texture = it->second.texture;
199                if (texture)
200                    GL_CMD(glDeleteTextures(1, &texture));
201            }
202
203        }
204    } directlyCompositedImages;
205
206    TextureMapperGLData()
207        : currentProgram(TextureMapperGLData::ShaderInfo::TargetProgram)
208    { }
209
210    TransformationMatrix projectionMatrix;
211    int currentProgram;
212
213#if OS(MAC_OS_X)
214    AGLContext aglContext;
215#elif OS(UNIX)
216    Drawable glxDrawable;
217    GLXContext glxContext;
218#endif
219};
220
221TextureMapperGLData::ShaderInfo TextureMapperGLData::shaderInfo;
222
223class BitmapTextureGL : public BitmapTexture {
224public:
225    virtual void destroy();
226    virtual IntSize size() const;
227    virtual bool isValid() const;
228    virtual void reset(const IntSize&, bool opaque);
229    virtual PlatformGraphicsContext* beginPaint(const IntRect& dirtyRect);
230    virtual void endPaint();
231    virtual void setContentsToImage(Image*);
232    ~BitmapTextureGL() { destroy(); }
233
234private:
235    GLuint m_id;
236    NativeImagePtr m_image;
237    FloatSize m_relativeSize;
238    bool m_opaque;
239    IntSize m_textureSize;
240    RefPtr<RGBA32PremultimpliedBuffer> m_buffer;
241    IntRect m_dirtyRect;
242    GLuint m_fbo;
243    IntSize m_actualSize;
244    bool m_surfaceNeedsReset;
245    TextureMapperGL* m_textureMapper;
246    BitmapTextureGL()
247        : m_id(0)
248        , m_image(0)
249        , m_opaque(false)
250        , m_fbo(0)
251        , m_surfaceNeedsReset(true)
252        , m_textureMapper(0)
253    {
254    }
255
256    friend class TextureMapperGL;
257};
258
259#define TEXMAP_GET_SHADER_VAR_LOCATION(prog, var) \
260    if (TextureMapperGLData::shaderInfo.getUniformLocation(TextureMapperGLData::shaderInfo.prog##Program, TextureMapperGLData::shaderInfo.var##Variable, #var) < 0) \
261            LOG_ERROR("Couldn't find variable "#var" in program "#prog"\n");
262
263#define TEXMAP_BUILD_SHADER(program) \
264    TextureMapperGLData::shaderInfo.createShaderProgram(vertexShaderSource##program, fragmentShaderSource##program, TextureMapperGLData::shaderInfo.program##Program);
265
266TextureMapperGL::TextureMapperGL()
267    : m_data(new TextureMapperGLData)
268{
269    static bool shadersCompiled = false;
270    obtainCurrentContext();
271    if (shadersCompiled)
272        return;
273    shadersCompiled = true;
274#ifndef TEXMAP_OPENGL_ES2
275#define OES2_PRECISION_DEFINITIONS \
276    "#define lowp\n#define highp\n"
277#else
278#define OES2_PRECISION_DEFINITIONS
279#endif
280
281    const char* fragmentShaderSourceOpacityAndMask =
282            OES2_PRECISION_DEFINITIONS
283"               uniform sampler2D SourceTexture, MaskTexture;                       \n"
284"               uniform lowp float Opacity;                                         \n"
285"               varying highp vec2 OutTexCoordSource, OutTexCoordMask;              \n"
286"               void main(void)                                                     \n"
287"               {                                                                   \n"
288"                   lowp vec4 color = texture2D(SourceTexture, OutTexCoordSource);  \n"
289"                   lowp vec4 maskColor = texture2D(MaskTexture, OutTexCoordMask);  \n"
290"                   lowp float o = Opacity * maskColor.a;                           \n"
291"                   gl_FragColor = vec4(color.rgb * o, color.a * o);                \n"
292"               }                                                                   \n";
293
294    const char* vertexShaderSourceOpacityAndMask =
295            OES2_PRECISION_DEFINITIONS
296"               uniform mat4 InMatrix, InSourceMatrix, InMaskMatrix;            \n"
297"               attribute vec4 InVertex;                                        \n"
298"               varying highp vec2 OutTexCoordSource, OutTexCoordMask;          \n"
299"               void main(void)                                                 \n"
300"               {                                                               \n"
301"                   OutTexCoordSource = vec2(InSourceMatrix * InVertex);        \n"
302"                   OutTexCoordMask = vec2(InMaskMatrix * InVertex);            \n"
303"                   gl_Position = InMatrix * InVertex;                          \n"
304"               }                                                               \n";
305
306    const char* fragmentShaderSourceSimple =
307            OES2_PRECISION_DEFINITIONS
308"               uniform sampler2D SourceTexture;                                    \n"
309"               uniform lowp float Opacity;                                         \n"
310"               varying highp vec2 OutTexCoordSource;                               \n"
311"               void main(void)                                                     \n"
312"               {                                                                   \n"
313"                   lowp vec4 color = texture2D(SourceTexture, OutTexCoordSource);  \n"
314"                   gl_FragColor = vec4(color.rgb * Opacity, color.a * Opacity);    \n"
315"               }                                                                   \n";
316
317    const char* vertexShaderSourceSimple =
318            OES2_PRECISION_DEFINITIONS
319"               uniform mat4 InMatrix, InSourceMatrix;                      \n"
320"               attribute vec4 InVertex;                                    \n"
321"               varying highp vec2 OutTexCoordSource;                       \n"
322"               void main(void)                                             \n"
323"               {                                                           \n"
324"                   OutTexCoordSource = vec2(InSourceMatrix * InVertex);    \n"
325"                   gl_Position = InMatrix * InVertex;                      \n"
326"               }                                                           \n";
327
328    const char* fragmentShaderSourceTarget =
329            OES2_PRECISION_DEFINITIONS
330"               uniform sampler2D SourceTexture;                                            \n"
331"               uniform lowp float Opacity;                                                 \n"
332"               varying highp vec2 OutTexCoordSource;                                       \n"
333"               void main(void)                                                             \n"
334"               {                                                                           \n"
335"                   lowp vec4 color = texture2D(SourceTexture, OutTexCoordSource);          \n"
336"                   gl_FragColor = vec4(color.bgr * Opacity, color.a * Opacity);            \n"
337"               }                                                                           \n";
338
339    const char* vertexShaderSourceTarget = vertexShaderSourceSimple;
340
341    TEXMAP_BUILD_SHADER(Simple)
342    TEXMAP_BUILD_SHADER(OpacityAndMask)
343    TEXMAP_BUILD_SHADER(Target)
344
345    TEXMAP_GET_SHADER_VAR_LOCATION(OpacityAndMask, InMatrix)
346    TEXMAP_GET_SHADER_VAR_LOCATION(OpacityAndMask, InSourceMatrix)
347    TEXMAP_GET_SHADER_VAR_LOCATION(OpacityAndMask, InMaskMatrix)
348    TEXMAP_GET_SHADER_VAR_LOCATION(OpacityAndMask, SourceTexture)
349    TEXMAP_GET_SHADER_VAR_LOCATION(OpacityAndMask, MaskTexture)
350    TEXMAP_GET_SHADER_VAR_LOCATION(OpacityAndMask, Opacity)
351
352    TEXMAP_GET_SHADER_VAR_LOCATION(Simple, InSourceMatrix)
353    TEXMAP_GET_SHADER_VAR_LOCATION(Simple, InMatrix)
354    TEXMAP_GET_SHADER_VAR_LOCATION(Simple, SourceTexture)
355    TEXMAP_GET_SHADER_VAR_LOCATION(Simple, Opacity)
356
357    TEXMAP_GET_SHADER_VAR_LOCATION(Target, InSourceMatrix)
358    TEXMAP_GET_SHADER_VAR_LOCATION(Target, InMatrix)
359    TEXMAP_GET_SHADER_VAR_LOCATION(Target, SourceTexture)
360    TEXMAP_GET_SHADER_VAR_LOCATION(Target, Opacity)
361}
362
363void TextureMapperGL::drawTexture(const BitmapTexture& texture, const IntRect& targetRect, const TransformationMatrix& modelViewMatrix, float opacity, const BitmapTexture* maskTexture)
364{
365    if (!texture.isValid())
366        return;
367
368    const BitmapTextureGL& textureGL = static_cast<const BitmapTextureGL&>(texture);
369
370    TextureMapperGLData::ShaderInfo::ShaderProgramIndex program;
371    if (maskTexture)
372        program = TextureMapperGLData::ShaderInfo::OpacityAndMaskProgram;
373    else
374        program = TextureMapperGLData::ShaderInfo::SimpleProgram;
375
376    const TextureMapperGLData::ShaderInfo::ProgramInfo& programInfo = data().shaderInfo.programs[program];
377    if (data().currentProgram != program) {
378        GL_CMD(glUseProgram(programInfo.id))
379        GL_CMD(glDisableVertexAttribArray(gInVertexAttributeIndex))
380        data().currentProgram = program;
381        GL_CMD(glEnableVertexAttribArray(gInVertexAttributeIndex))
382    }
383
384    GL_CMD(glDisable(GL_DEPTH_TEST))
385    GL_CMD(glDisable(GL_STENCIL_TEST))
386
387    GL_CMD(glActiveTexture(GL_TEXTURE0))
388    GL_CMD(glBindTexture(GL_TEXTURE_2D, textureGL.m_id))
389    GL_CMD(glBindBuffer(GL_ARRAY_BUFFER, 0))
390    const GLfloat unitRect[] = {0, 0, 1, 0, 1, 1, 0, 1};
391    GL_CMD(glVertexAttribPointer(gInVertexAttributeIndex, 2, GL_FLOAT, GL_FALSE, 0, unitRect))
392
393    TransformationMatrix matrix = TransformationMatrix(data().projectionMatrix).multiply(modelViewMatrix).multiply(TransformationMatrix(
394            targetRect.width(), 0, 0, 0,
395            0, targetRect.height(), 0, 0,
396            0, 0, 1, 0,
397            targetRect.x(), targetRect.y(), 0, 1));
398
399    const GLfloat m4[] = {
400        matrix.m11(), matrix.m12(), matrix.m13(), matrix.m14(),
401        matrix.m21(), matrix.m22(), matrix.m23(), matrix.m24(),
402        matrix.m31(), matrix.m32(), matrix.m33(), matrix.m34(),
403        matrix.m41(), matrix.m42(), matrix.m43(), matrix.m44()
404    };
405    const GLfloat m4src[] = {textureGL.m_relativeSize.width(), 0, 0, 0,
406                                     0, textureGL.m_relativeSize.height(), 0, 0,
407                                     0, 0, 1, 0,
408                                     0, 0, 0, 1};
409    GL_CMD(glUniformMatrix4fv(programInfo.vars[TextureMapperGLData::ShaderInfo::InMatrixVariable], 1, GL_FALSE, m4))
410    GL_CMD(glUniformMatrix4fv(programInfo.vars[TextureMapperGLData::ShaderInfo::InSourceMatrixVariable], 1, GL_FALSE, m4src))
411    GL_CMD(glUniform1i(programInfo.vars[TextureMapperGLData::ShaderInfo::SourceTextureVariable], 0))
412    GL_CMD(glUniform1f(programInfo.vars[TextureMapperGLData::ShaderInfo::OpacityVariable], opacity))
413
414    if (maskTexture && maskTexture->isValid()) {
415        const BitmapTextureGL* maskTextureGL = static_cast<const BitmapTextureGL*>(maskTexture);
416        GL_CMD(glActiveTexture(GL_TEXTURE1))
417        GL_CMD(glBindTexture(GL_TEXTURE_2D, maskTextureGL->m_id))
418        const GLfloat m4mask[] = {maskTextureGL->m_relativeSize.width(), 0, 0, 0,
419                                         0, maskTextureGL->m_relativeSize.height(), 0, 0,
420                                         0, 0, 1, 0,
421                                         0, 0, 0, 1};
422        GL_CMD(glUniformMatrix4fv(programInfo.vars[TextureMapperGLData::ShaderInfo::InMaskMatrixVariable], 1, GL_FALSE, m4mask));
423        GL_CMD(glUniform1i(programInfo.vars[TextureMapperGLData::ShaderInfo::MaskTextureVariable], 1))
424        GL_CMD(glActiveTexture(GL_TEXTURE0))
425    }
426
427    if (textureGL.m_opaque && opacity > 0.99 && !maskTexture)
428        GL_CMD(glDisable(GL_BLEND))
429    else {
430        GL_CMD(glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA))
431        GL_CMD(glEnable(GL_BLEND))
432    }
433
434    GL_CMD(glDrawArrays(GL_TRIANGLE_FAN, 0, 4))
435}
436
437const char* TextureMapperGL::type() const
438{
439    return "OpenGL";
440}
441
442void BitmapTextureGL::reset(const IntSize& newSize, bool opaque)
443{
444    BitmapTexture::reset(newSize, opaque);
445    m_image = 0;
446    IntSize newTextureSize = nextPowerOfTwo(newSize);
447    bool justCreated = false;
448    if (!m_id) {
449        GL_CMD(glGenTextures(1, &m_id))
450        justCreated = true;
451    }
452
453    if (justCreated || newTextureSize.width() > m_textureSize.width() || newTextureSize.height() > m_textureSize.height()) {
454        m_textureSize = newTextureSize;
455        GL_CMD(glBindTexture(GL_TEXTURE_2D, m_id))
456        GL_CMD(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR))
457        GL_CMD(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR))
458        GL_CMD(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE))
459        GL_CMD(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE))
460        GL_CMD(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_textureSize.width(), m_textureSize.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0))
461    }
462    m_actualSize = newSize;
463    m_relativeSize = FloatSize(float(newSize.width()) / m_textureSize.width(), float(newSize.height()) / m_textureSize.height());
464    m_opaque = opaque;
465    m_surfaceNeedsReset = true;
466}
467
468PlatformGraphicsContext* BitmapTextureGL::beginPaint(const IntRect& dirtyRect)
469{
470    m_buffer = RGBA32PremultimpliedBuffer::create();
471    m_dirtyRect = dirtyRect;
472    return m_buffer->beginPaint(dirtyRect, m_opaque);
473}
474
475void BitmapTextureGL::endPaint()
476{
477    if (!m_buffer)
478        return;
479    m_buffer->endPaint();
480    GL_CMD(glBindTexture(GL_TEXTURE_2D, m_id))
481    GL_CMD(glTexSubImage2D(GL_TEXTURE_2D, 0, m_dirtyRect.x(), m_dirtyRect.y(), m_dirtyRect.width(), m_dirtyRect.height(), GL_RGBA, GL_UNSIGNED_BYTE, m_buffer->data()))
482    m_buffer.clear();
483}
484
485void BitmapTextureGL::setContentsToImage(Image* image)
486{
487    NativeImagePtr nativeImage = image ? image->nativeImageForCurrentFrame() : 0;
488    if (!image || !nativeImage) {
489        if (m_image)
490            destroy();
491        return;
492    }
493
494    if (nativeImage == m_image)
495        return;
496    bool found = false;
497    GLuint newTextureID = m_textureMapper->data().directlyCompositedImages.findOrCreate(nativeImage, found);
498    if (newTextureID != m_id) {
499        destroy();
500        m_id = newTextureID;
501        reset(image->size(), false);
502        m_image = nativeImage;
503        if (!found) {
504            GraphicsContext context(beginPaint(IntRect(0, 0, m_textureSize.width(), m_textureSize.height())));
505            context.drawImage(image, ColorSpaceDeviceRGB, IntPoint(0, 0), CompositeCopy);
506            endPaint();
507        }
508    }
509}
510
511void BitmapTextureGL::destroy()
512{
513    if (m_id && (!m_image || !m_textureMapper->data().directlyCompositedImages.deref(m_image)))
514        GL_CMD(glDeleteTextures(1, &m_id))
515    if (m_fbo)
516        GL_CMD(glDeleteFramebuffers(1, &m_fbo))
517
518    m_fbo = 0;
519    m_id = 0;
520    m_textureSize = IntSize();
521    m_relativeSize = FloatSize(1, 1);
522}
523
524bool BitmapTextureGL::isValid() const
525{
526    return m_id;
527}
528
529IntSize BitmapTextureGL::size() const
530{
531    return m_textureSize;
532}
533
534static inline TransformationMatrix createProjectionMatrix(const IntSize& size, bool flip)
535{
536    return TransformationMatrix(2.0 / float(size.width()), 0, 0, 0,
537                                0, (flip ? -2.0 : 2.0) / float(size.height()), 0, 0,
538                                0, 0, -0.000001, 0,
539                                -1, flip ? 1 : -1, 0, 1);
540}
541
542TextureMapperGL::~TextureMapperGL()
543{
544    makeContextCurrent();
545    delete m_data;
546}
547
548bool TextureMapperGL::makeContextCurrent()
549{
550#if OS(MAC_OS_X)
551    return aglSetCurrentContext(data().aglContext);
552#elif OS(UNIX)
553    Display* display = XOpenDisplay(0);
554    if (!display)
555        return false;
556    return glXMakeCurrent(display, data().glxDrawable, data().glxContext);
557#endif
558}
559
560void TextureMapperGL::obtainCurrentContext()
561{
562#if OS(MAC_OS_X)
563    data().aglContext = aglGetCurrentContext();
564#elif OS(UNIX)
565    data().glxDrawable = glXGetCurrentDrawable();
566    data().glxContext = glXGetCurrentContext();
567#endif
568}
569
570void TextureMapperGL::bindSurface(BitmapTexture *surfacePointer)
571{
572    BitmapTextureGL* surface = static_cast<BitmapTextureGL*>(surfacePointer);
573
574    if (!surface)
575        return;
576
577    TransformationMatrix matrix = createProjectionMatrix(surface->size(), false);
578    matrix.translate(-surface->offset().x(), -surface->offset().y());
579
580    if (surface->m_surfaceNeedsReset || !surface->m_fbo) {
581        if (!surface->m_fbo)
582            GL_CMD(glGenFramebuffers(1, &surface->m_fbo))
583        GL_CMD(glBindFramebuffer(GL_FRAMEBUFFER, surface->m_fbo))
584        GL_CMD(glBindTexture(GL_TEXTURE_2D, 0))
585        GL_CMD(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, surface->m_id, 0))
586        GL_CMD(glClearColor(0, 0, 0, 0))
587        GL_CMD(glClear(GL_COLOR_BUFFER_BIT))
588        surface->m_surfaceNeedsReset = false;
589    } else {
590        GL_CMD(glBindFramebuffer(GL_FRAMEBUFFER, surface->m_fbo))
591    }
592
593    GL_CMD(glViewport(0, 0, surface->size().width(), surface->size().height()))
594    data().projectionMatrix = matrix;
595}
596
597void TextureMapperGL::setClip(const IntRect& rect)
598{
599    GL_CMD(glScissor(rect.x(), rect.y(), rect.width(), rect.height()))
600    GL_CMD(glEnable(GL_SCISSOR_TEST))
601}
602
603
604void TextureMapperGL::paintToTarget(const BitmapTexture& aSurface, const IntSize& surfaceSize, const TransformationMatrix& transform, float opacity, const IntRect& visibleRect)
605{
606    const BitmapTextureGL& surface = static_cast<const BitmapTextureGL&>(aSurface);
607
608    // Create the model-view-projection matrix to display on screen.
609    TransformationMatrix matrix = createProjectionMatrix(surfaceSize, true).multiply(transform).multiply(
610                TransformationMatrix(
611                        surface.m_actualSize.width(), 0, 0, 0,
612                        0, surface.m_actualSize.height(), 0, 0,
613                        0, 0, 1, 0,
614                        surface.offset().x(), surface.offset().y(), 0, 1)
615            );
616
617    const GLfloat m4[] = {
618        matrix.m11(), matrix.m12(), matrix.m13(), matrix.m14(),
619        matrix.m21(), matrix.m22(), matrix.m23(), matrix.m24(),
620        matrix.m31(), matrix.m32(), matrix.m33(), matrix.m34(),
621        matrix.m41(), matrix.m42(), matrix.m43(), matrix.m44()
622    };
623
624    const GLfloat m4src[] = {surface.m_relativeSize.width(), 0, 0, 0,
625                                     0, surface.m_relativeSize.height(), 0, 0,
626                                     0, 0, 1, 0,
627                                     0, 0, 0, 1};
628
629    // We already blended the alpha in; the result is premultiplied.
630    GL_CMD(glUseProgram(data().shaderInfo.programs[TextureMapperGLData::ShaderInfo::TargetProgram].id))
631    GL_CMD(glBindFramebuffer(GL_FRAMEBUFFER, 0))
632    GL_CMD(glViewport(0, 0, surfaceSize.width(), surfaceSize.height()))
633    GL_CMD(glDisable(GL_STENCIL_TEST))
634    const TextureMapperGLData::ShaderInfo::ProgramInfo& programInfo = data().shaderInfo.programs[TextureMapperGLData::ShaderInfo::TargetProgram];
635    GL_CMD(glUniform1f(programInfo.vars[TextureMapperGLData::ShaderInfo::OpacityVariable], opacity))
636    GL_CMD(glActiveTexture(GL_TEXTURE0))
637    GL_CMD(glBindTexture(GL_TEXTURE_2D, surface.m_id))
638    GL_CMD(glUniform1i(programInfo.vars[TextureMapperGLData::ShaderInfo::SourceTextureVariable], 0))
639    GL_CMD(glEnableVertexAttribArray(gInVertexAttributeIndex))
640    GL_CMD(glUniformMatrix4fv(programInfo.vars[TextureMapperGLData::ShaderInfo::InMatrixVariable], 1, GL_FALSE, m4))
641    GL_CMD(glUniformMatrix4fv(programInfo.vars[TextureMapperGLData::ShaderInfo::InSourceMatrixVariable], 1, GL_FALSE, m4src))
642    GL_CMD(glBindBuffer(GL_ARRAY_BUFFER, 0))
643    const GLfloat unitRect[] = {0, 0, 1, 0, 1, 1, 0, 1};
644    GL_CMD(glVertexAttribPointer(gInVertexAttributeIndex, 2, GL_FLOAT, GL_FALSE, 0, unitRect))
645    GL_CMD(glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA))
646    GL_CMD(glEnable(GL_BLEND))
647    setClip(visibleRect);
648
649    GL_CMD(glDrawArrays(GL_TRIANGLE_FAN, 0, 4))
650    GL_CMD(glDisableVertexAttribArray(0))
651    GL_CMD(glUseProgram(0))
652    GL_CMD(glBindBuffer(GL_ARRAY_BUFFER, 0))
653    data().currentProgram = TextureMapperGLData::ShaderInfo::TargetProgram;
654}
655
656PassRefPtr<BitmapTexture> TextureMapperGL::createTexture()
657{
658    BitmapTextureGL* texture = new BitmapTextureGL();
659    texture->m_textureMapper = this;
660    return adoptRef(texture);
661}
662
663};
664