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