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
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.
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.
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.
23 #include "BitmapTextureGL.h"
25 #if USE(TEXTURE_MAPPER_GL)
27 #include "Extensions3D.h"
28 #include "FilterOperations.h"
29 #include "GraphicsContext.h"
31 #include "LengthFunctions.h"
32 #include "NotImplemented.h"
33 #include "TextureMapperShaderProgram.h"
35 #include <wtf/HashMap.h>
36 #include <wtf/RefCounted.h>
37 #include <wtf/RefPtr.h>
40 #include "CairoUtilities.h"
41 #include "RefPtrCairo.h"
43 #include <wtf/text/CString.h>
47 #define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
52 BitmapTextureGL* toBitmapTextureGL(BitmapTexture* texture)
54 if (!texture || !texture->isBackedByOpenGL())
57 return static_cast<BitmapTextureGL*>(texture);
60 BitmapTextureGL::BitmapTextureGL(const TextureMapperContextAttributes& contextAttributes, RefPtr<GraphicsContext3D>&& context3D, const Flags flags, GC3Dint internalFormat)
61 : m_contextAttributes(contextAttributes)
62 , m_context3D(WTFMove(context3D))
64 if (internalFormat != GraphicsContext3D::DONT_CARE) {
65 m_internalFormat = m_format = internalFormat;
69 if (flags & FBOAttachment)
70 m_internalFormat = m_format = GraphicsContext3D::RGBA;
72 // If GL_EXT_texture_format_BGRA8888 is supported in the OpenGLES
73 // internal and external formats need to be BGRA
74 m_internalFormat = GraphicsContext3D::RGBA;
75 m_format = GraphicsContext3D::BGRA;
76 if (m_contextAttributes.isGLES2Compliant) {
77 if (m_contextAttributes.supportsBGRA8888)
78 m_internalFormat = GraphicsContext3D::BGRA;
80 m_format = GraphicsContext3D::RGBA;
85 static void swizzleBGRAToRGBA(uint32_t* data, const IntRect& rect, int stride = 0)
87 stride = stride ? stride : rect.width();
88 for (int y = rect.y(); y < rect.maxY(); ++y) {
89 uint32_t* p = data + y * stride;
90 for (int x = rect.x(); x < rect.maxX(); ++x)
91 p[x] = ((p[x] << 16) & 0xff0000) | ((p[x] >> 16) & 0xff) | (p[x] & 0xff00ff00);
95 void BitmapTextureGL::didReset()
98 m_id = m_context3D->createTexture();
100 m_shouldClear = true;
101 if (m_textureSize == contentSize())
104 m_textureSize = contentSize();
105 m_context3D->bindTexture(GraphicsContext3D::TEXTURE_2D, m_id);
106 m_context3D->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR);
107 m_context3D->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR);
108 m_context3D->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE);
109 m_context3D->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE);
111 m_context3D->texImage2DDirect(GraphicsContext3D::TEXTURE_2D, 0, m_internalFormat, m_textureSize.width(), m_textureSize.height(), 0, m_format, m_type, 0);
114 void BitmapTextureGL::updateContentsNoSwizzle(const void* srcData, const IntRect& targetRect, const IntPoint& sourceOffset, int bytesPerLine, unsigned bytesPerPixel, Platform3DObject glFormat)
116 // For ES drivers that don't support sub-images.
117 bool contextSupportsUnpackSubimage = m_contextAttributes.supportsUnpackSubimage;
119 m_context3D->bindTexture(GraphicsContext3D::TEXTURE_2D, m_id);
121 if (contextSupportsUnpackSubimage) {
122 // Use the OpenGL sub-image extension, now that we know it's available.
123 m_context3D->pixelStorei(GraphicsContext3D::UNPACK_ROW_LENGTH, bytesPerLine / bytesPerPixel);
124 m_context3D->pixelStorei(GraphicsContext3D::UNPACK_SKIP_ROWS, sourceOffset.y());
125 m_context3D->pixelStorei(GraphicsContext3D::UNPACK_SKIP_PIXELS, sourceOffset.x());
128 m_context3D->texSubImage2D(GraphicsContext3D::TEXTURE_2D, 0, targetRect.x(), targetRect.y(), targetRect.width(), targetRect.height(), glFormat, m_type, srcData);
130 if (contextSupportsUnpackSubimage) {
131 m_context3D->pixelStorei(GraphicsContext3D::UNPACK_ROW_LENGTH, 0);
132 m_context3D->pixelStorei(GraphicsContext3D::UNPACK_SKIP_ROWS, 0);
133 m_context3D->pixelStorei(GraphicsContext3D::UNPACK_SKIP_PIXELS, 0);
137 void BitmapTextureGL::updateContents(const void* srcData, const IntRect& targetRect, const IntPoint& sourceOffset, int bytesPerLine, UpdateContentsFlag updateContentsFlag)
139 m_context3D->bindTexture(GraphicsContext3D::TEXTURE_2D, m_id);
141 const unsigned bytesPerPixel = 4;
142 char* data = reinterpret_cast<char*>(const_cast<void*>(srcData));
143 Vector<char> temporaryData;
144 IntPoint adjustedSourceOffset = sourceOffset;
146 // Texture upload requires subimage buffer if driver doesn't support subimage and we don't have full image upload.
147 bool requireSubImageBuffer = !m_contextAttributes.supportsUnpackSubimage
148 && !(bytesPerLine == static_cast<int>(targetRect.width() * bytesPerPixel) && adjustedSourceOffset == IntPoint::zero());
150 // prepare temporaryData if necessary
151 if ((m_format == GraphicsContext3D::RGBA && updateContentsFlag == UpdateCannotModifyOriginalImageData) || requireSubImageBuffer) {
152 temporaryData.resize(targetRect.width() * targetRect.height() * bytesPerPixel);
153 data = temporaryData.data();
154 const char* bits = static_cast<const char*>(srcData);
155 const char* src = bits + sourceOffset.y() * bytesPerLine + sourceOffset.x() * bytesPerPixel;
157 const int targetBytesPerLine = targetRect.width() * bytesPerPixel;
158 for (int y = 0; y < targetRect.height(); ++y) {
159 memcpy(dst, src, targetBytesPerLine);
161 dst += targetBytesPerLine;
164 bytesPerLine = targetBytesPerLine;
165 adjustedSourceOffset = IntPoint(0, 0);
168 if (m_format == GraphicsContext3D::RGBA)
169 swizzleBGRAToRGBA(reinterpret_cast_ptr<uint32_t*>(data), IntRect(adjustedSourceOffset, targetRect.size()), bytesPerLine / bytesPerPixel);
171 updateContentsNoSwizzle(data, targetRect, adjustedSourceOffset, bytesPerLine, bytesPerPixel, m_format);
174 void BitmapTextureGL::updateContents(Image* image, const IntRect& targetRect, const IntPoint& offset, UpdateContentsFlag updateContentsFlag)
178 NativeImagePtr frameImage = image->nativeImageForCurrentFrame();
183 const char* imageData;
186 cairo_surface_t* surface = frameImage.get();
187 imageData = reinterpret_cast<const char*>(cairo_image_surface_get_data(surface));
188 bytesPerLine = cairo_image_surface_get_stride(surface);
191 updateContents(imageData, targetRect, offset, bytesPerLine, updateContentsFlag);
194 static unsigned getPassesRequiredForFilter(FilterOperation::OperationType type)
197 case FilterOperation::GRAYSCALE:
198 case FilterOperation::SEPIA:
199 case FilterOperation::SATURATE:
200 case FilterOperation::HUE_ROTATE:
201 case FilterOperation::INVERT:
202 case FilterOperation::BRIGHTNESS:
203 case FilterOperation::CONTRAST:
204 case FilterOperation::OPACITY:
206 case FilterOperation::BLUR:
207 case FilterOperation::DROP_SHADOW:
208 // We use two-passes (vertical+horizontal) for blur and drop-shadow.
215 RefPtr<BitmapTexture> BitmapTextureGL::applyFilters(TextureMapper& textureMapper, const FilterOperations& filters)
217 if (filters.isEmpty())
220 TextureMapperGL& texmapGL = static_cast<TextureMapperGL&>(textureMapper);
221 RefPtr<BitmapTexture> previousSurface = texmapGL.currentSurface();
222 RefPtr<BitmapTexture> resultSurface = this;
223 RefPtr<BitmapTexture> intermediateSurface;
224 RefPtr<BitmapTexture> spareSurface;
226 m_filterInfo = FilterInfo();
228 for (size_t i = 0; i < filters.size(); ++i) {
229 RefPtr<FilterOperation> filter = filters.operations()[i];
232 int numPasses = getPassesRequiredForFilter(filter->type());
233 for (int j = 0; j < numPasses; ++j) {
234 bool last = (i == filters.size() - 1) && (j == numPasses - 1);
236 if (!intermediateSurface)
237 intermediateSurface = texmapGL.acquireTextureFromPool(contentSize(), BitmapTexture::SupportsAlpha | BitmapTexture::FBOAttachment);
238 texmapGL.bindSurface(intermediateSurface.get());
242 toBitmapTextureGL(resultSurface.get())->m_filterInfo = BitmapTextureGL::FilterInfo(filter.copyRef(), j, spareSurface.copyRef());
246 texmapGL.drawFiltered(*resultSurface.get(), spareSurface.get(), *filter, j);
247 if (!j && filter->type() == FilterOperation::DROP_SHADOW) {
248 spareSurface = resultSurface;
249 resultSurface = nullptr;
251 std::swap(resultSurface, intermediateSurface);
255 texmapGL.bindSurface(previousSurface.get());
256 return resultSurface;
259 void BitmapTextureGL::initializeStencil()
264 m_rbo = m_context3D->createRenderbuffer();
265 m_context3D->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_rbo);
266 m_context3D->renderbufferStorage(GraphicsContext3D::RENDERBUFFER, GraphicsContext3D::STENCIL_INDEX8, m_textureSize.width(), m_textureSize.height());
267 m_context3D->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, 0);
268 m_context3D->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::STENCIL_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, m_rbo);
269 m_context3D->clearStencil(0);
270 m_context3D->clear(GraphicsContext3D::STENCIL_BUFFER_BIT);
273 void BitmapTextureGL::initializeDepthBuffer()
275 if (m_depthBufferObject)
278 m_depthBufferObject = m_context3D->createRenderbuffer();
279 m_context3D->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_depthBufferObject);
280 m_context3D->renderbufferStorage(GraphicsContext3D::RENDERBUFFER, GraphicsContext3D::DEPTH_COMPONENT16, m_textureSize.width(), m_textureSize.height());
281 m_context3D->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, 0);
282 m_context3D->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, m_depthBufferObject);
285 void BitmapTextureGL::clearIfNeeded()
290 m_clipStack.reset(IntRect(IntPoint::zero(), m_textureSize), ClipStack::YAxisMode::Default);
291 m_clipStack.applyIfNeeded(*m_context3D);
292 m_context3D->clearColor(0, 0, 0, 0);
293 m_context3D->clear(GraphicsContext3D::COLOR_BUFFER_BIT);
294 m_shouldClear = false;
297 void BitmapTextureGL::createFboIfNeeded()
302 m_fbo = m_context3D->createFramebuffer();
303 m_context3D->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo);
304 m_context3D->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE_2D, id(), 0);
305 m_shouldClear = true;
308 void BitmapTextureGL::bindAsSurface(GraphicsContext3D* context3D)
310 context3D->bindTexture(GraphicsContext3D::TEXTURE_2D, 0);
312 context3D->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo);
313 context3D->viewport(0, 0, m_textureSize.width(), m_textureSize.height());
315 m_clipStack.apply(*m_context3D);
318 BitmapTextureGL::~BitmapTextureGL()
321 m_context3D->deleteTexture(m_id);
324 m_context3D->deleteFramebuffer(m_fbo);
327 m_context3D->deleteRenderbuffer(m_rbo);
329 if (m_depthBufferObject)
330 m_context3D->deleteRenderbuffer(m_depthBufferObject);
333 bool BitmapTextureGL::isValid() const
338 IntSize BitmapTextureGL::size() const
340 return m_textureSize;
344 void BitmapTextureGL::copyFromExternalTexture(Platform3DObject sourceTextureID)
346 GC3Dint boundTexture = 0;
347 GC3Dint boundFramebuffer = 0;
348 GC3Dint boundActiveTexture = 0;
350 m_context3D->getIntegerv(GraphicsContext3D::TEXTURE_BINDING_2D, &boundTexture);
351 m_context3D->getIntegerv(GraphicsContext3D::FRAMEBUFFER_BINDING, &boundFramebuffer);
352 m_context3D->getIntegerv(GraphicsContext3D::ACTIVE_TEXTURE, &boundActiveTexture);
354 m_context3D->bindTexture(GraphicsContext3D::TEXTURE_2D, sourceTextureID);
356 Platform3DObject copyFbo = m_context3D->createFramebuffer();
357 m_context3D->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, copyFbo);
358 m_context3D->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE_2D, sourceTextureID, 0);
360 m_context3D->activeTexture(GraphicsContext3D::TEXTURE0);
361 m_context3D->bindTexture(GraphicsContext3D::TEXTURE_2D, id());
362 m_context3D->copyTexSubImage2D(GraphicsContext3D::TEXTURE_2D, 0, 0, 0, 0, 0, m_textureSize.width(), m_textureSize.height());
364 m_context3D->bindTexture(GraphicsContext3D::TEXTURE_2D, boundTexture);
365 m_context3D->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, boundFramebuffer);
366 m_context3D->bindTexture(GraphicsContext3D::TEXTURE_2D, boundTexture);
367 m_context3D->activeTexture(boundActiveTexture);
368 m_context3D->deleteFramebuffer(copyFbo);
371 }; // namespace WebCore
373 #endif // USE(TEXTURE_MAPPER_GL)