Stop using PassRefPtr in platform/graphics
[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 #if USE(TEXTURE_MAPPER_GL)
26
27 #include "Extensions3D.h"
28 #include "FilterOperations.h"
29 #include "GraphicsContext.h"
30 #include "Image.h"
31 #include "LengthFunctions.h"
32 #include "NotImplemented.h"
33 #include "TextureMapperShaderProgram.h"
34 #include "Timer.h"
35 #include <wtf/HashMap.h>
36 #include <wtf/RefCounted.h>
37 #include <wtf/RefPtr.h>
38
39 #if USE(CAIRO)
40 #include "CairoUtilities.h"
41 #include "RefPtrCairo.h"
42 #include <cairo.h>
43 #include <wtf/text/CString.h>
44 #endif
45
46 #if OS(DARWIN)
47 #define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
48 #endif
49
50 namespace WebCore {
51
52 BitmapTextureGL* toBitmapTextureGL(BitmapTexture* texture)
53 {
54     if (!texture || !texture->isBackedByOpenGL())
55         return 0;
56
57     return static_cast<BitmapTextureGL*>(texture);
58 }
59
60 BitmapTextureGL::BitmapTextureGL(RefPtr<GraphicsContext3D>&& context3D, const Flags flags)
61     : m_context3D(WTFMove(context3D))
62 {
63     if (flags & FBOAttachment)
64         m_internalFormat = m_format = GraphicsContext3D::RGBA;
65     else {
66         // If GL_EXT_texture_format_BGRA8888 is supported in the OpenGLES
67         // internal and external formats need to be BGRA
68         m_internalFormat = GraphicsContext3D::RGBA;
69         m_format = GraphicsContext3D::BGRA;
70         if (m_context3D->isGLES2Compliant()) {
71             if (m_context3D->getExtensions().supports("GL_EXT_texture_format_BGRA8888"))
72                 m_internalFormat = GraphicsContext3D::BGRA;
73             else
74                 m_format = GraphicsContext3D::RGBA;
75         }
76     }
77 }
78
79 static void swizzleBGRAToRGBA(uint32_t* data, const IntRect& rect, int stride = 0)
80 {
81     stride = stride ? stride : rect.width();
82     for (int y = rect.y(); y < rect.maxY(); ++y) {
83         uint32_t* p = data + y * stride;
84         for (int x = rect.x(); x < rect.maxX(); ++x)
85             p[x] = ((p[x] << 16) & 0xff0000) | ((p[x] >> 16) & 0xff) | (p[x] & 0xff00ff00);
86     }
87 }
88
89 static bool driverSupportsSubImage(GraphicsContext3D* context)
90 {
91     if (context->isGLES2Compliant()) {
92         static bool supportsSubImage = context->getExtensions().supports("GL_EXT_unpack_subimage");
93         return supportsSubImage;
94     }
95
96     return true;
97 }
98
99 void BitmapTextureGL::didReset()
100 {
101     if (!m_id)
102         m_id = m_context3D->createTexture();
103
104     m_shouldClear = true;
105     if (m_textureSize == contentSize())
106         return;
107
108     m_textureSize = contentSize();
109     m_context3D->bindTexture(GraphicsContext3D::TEXTURE_2D, m_id);
110     m_context3D->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR);
111     m_context3D->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR);
112     m_context3D->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE);
113     m_context3D->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE);
114
115     m_context3D->texImage2DDirect(GraphicsContext3D::TEXTURE_2D, 0, m_internalFormat, m_textureSize.width(), m_textureSize.height(), 0, m_format, m_type, 0);
116 }
117
118 void BitmapTextureGL::updateContentsNoSwizzle(const void* srcData, const IntRect& targetRect, const IntPoint& sourceOffset, int bytesPerLine, unsigned bytesPerPixel, Platform3DObject glFormat)
119 {
120     m_context3D->bindTexture(GraphicsContext3D::TEXTURE_2D, m_id);
121     // For ES drivers that don't support sub-images.
122     if (driverSupportsSubImage(m_context3D.get())) {
123         // Use the OpenGL sub-image extension, now that we know it's available.
124         m_context3D->pixelStorei(GraphicsContext3D::UNPACK_ROW_LENGTH, bytesPerLine / bytesPerPixel);
125         m_context3D->pixelStorei(GraphicsContext3D::UNPACK_SKIP_ROWS, sourceOffset.y());
126         m_context3D->pixelStorei(GraphicsContext3D::UNPACK_SKIP_PIXELS, sourceOffset.x());
127     }
128
129     m_context3D->texSubImage2D(GraphicsContext3D::TEXTURE_2D, 0, targetRect.x(), targetRect.y(), targetRect.width(), targetRect.height(), glFormat, m_type, srcData);
130
131     // For ES drivers that don't support sub-images.
132     if (driverSupportsSubImage(m_context3D.get())) {
133         m_context3D->pixelStorei(GraphicsContext3D::UNPACK_ROW_LENGTH, 0);
134         m_context3D->pixelStorei(GraphicsContext3D::UNPACK_SKIP_ROWS, 0);
135         m_context3D->pixelStorei(GraphicsContext3D::UNPACK_SKIP_PIXELS, 0);
136     }
137 }
138
139 void BitmapTextureGL::updateContents(const void* srcData, const IntRect& targetRect, const IntPoint& sourceOffset, int bytesPerLine, UpdateContentsFlag updateContentsFlag)
140 {
141     m_context3D->bindTexture(GraphicsContext3D::TEXTURE_2D, m_id);
142
143     const unsigned bytesPerPixel = 4;
144     char* data = reinterpret_cast<char*>(const_cast<void*>(srcData));
145     Vector<char> temporaryData;
146     IntPoint adjustedSourceOffset = sourceOffset;
147
148     // Texture upload requires subimage buffer if driver doesn't support subimage and we don't have full image upload.
149     bool requireSubImageBuffer = !driverSupportsSubImage(m_context3D.get())
150         && !(bytesPerLine == static_cast<int>(targetRect.width() * bytesPerPixel) && adjustedSourceOffset == IntPoint::zero());
151
152     // prepare temporaryData if necessary
153     if ((m_format == GraphicsContext3D::RGBA && updateContentsFlag == UpdateCannotModifyOriginalImageData) || requireSubImageBuffer) {
154         temporaryData.resize(targetRect.width() * targetRect.height() * bytesPerPixel);
155         data = temporaryData.data();
156         const char* bits = static_cast<const char*>(srcData);
157         const char* src = bits + sourceOffset.y() * bytesPerLine + sourceOffset.x() * bytesPerPixel;
158         char* dst = data;
159         const int targetBytesPerLine = targetRect.width() * bytesPerPixel;
160         for (int y = 0; y < targetRect.height(); ++y) {
161             memcpy(dst, src, targetBytesPerLine);
162             src += bytesPerLine;
163             dst += targetBytesPerLine;
164         }
165
166         bytesPerLine = targetBytesPerLine;
167         adjustedSourceOffset = IntPoint(0, 0);
168     }
169
170     if (m_format == GraphicsContext3D::RGBA)
171         swizzleBGRAToRGBA(reinterpret_cast_ptr<uint32_t*>(data), IntRect(adjustedSourceOffset, targetRect.size()), bytesPerLine / bytesPerPixel);
172
173     updateContentsNoSwizzle(data, targetRect, adjustedSourceOffset, bytesPerLine, bytesPerPixel, m_format);
174 }
175
176 void BitmapTextureGL::updateContents(Image* image, const IntRect& targetRect, const IntPoint& offset, UpdateContentsFlag updateContentsFlag)
177 {
178     if (!image)
179         return;
180     NativeImagePtr frameImage = image->nativeImageForCurrentFrame();
181     if (!frameImage)
182         return;
183
184     int bytesPerLine;
185     const char* imageData;
186
187 #if USE(CAIRO)
188     cairo_surface_t* surface = frameImage.get();
189     imageData = reinterpret_cast<const char*>(cairo_image_surface_get_data(surface));
190     bytesPerLine = cairo_image_surface_get_stride(surface);
191 #endif
192
193     updateContents(imageData, targetRect, offset, bytesPerLine, updateContentsFlag);
194 }
195
196 static unsigned getPassesRequiredForFilter(FilterOperation::OperationType type)
197 {
198     switch (type) {
199     case FilterOperation::GRAYSCALE:
200     case FilterOperation::SEPIA:
201     case FilterOperation::SATURATE:
202     case FilterOperation::HUE_ROTATE:
203     case FilterOperation::INVERT:
204     case FilterOperation::BRIGHTNESS:
205     case FilterOperation::CONTRAST:
206     case FilterOperation::OPACITY:
207         return 1;
208     case FilterOperation::BLUR:
209     case FilterOperation::DROP_SHADOW:
210         // We use two-passes (vertical+horizontal) for blur and drop-shadow.
211         return 2;
212     default:
213         return 0;
214     }
215 }
216
217 RefPtr<BitmapTexture> BitmapTextureGL::applyFilters(TextureMapper& textureMapper, const FilterOperations& filters)
218 {
219     if (filters.isEmpty())
220         return this;
221
222     TextureMapperGL& texmapGL = static_cast<TextureMapperGL&>(textureMapper);
223     RefPtr<BitmapTexture> previousSurface = texmapGL.currentSurface();
224     RefPtr<BitmapTexture> resultSurface = this;
225     RefPtr<BitmapTexture> intermediateSurface;
226     RefPtr<BitmapTexture> spareSurface;
227
228     m_filterInfo = FilterInfo();
229
230     for (size_t i = 0; i < filters.size(); ++i) {
231         RefPtr<FilterOperation> filter = filters.operations()[i];
232         ASSERT(filter);
233
234         int numPasses = getPassesRequiredForFilter(filter->type());
235         for (int j = 0; j < numPasses; ++j) {
236             bool last = (i == filters.size() - 1) && (j == numPasses - 1);
237             if (!last) {
238                 if (!intermediateSurface)
239                     intermediateSurface = texmapGL.acquireTextureFromPool(contentSize(), BitmapTexture::SupportsAlpha | BitmapTexture::FBOAttachment);
240                 texmapGL.bindSurface(intermediateSurface.get());
241             }
242
243             if (last) {
244                 toBitmapTextureGL(resultSurface.get())->m_filterInfo = BitmapTextureGL::FilterInfo(filter.copyRef(), j, spareSurface.copyRef());
245                 break;
246             }
247
248             texmapGL.drawFiltered(*resultSurface.get(), spareSurface.get(), *filter, j);
249             if (!j && filter->type() == FilterOperation::DROP_SHADOW) {
250                 spareSurface = resultSurface;
251                 resultSurface = nullptr;
252             }
253             std::swap(resultSurface, intermediateSurface);
254         }
255     }
256
257     texmapGL.bindSurface(previousSurface.get());
258     return resultSurface;
259 }
260
261 void BitmapTextureGL::initializeStencil()
262 {
263     if (m_rbo)
264         return;
265
266     m_rbo = m_context3D->createRenderbuffer();
267     m_context3D->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_rbo);
268     m_context3D->renderbufferStorage(GraphicsContext3D::RENDERBUFFER, GraphicsContext3D::STENCIL_INDEX8, m_textureSize.width(), m_textureSize.height());
269     m_context3D->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, 0);
270     m_context3D->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::STENCIL_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, m_rbo);
271     m_context3D->clearStencil(0);
272     m_context3D->clear(GraphicsContext3D::STENCIL_BUFFER_BIT);
273 }
274
275 void BitmapTextureGL::initializeDepthBuffer()
276 {
277     if (m_depthBufferObject)
278         return;
279
280     m_depthBufferObject = m_context3D->createRenderbuffer();
281     m_context3D->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_depthBufferObject);
282     m_context3D->renderbufferStorage(GraphicsContext3D::RENDERBUFFER, GraphicsContext3D::DEPTH_COMPONENT16, m_textureSize.width(), m_textureSize.height());
283     m_context3D->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, 0);
284     m_context3D->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, m_depthBufferObject);
285 }
286
287 void BitmapTextureGL::clearIfNeeded()
288 {
289     if (!m_shouldClear)
290         return;
291
292     m_clipStack.reset(IntRect(IntPoint::zero(), m_textureSize), ClipStack::YAxisMode::Default);
293     m_clipStack.applyIfNeeded(*m_context3D);
294     m_context3D->clearColor(0, 0, 0, 0);
295     m_context3D->clear(GraphicsContext3D::COLOR_BUFFER_BIT);
296     m_shouldClear = false;
297 }
298
299 void BitmapTextureGL::createFboIfNeeded()
300 {
301     if (m_fbo)
302         return;
303
304     m_fbo = m_context3D->createFramebuffer();
305     m_context3D->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo);
306     m_context3D->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE_2D, id(), 0);
307     m_shouldClear = true;
308 }
309
310 void BitmapTextureGL::bindAsSurface(GraphicsContext3D* context3D)
311 {
312     context3D->bindTexture(GraphicsContext3D::TEXTURE_2D, 0);
313     createFboIfNeeded();
314     context3D->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo);
315     context3D->viewport(0, 0, m_textureSize.width(), m_textureSize.height());
316     clearIfNeeded();
317     m_clipStack.apply(*m_context3D);
318 }
319
320 BitmapTextureGL::~BitmapTextureGL()
321 {
322     if (m_id)
323         m_context3D->deleteTexture(m_id);
324
325     if (m_fbo)
326         m_context3D->deleteFramebuffer(m_fbo);
327
328     if (m_rbo)
329         m_context3D->deleteRenderbuffer(m_rbo);
330
331     if (m_depthBufferObject)
332         m_context3D->deleteRenderbuffer(m_depthBufferObject);
333 }
334
335 bool BitmapTextureGL::isValid() const
336 {
337     return m_id;
338 }
339
340 IntSize BitmapTextureGL::size() const
341 {
342     return m_textureSize;
343 }
344
345 }; // namespace WebCore
346
347 #endif // USE(TEXTURE_MAPPER_GL)