• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
3  * Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved.
4  * Copyright (C) 2013 Google Inc. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above
11  *    copyright notice, this list of conditions and the following
12  *    disclaimer.
13  * 2. Redistributions in binary form must reproduce the above
14  *    copyright notice, this list of conditions and the following
15  *    disclaimer in the documentation and/or other materials
16  *    provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
23  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
27  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
28  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include "config.h"
33 #include "platform/graphics/filters/custom/FECustomFilter.h"
34 
35 #include "platform/graphics/Extensions3D.h"
36 #include "platform/graphics/GraphicsContext3D.h"
37 #include "platform/graphics/filters/custom/CustomFilterRenderer.h"
38 #include "platform/graphics/filters/custom/CustomFilterValidatedProgram.h"
39 #include "platform/text/TextStream.h"
40 #include "wtf/Uint8ClampedArray.h"
41 
42 namespace WebCore {
43 
FECustomFilter(Filter * filter,PassRefPtr<GraphicsContext3D> context,PassRefPtr<CustomFilterValidatedProgram> validatedProgram,const CustomFilterParameterList & parameters,unsigned meshRows,unsigned meshColumns,CustomFilterMeshType meshType)44 FECustomFilter::FECustomFilter(Filter* filter, PassRefPtr<GraphicsContext3D> context, PassRefPtr<CustomFilterValidatedProgram> validatedProgram, const CustomFilterParameterList& parameters,
45     unsigned meshRows, unsigned meshColumns, CustomFilterMeshType meshType)
46     : FilterEffect(filter)
47     , m_context(context)
48     , m_validatedProgram(validatedProgram)
49     , m_inputTexture(0)
50     , m_frameBuffer(0)
51     , m_depthBuffer(0)
52     , m_destTexture(0)
53     , m_triedMultisampleBuffer(false)
54     , m_multisampleFrameBuffer(0)
55     , m_multisampleRenderBuffer(0)
56     , m_multisampleDepthBuffer(0)
57 {
58     // We will not pass a CustomFilterCompiledProgram here, as we only want to compile it when we actually need it in the first paint.
59     m_customFilterRenderer = CustomFilterRenderer::create(m_context, m_validatedProgram->programInfo().programType(), parameters, meshRows, meshColumns, meshType);
60 }
61 
create(Filter * filter,PassRefPtr<GraphicsContext3D> context,PassRefPtr<CustomFilterValidatedProgram> validatedProgram,const CustomFilterParameterList & parameters,unsigned meshRows,unsigned meshColumns,CustomFilterMeshType meshType)62 PassRefPtr<FECustomFilter> FECustomFilter::create(Filter* filter, PassRefPtr<GraphicsContext3D> context, PassRefPtr<CustomFilterValidatedProgram> validatedProgram, const CustomFilterParameterList& parameters,
63     unsigned meshRows, unsigned meshColumns, CustomFilterMeshType meshType)
64 {
65     return adoptRef(new FECustomFilter(filter, context, validatedProgram, parameters, meshRows, meshColumns, meshType));
66 }
67 
~FECustomFilter()68 FECustomFilter::~FECustomFilter()
69 {
70     deleteRenderBuffers();
71 }
72 
deleteRenderBuffers()73 void FECustomFilter::deleteRenderBuffers()
74 {
75     ASSERT(m_context);
76     m_context->makeContextCurrent();
77     if (m_inputTexture) {
78         m_context->deleteTexture(m_inputTexture);
79         m_inputTexture = 0;
80     }
81     if (m_frameBuffer) {
82         // Make sure to unbind any framebuffer from the context first, otherwise
83         // some platforms might refuse to bind the same buffer id again.
84         m_context->bindFramebuffer(GL_FRAMEBUFFER, 0);
85         m_context->deleteFramebuffer(m_frameBuffer);
86         m_frameBuffer = 0;
87     }
88     if (m_depthBuffer) {
89         m_context->deleteRenderbuffer(m_depthBuffer);
90         m_depthBuffer = 0;
91     }
92     if (m_destTexture) {
93         m_context->deleteTexture(m_destTexture);
94         m_destTexture = 0;
95     }
96     deleteMultisampleRenderBuffers();
97 }
98 
deleteMultisampleRenderBuffers()99 void FECustomFilter::deleteMultisampleRenderBuffers()
100 {
101     if (m_multisampleFrameBuffer) {
102         // Make sure to unbind any framebuffer from the context first, otherwise
103         // some platforms might refuse to bind the same buffer id again.
104         m_context->bindFramebuffer(GL_FRAMEBUFFER, 0);
105         m_context->deleteFramebuffer(m_multisampleFrameBuffer);
106         m_multisampleFrameBuffer = 0;
107     }
108     if (m_multisampleRenderBuffer) {
109         m_context->deleteRenderbuffer(m_multisampleRenderBuffer);
110         m_multisampleRenderBuffer = 0;
111     }
112     if (m_multisampleDepthBuffer) {
113         m_context->deleteRenderbuffer(m_multisampleDepthBuffer);
114         m_multisampleDepthBuffer = 0;
115     }
116 }
117 
applySoftware()118 void FECustomFilter::applySoftware()
119 {
120     if (!applyShader())
121         clearShaderResult();
122 }
123 
clearShaderResult()124 void FECustomFilter::clearShaderResult()
125 {
126     clearResult();
127     Uint8ClampedArray* dstPixelArray = createUnmultipliedImageResult();
128     if (!dstPixelArray)
129         return;
130 
131     FilterEffect* in = inputEffect(0);
132     setIsAlphaImage(in->isAlphaImage());
133     IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
134     in->copyUnmultipliedImage(dstPixelArray, effectDrawingRect);
135 }
136 
drawFilterMesh(Platform3DObject inputTexture)137 void FECustomFilter::drawFilterMesh(Platform3DObject inputTexture)
138 {
139     bool multisample = canUseMultisampleBuffers();
140     m_context->bindFramebuffer(GL_FRAMEBUFFER, multisample ? m_multisampleFrameBuffer : m_frameBuffer);
141     m_context->viewport(0, 0, m_contextSize.width(), m_contextSize.height());
142 
143     m_context->clearColor(0, 0, 0, 0);
144     m_context->clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
145 
146     m_customFilterRenderer->draw(inputTexture, m_contextSize);
147 
148     if (multisample)
149         resolveMultisampleBuffer();
150 }
151 
prepareForDrawing()152 bool FECustomFilter::prepareForDrawing()
153 {
154     m_context->makeContextCurrent();
155 
156     // Lazily inject the compiled program into the CustomFilterRenderer.
157     if (!m_customFilterRenderer->compiledProgram())
158         m_customFilterRenderer->setCompiledProgram(m_validatedProgram->compiledProgram());
159 
160     if (!m_customFilterRenderer->prepareForDrawing())
161         return false;
162 
163     // Only allocate a texture if the program needs one and the caller doesn't allocate one by itself.
164     if ((m_customFilterRenderer->programNeedsInputTexture() && !ensureInputTexture()) || !ensureFrameBuffer())
165         return false;
166 
167     return true;
168 }
169 
applyShader()170 bool FECustomFilter::applyShader()
171 {
172     Uint8ClampedArray* dstPixelArray = m_customFilterRenderer->premultipliedAlpha() ? createPremultipliedImageResult() : createUnmultipliedImageResult();
173     if (!dstPixelArray)
174         return false;
175 
176     if (!prepareForDrawing())
177         return false;
178 
179     FilterEffect* in = inputEffect(0);
180     IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
181     IntSize newContextSize(effectDrawingRect.size());
182     if (!resizeContextIfNeeded(newContextSize))
183         return false;
184 
185     bool needsInputTexture = m_customFilterRenderer->programNeedsInputTexture();
186     if (needsInputTexture) {
187         RefPtr<Uint8ClampedArray> srcPixelArray = in->asUnmultipliedImage(effectDrawingRect);
188         uploadInputTexture(srcPixelArray.get());
189     }
190     drawFilterMesh(needsInputTexture ? m_inputTexture : 0);
191 
192     ASSERT(static_cast<size_t>(newContextSize.width() * newContextSize.height() * 4) == dstPixelArray->length());
193     m_context->readPixels(0, 0, newContextSize.width(), newContextSize.height(), GL_RGBA, GL_UNSIGNED_BYTE, dstPixelArray->data());
194 
195     return true;
196 }
197 
ensureInputTexture()198 bool FECustomFilter::ensureInputTexture()
199 {
200     if (!m_inputTexture)
201         m_inputTexture = m_context->createTexture();
202     return m_inputTexture;
203 }
204 
uploadInputTexture(Uint8ClampedArray * srcPixelArray)205 void FECustomFilter::uploadInputTexture(Uint8ClampedArray* srcPixelArray)
206 {
207     m_context->bindTexture(GL_TEXTURE_2D, m_inputTexture);
208     m_context->texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_contextSize.width(), m_contextSize.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, srcPixelArray->data());
209 }
210 
ensureFrameBuffer()211 bool FECustomFilter::ensureFrameBuffer()
212 {
213     if (!m_frameBuffer)
214         m_frameBuffer = m_context->createFramebuffer();
215     if (!m_depthBuffer)
216         m_depthBuffer = m_context->createRenderbuffer();
217     if (!m_destTexture)
218         m_destTexture = m_context->createTexture();
219     return m_frameBuffer && m_depthBuffer && m_destTexture;
220 }
221 
createMultisampleBuffer()222 bool FECustomFilter::createMultisampleBuffer()
223 {
224     ASSERT(!m_triedMultisampleBuffer);
225     m_triedMultisampleBuffer = true;
226 
227     Extensions3D* extensions = m_context->extensions();
228     if (!extensions
229         || !extensions->supports("GL_ANGLE_framebuffer_multisample")
230         || !extensions->supports("GL_ANGLE_framebuffer_blit")
231         || !extensions->supports("GL_OES_rgb8_rgba8"))
232         return false;
233 
234     extensions->ensureEnabled("GL_ANGLE_framebuffer_blit");
235     extensions->ensureEnabled("GL_ANGLE_framebuffer_multisample");
236     extensions->ensureEnabled("GL_OES_rgb8_rgba8");
237 
238     if (!m_multisampleFrameBuffer)
239         m_multisampleFrameBuffer = m_context->createFramebuffer();
240     if (!m_multisampleRenderBuffer)
241         m_multisampleRenderBuffer = m_context->createRenderbuffer();
242     if (!m_multisampleDepthBuffer)
243         m_multisampleDepthBuffer = m_context->createRenderbuffer();
244 
245     return true;
246 }
247 
resolveMultisampleBuffer()248 void FECustomFilter::resolveMultisampleBuffer()
249 {
250     ASSERT(m_triedMultisampleBuffer && m_multisampleFrameBuffer && m_multisampleRenderBuffer && m_multisampleDepthBuffer);
251     m_context->bindFramebuffer(Extensions3D::READ_FRAMEBUFFER, m_multisampleFrameBuffer);
252     m_context->bindFramebuffer(Extensions3D::DRAW_FRAMEBUFFER, m_frameBuffer);
253 
254     ASSERT(m_context->extensions());
255     m_context->extensions()->blitFramebuffer(0, 0, m_contextSize.width(), m_contextSize.height(), 0, 0, m_contextSize.width(), m_contextSize.height(), GL_COLOR_BUFFER_BIT, GL_NEAREST);
256 
257     m_context->bindFramebuffer(Extensions3D::READ_FRAMEBUFFER, 0);
258     m_context->bindFramebuffer(Extensions3D::DRAW_FRAMEBUFFER, 0);
259 
260     m_context->bindFramebuffer(GL_FRAMEBUFFER, m_frameBuffer);
261 }
262 
canUseMultisampleBuffers() const263 bool FECustomFilter::canUseMultisampleBuffers() const
264 {
265     return m_triedMultisampleBuffer && m_multisampleFrameBuffer && m_multisampleRenderBuffer && m_multisampleDepthBuffer;
266 }
267 
resizeMultisampleBuffers(const IntSize & newContextSize)268 bool FECustomFilter::resizeMultisampleBuffers(const IntSize& newContextSize)
269 {
270     if (!m_triedMultisampleBuffer && !createMultisampleBuffer())
271         return false;
272 
273     if (!canUseMultisampleBuffers())
274         return false;
275 
276     static const int kMaxSampleCount = 4;
277     int maxSupportedSampleCount = 0;
278     m_context->getIntegerv(Extensions3D::MAX_SAMPLES, &maxSupportedSampleCount);
279     int sampleCount = std::min(kMaxSampleCount, maxSupportedSampleCount);
280     if (!sampleCount) {
281         deleteMultisampleRenderBuffers();
282         return false;
283     }
284 
285     Extensions3D* extensions = m_context->extensions();
286     ASSERT(extensions);
287 
288     m_context->bindFramebuffer(GL_FRAMEBUFFER, m_multisampleFrameBuffer);
289 
290     m_context->bindRenderbuffer(GL_RENDERBUFFER, m_multisampleRenderBuffer);
291     extensions->renderbufferStorageMultisample(GL_RENDERBUFFER, sampleCount, Extensions3D::RGBA8_OES, newContextSize.width(), newContextSize.height());
292     m_context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_multisampleRenderBuffer);
293 
294     m_context->bindRenderbuffer(GL_RENDERBUFFER, m_multisampleDepthBuffer);
295     extensions->renderbufferStorageMultisample(GL_RENDERBUFFER, sampleCount, GL_DEPTH_COMPONENT16, newContextSize.width(), newContextSize.height());
296     m_context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_multisampleDepthBuffer);
297 
298     m_context->bindRenderbuffer(GL_RENDERBUFFER, 0);
299 
300     if (m_context->checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
301         deleteMultisampleRenderBuffers();
302         return false;
303     }
304 
305     return true;
306 }
307 
resizeContextIfNeeded(const IntSize & newContextSize)308 bool FECustomFilter::resizeContextIfNeeded(const IntSize& newContextSize)
309 {
310     if (newContextSize.isEmpty())
311         return false;
312     if (m_contextSize == newContextSize)
313         return true;
314 
315     int maxTextureSize = 0;
316     m_context->getIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
317     if (newContextSize.height() > maxTextureSize || newContextSize.width() > maxTextureSize)
318         return false;
319 
320     return resizeContext(newContextSize);
321 }
322 
resizeContext(const IntSize & newContextSize)323 bool FECustomFilter::resizeContext(const IntSize& newContextSize)
324 {
325     bool multisample = resizeMultisampleBuffers(newContextSize);
326 
327     m_context->bindFramebuffer(GL_FRAMEBUFFER, m_frameBuffer);
328     m_context->bindTexture(GL_TEXTURE_2D, m_destTexture);
329     // We are going to clear the output buffer anyway, so we can safely initialize the destination texture with garbage data.
330     // FIXME: GraphicsContext3D::texImage2DDirect is not implemented on Chromium.
331     m_context->texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, newContextSize.width(), newContextSize.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
332     m_context->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_destTexture, 0);
333 
334     // We don't need the depth buffer for the texture framebuffer, if we already
335     // have a multisample buffer.
336     if (!multisample) {
337         m_context->bindRenderbuffer(GL_RENDERBUFFER, m_depthBuffer);
338         m_context->renderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, newContextSize.width(), newContextSize.height());
339         m_context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthBuffer);
340     }
341 
342     if (m_context->checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
343         return false;
344 
345     if (multisample) {
346         // Clear the framebuffer first, otherwise the first blit will fail.
347         m_context->clearColor(0, 0, 0, 0);
348         m_context->clear(GL_COLOR_BUFFER_BIT);
349     }
350 
351     m_context->bindRenderbuffer(GL_RENDERBUFFER, 0);
352 
353     m_contextSize = newContextSize;
354     return true;
355 }
356 
externalRepresentation(TextStream & ts,int indent) const357 TextStream& FECustomFilter::externalRepresentation(TextStream& ts, int indent) const
358 {
359     writeIndent(ts, indent);
360     ts << "[feCustomFilter";
361     FilterEffect::externalRepresentation(ts);
362     ts << "]\n";
363     inputEffect(0)->externalRepresentation(ts, indent + 1);
364     return ts;
365 }
366 
367 } // namespace WebCore
368