[TexMap] Seperate BitmapTexture related classes implementations from TextureMapper
[WebKit-https.git] / Source / WebCore / platform / graphics / texmap / BitmapTextureGL.cpp
1 /*
2  Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
3  Copyright (C) 2012 Igalia S.L.
4  Copyright (C) 2012 Adobe Systems Incorporated
5
6  This library is free software; you can redistribute it and/or
7  modify it under the terms of the GNU Library General Public
8  License as published by the Free Software Foundation; either
9  version 2 of the License, or (at your option) any later version.
10
11  This library is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  Library General Public License for more details.
15
16  You should have received a copy of the GNU Library General Public License
17  along with this library; see the file COPYING.LIB.  If not, write to
18  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  Boston, MA 02110-1301, USA.
20  */
21
22 #include "config.h"
23 #include "BitmapTextureGL.h"
24
25 #include "Extensions3D.h"
26 #include "FilterOperations.h"
27 #include "GraphicsContext.h"
28 #include "Image.h"
29 #include "LengthFunctions.h"
30 #include "NotImplemented.h"
31 #include "TextureMapperShaderProgram.h"
32 #include "Timer.h"
33 #include <wtf/HashMap.h>
34 #include <wtf/PassRefPtr.h>
35 #include <wtf/RefCounted.h>
36 #include <wtf/TemporaryChange.h>
37
38 #if USE(CAIRO)
39 #include "CairoUtilities.h"
40 #include "RefPtrCairo.h"
41 #include <cairo.h>
42 #include <wtf/text/CString.h>
43 #endif
44
45 #if !USE(TEXMAP_OPENGL_ES_2)
46 // FIXME: Move to Extensions3D.h.
47 #define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
48 #define GL_UNPACK_ROW_LENGTH 0x0CF2
49 #define GL_UNPACK_SKIP_PIXELS 0x0CF4
50 #define GL_UNPACK_SKIP_ROWS 0x0CF3
51 #endif
52
53 namespace WebCore {
54
55 BitmapTextureGL* toBitmapTextureGL(BitmapTexture* texture)
56 {
57     if (!texture || !texture->isBackedByOpenGL())
58         return 0;
59
60     return static_cast<BitmapTextureGL*>(texture);
61 }
62
63 BitmapTextureGL::BitmapTextureGL(PassRefPtr<GraphicsContext3D> context3D)
64     : m_id(0)
65     , m_fbo(0)
66     , m_rbo(0)
67     , m_depthBufferObject(0)
68     , m_shouldClear(true)
69     , m_context3D(context3D)
70 {
71 }
72
73 bool BitmapTextureGL::canReuseWith(const IntSize& contentsSize, Flags)
74 {
75     return contentsSize == m_textureSize;
76 }
77
78 #if OS(DARWIN)
79 #define DEFAULT_TEXTURE_PIXEL_TRANSFER_TYPE GL_UNSIGNED_INT_8_8_8_8_REV
80 #else
81 #define DEFAULT_TEXTURE_PIXEL_TRANSFER_TYPE GraphicsContext3D::UNSIGNED_BYTE
82 #endif
83
84 static void swizzleBGRAToRGBA(uint32_t* data, const IntRect& rect, int stride = 0)
85 {
86     stride = stride ? stride : rect.width();
87     for (int y = rect.y(); y < rect.maxY(); ++y) {
88         uint32_t* p = data + y * stride;
89         for (int x = rect.x(); x < rect.maxX(); ++x)
90             p[x] = ((p[x] << 16) & 0xff0000) | ((p[x] >> 16) & 0xff) | (p[x] & 0xff00ff00);
91     }
92 }
93
94 // If GL_EXT_texture_format_BGRA8888 is supported in the OpenGLES
95 // internal and external formats need to be BGRA
96 static bool driverSupportsExternalTextureBGRA(GraphicsContext3D* context)
97 {
98     if (context->isGLES2Compliant()) {
99         static bool supportsExternalTextureBGRA = context->getExtensions()->supports("GL_EXT_texture_format_BGRA8888");
100         return supportsExternalTextureBGRA;
101     }
102
103     return true;
104 }
105
106 static bool driverSupportsSubImage(GraphicsContext3D* context)
107 {
108     if (context->isGLES2Compliant()) {
109         static bool supportsSubImage = context->getExtensions()->supports("GL_EXT_unpack_subimage");
110         return supportsSubImage;
111     }
112
113     return true;
114 }
115
116 void BitmapTextureGL::didReset()
117 {
118     if (!m_id)
119         m_id = m_context3D->createTexture();
120
121     m_shouldClear = true;
122     if (m_textureSize == contentSize())
123         return;
124
125
126     m_textureSize = contentSize();
127     m_context3D->bindTexture(GraphicsContext3D::TEXTURE_2D, m_id);
128     m_context3D->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR);
129     m_context3D->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR);
130     m_context3D->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE);
131     m_context3D->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE);
132
133     Platform3DObject internalFormat = GraphicsContext3D::RGBA;
134     Platform3DObject externalFormat = GraphicsContext3D::BGRA;
135     if (m_context3D->isGLES2Compliant()) {
136         if (driverSupportsExternalTextureBGRA(m_context3D.get()))
137             internalFormat = GraphicsContext3D::BGRA;
138         else
139             externalFormat = GraphicsContext3D::RGBA;
140     }
141
142     m_context3D->texImage2DDirect(GraphicsContext3D::TEXTURE_2D, 0, internalFormat, m_textureSize.width(), m_textureSize.height(), 0, externalFormat, DEFAULT_TEXTURE_PIXEL_TRANSFER_TYPE, 0);
143 }
144
145 void BitmapTextureGL::updateContentsNoSwizzle(const void* srcData, const IntRect& targetRect, const IntPoint& sourceOffset, int bytesPerLine, unsigned bytesPerPixel, Platform3DObject glFormat)
146 {
147     m_context3D->bindTexture(GraphicsContext3D::TEXTURE_2D, m_id);
148     // For ES drivers that don't support sub-images.
149     if (driverSupportsSubImage(m_context3D.get())) {
150         // Use the OpenGL sub-image extension, now that we know it's available.
151         m_context3D->pixelStorei(GL_UNPACK_ROW_LENGTH, bytesPerLine / bytesPerPixel);
152         m_context3D->pixelStorei(GL_UNPACK_SKIP_ROWS, sourceOffset.y());
153         m_context3D->pixelStorei(GL_UNPACK_SKIP_PIXELS, sourceOffset.x());
154     }
155
156     m_context3D->texSubImage2D(GraphicsContext3D::TEXTURE_2D, 0, targetRect.x(), targetRect.y(), targetRect.width(), targetRect.height(), glFormat, DEFAULT_TEXTURE_PIXEL_TRANSFER_TYPE, srcData);
157
158     // For ES drivers that don't support sub-images.
159     if (driverSupportsSubImage(m_context3D.get())) {
160         m_context3D->pixelStorei(GL_UNPACK_ROW_LENGTH, 0);
161         m_context3D->pixelStorei(GL_UNPACK_SKIP_ROWS, 0);
162         m_context3D->pixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
163     }
164 }
165
166 void BitmapTextureGL::updateContents(const void* srcData, const IntRect& targetRect, const IntPoint& sourceOffset, int bytesPerLine, UpdateContentsFlag updateContentsFlag)
167 {
168     Platform3DObject glFormat = GraphicsContext3D::RGBA;
169     m_context3D->bindTexture(GraphicsContext3D::TEXTURE_2D, m_id);
170
171     const unsigned bytesPerPixel = 4;
172     char* data = reinterpret_cast<char*>(const_cast<void*>(srcData));
173     Vector<char> temporaryData;
174     IntPoint adjustedSourceOffset = sourceOffset;
175
176     // Texture upload requires subimage buffer if driver doesn't support subimage and we don't have full image upload.
177     bool requireSubImageBuffer = !driverSupportsSubImage(m_context3D.get())
178         && !(bytesPerLine == static_cast<int>(targetRect.width() * bytesPerPixel) && adjustedSourceOffset == IntPoint::zero());
179
180     // prepare temporaryData if necessary
181     if ((!driverSupportsExternalTextureBGRA(m_context3D.get()) && updateContentsFlag == UpdateCannotModifyOriginalImageData) || requireSubImageBuffer) {
182         temporaryData.resize(targetRect.width() * targetRect.height() * bytesPerPixel);
183         data = temporaryData.data();
184         const char* bits = static_cast<const char*>(srcData);
185         const char* src = bits + sourceOffset.y() * bytesPerLine + sourceOffset.x() * bytesPerPixel;
186         char* dst = data;
187         const int targetBytesPerLine = targetRect.width() * bytesPerPixel;
188         for (int y = 0; y < targetRect.height(); ++y) {
189             memcpy(dst, src, targetBytesPerLine);
190             src += bytesPerLine;
191             dst += targetBytesPerLine;
192         }
193
194         bytesPerLine = targetBytesPerLine;
195         adjustedSourceOffset = IntPoint(0, 0);
196     }
197
198     if (driverSupportsExternalTextureBGRA(m_context3D.get()))
199         glFormat = GraphicsContext3D::BGRA;
200     else
201         swizzleBGRAToRGBA(reinterpret_cast_ptr<uint32_t*>(data), IntRect(adjustedSourceOffset, targetRect.size()), bytesPerLine / bytesPerPixel);
202
203     updateContentsNoSwizzle(data, targetRect, adjustedSourceOffset, bytesPerLine, bytesPerPixel, glFormat);
204 }
205
206 void BitmapTextureGL::updateContents(Image* image, const IntRect& targetRect, const IntPoint& offset, UpdateContentsFlag updateContentsFlag)
207 {
208     if (!image)
209         return;
210     NativeImagePtr frameImage = image->nativeImageForCurrentFrame();
211     if (!frameImage)
212         return;
213
214     int bytesPerLine;
215     const char* imageData;
216
217 #if USE(CAIRO)
218     cairo_surface_t* surface = frameImage.get();
219     imageData = reinterpret_cast<const char*>(cairo_image_surface_get_data(surface));
220     bytesPerLine = cairo_image_surface_get_stride(surface);
221 #endif
222
223     updateContents(imageData, targetRect, offset, bytesPerLine, updateContentsFlag);
224 }
225
226 static unsigned getPassesRequiredForFilter(FilterOperation::OperationType type)
227 {
228     switch (type) {
229     case FilterOperation::GRAYSCALE:
230     case FilterOperation::SEPIA:
231     case FilterOperation::SATURATE:
232     case FilterOperation::HUE_ROTATE:
233     case FilterOperation::INVERT:
234     case FilterOperation::BRIGHTNESS:
235     case FilterOperation::CONTRAST:
236     case FilterOperation::OPACITY:
237         return 1;
238     case FilterOperation::BLUR:
239     case FilterOperation::DROP_SHADOW:
240         // We use two-passes (vertical+horizontal) for blur and drop-shadow.
241         return 2;
242     default:
243         return 0;
244     }
245 }
246
247 PassRefPtr<BitmapTexture> BitmapTextureGL::applyFilters(TextureMapper* textureMapper, const FilterOperations& filters)
248 {
249     if (filters.isEmpty())
250         return this;
251
252     TextureMapperGL* texmapGL = static_cast<TextureMapperGL*>(textureMapper);
253     RefPtr<BitmapTexture> previousSurface = texmapGL->currentSurface();
254     RefPtr<BitmapTexture> resultSurface = this;
255     RefPtr<BitmapTexture> intermediateSurface;
256     RefPtr<BitmapTexture> spareSurface;
257
258     m_filterInfo = FilterInfo();
259
260     for (size_t i = 0; i < filters.size(); ++i) {
261         RefPtr<FilterOperation> filter = filters.operations()[i];
262         ASSERT(filter);
263
264         int numPasses = getPassesRequiredForFilter(filter->type());
265         for (int j = 0; j < numPasses; ++j) {
266             bool last = (i == filters.size() - 1) && (j == numPasses - 1);
267             if (!last) {
268                 if (!intermediateSurface)
269                     intermediateSurface = texmapGL->acquireTextureFromPool(contentSize());
270                 texmapGL->bindSurface(intermediateSurface.get());
271             }
272
273             if (last) {
274                 toBitmapTextureGL(resultSurface.get())->m_filterInfo = BitmapTextureGL::FilterInfo(filter, j, spareSurface);
275                 break;
276             }
277
278             texmapGL->drawFiltered(*resultSurface.get(), spareSurface.get(), *filter, j);
279             if (!j && filter->type() == FilterOperation::DROP_SHADOW) {
280                 spareSurface = resultSurface;
281                 resultSurface.clear();
282             }
283             std::swap(resultSurface, intermediateSurface);
284         }
285     }
286
287     texmapGL->bindSurface(previousSurface.get());
288     return resultSurface;
289 }
290
291 void BitmapTextureGL::initializeStencil()
292 {
293     if (m_rbo)
294         return;
295
296     m_rbo = m_context3D->createRenderbuffer();
297     m_context3D->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_rbo);
298 #ifdef TEXMAP_OPENGL_ES_2
299     m_context3D->renderbufferStorage(GraphicsContext3D::RENDERBUFFER, GraphicsContext3D::STENCIL_INDEX8, m_textureSize.width(), m_textureSize.height());
300 #else
301     m_context3D->renderbufferStorage(GraphicsContext3D::RENDERBUFFER, GraphicsContext3D::DEPTH_STENCIL, m_textureSize.width(), m_textureSize.height());
302 #endif
303     m_context3D->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, 0);
304     m_context3D->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::STENCIL_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, m_rbo);
305     m_context3D->clearStencil(0);
306     m_context3D->clear(GraphicsContext3D::STENCIL_BUFFER_BIT);
307 }
308
309 void BitmapTextureGL::initializeDepthBuffer()
310 {
311     if (m_depthBufferObject)
312         return;
313
314     m_depthBufferObject = m_context3D->createRenderbuffer();
315     m_context3D->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_depthBufferObject);
316     m_context3D->renderbufferStorage(GraphicsContext3D::RENDERBUFFER, GraphicsContext3D::DEPTH_COMPONENT16, m_textureSize.width(), m_textureSize.height());
317     m_context3D->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, 0);
318     m_context3D->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, m_depthBufferObject);
319 }
320
321 void BitmapTextureGL::clearIfNeeded()
322 {
323     if (!m_shouldClear)
324         return;
325
326     m_clipStack.reset(IntRect(IntPoint::zero(), m_textureSize), TextureMapperGL::ClipStack::DefaultYAxis);
327     m_clipStack.applyIfNeeded(m_context3D.get());
328     m_context3D->clearColor(0, 0, 0, 0);
329     m_context3D->clear(GraphicsContext3D::COLOR_BUFFER_BIT);
330     m_shouldClear = false;
331 }
332
333 void BitmapTextureGL::createFboIfNeeded()
334 {
335     if (m_fbo)
336         return;
337
338     m_fbo = m_context3D->createFramebuffer();
339     m_context3D->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo);
340     m_context3D->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE_2D, id(), 0);
341     m_shouldClear = true;
342 }
343
344 void BitmapTextureGL::bindAsSurface(GraphicsContext3D* context3D)
345 {
346     context3D->bindTexture(GraphicsContext3D::TEXTURE_2D, 0);
347     createFboIfNeeded();
348     context3D->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo);
349     context3D->viewport(0, 0, m_textureSize.width(), m_textureSize.height());
350     clearIfNeeded();
351     m_clipStack.apply(m_context3D.get());
352 }
353
354 BitmapTextureGL::~BitmapTextureGL()
355 {
356     if (m_id)
357         m_context3D->deleteTexture(m_id);
358
359     if (m_fbo)
360         m_context3D->deleteFramebuffer(m_fbo);
361
362     if (m_rbo)
363         m_context3D->deleteRenderbuffer(m_rbo);
364
365     if (m_depthBufferObject)
366         m_context3D->deleteRenderbuffer(m_depthBufferObject);
367 }
368
369 bool BitmapTextureGL::isValid() const
370 {
371     return m_id;
372 }
373
374 IntSize BitmapTextureGL::size() const
375 {
376     return m_textureSize;
377 }
378
379 }; // namespace WebCore