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
43 extern "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
79 namespace WebCore {
80
debugGLCommand(const char * command,int line)81 inline 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
97 static const GLuint gInVertexAttributeIndex = 0;
98
99 struct 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
getUniformLocationWebCore::TextureMapperGLData::ShaderInfo125 GLint getUniformLocation(ShaderProgramIndex prog, ShaderVariableIndex var, const char* name)
126 {
127 return programs[prog].vars[var] = glGetUniformLocation(programs[prog].id, name);
128 }
129
createShaderProgramWebCore::TextureMapperGLData::ShaderInfo130 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
findOrCreateWebCore::TextureMapperGLData::DirectlyCompositedImageRepository163 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
derefWebCore::TextureMapperGLData::DirectlyCompositedImageRepository179 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
DirectlyCompositedImageRepositoryWebCore::TextureMapperGLData::DirectlyCompositedImageRepository191 DirectlyCompositedImageRepository()
192 {
193 }
194
~DirectlyCompositedImageRepositoryWebCore::TextureMapperGLData::DirectlyCompositedImageRepository195 ~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
TextureMapperGLDataWebCore::TextureMapperGLData206 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
221 TextureMapperGLData::ShaderInfo TextureMapperGLData::shaderInfo;
222
223 class BitmapTextureGL : public BitmapTexture {
224 public:
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*);
~BitmapTextureGL()232 ~BitmapTextureGL() { destroy(); }
233
234 private:
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;
BitmapTextureGL()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
TextureMapperGL()266 TextureMapperGL::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
drawTexture(const BitmapTexture & texture,const IntRect & targetRect,const TransformationMatrix & modelViewMatrix,float opacity,const BitmapTexture * maskTexture)363 void 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
type() const437 const char* TextureMapperGL::type() const
438 {
439 return "OpenGL";
440 }
441
reset(const IntSize & newSize,bool opaque)442 void 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
beginPaint(const IntRect & dirtyRect)468 PlatformGraphicsContext* 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
endPaint()475 void 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
setContentsToImage(Image * image)485 void 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
destroy()511 void 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
isValid() const524 bool BitmapTextureGL::isValid() const
525 {
526 return m_id;
527 }
528
size() const529 IntSize BitmapTextureGL::size() const
530 {
531 return m_textureSize;
532 }
533
createProjectionMatrix(const IntSize & size,bool flip)534 static 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
~TextureMapperGL()542 TextureMapperGL::~TextureMapperGL()
543 {
544 makeContextCurrent();
545 delete m_data;
546 }
547
makeContextCurrent()548 bool 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
obtainCurrentContext()560 void 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
bindSurface(BitmapTexture * surfacePointer)570 void 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
setClip(const IntRect & rect)597 void 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
paintToTarget(const BitmapTexture & aSurface,const IntSize & surfaceSize,const TransformationMatrix & transform,float opacity,const IntRect & visibleRect)604 void 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
createTexture()656 PassRefPtr<BitmapTexture> TextureMapperGL::createTexture()
657 {
658 BitmapTextureGL* texture = new BitmapTextureGL();
659 texture->m_textureMapper = this;
660 return adoptRef(texture);
661 }
662
663 };
664