Modified: trunk/Source/WebCore/platform/graphics/texmap/TextureMapperGL.cpp (149364 => 149365)
--- trunk/Source/WebCore/platform/graphics/texmap/TextureMapperGL.cpp 2013-04-30 13:47:10 UTC (rev 149364)
+++ trunk/Source/WebCore/platform/graphics/texmap/TextureMapperGL.cpp 2013-04-30 13:47:49 UTC (rev 149365)
@@ -35,6 +35,7 @@
#include <wtf/PassOwnArrayPtr.h>
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
+#include <wtf/TemporaryChange.h>
#if PLATFORM(QT)
#include "NativeImageQt.h"
@@ -134,6 +135,9 @@
, previousScissorState(0)
, previousDepthState(0)
, sharedData(TextureMapperGLData::SharedGLData::currentSharedGLData(this->context))
+#if ENABLE(CSS_FILTERS)
+ , filterInfo(0)
+#endif
{ }
~TextureMapperGLData();
@@ -152,6 +156,9 @@
RefPtr<SharedGLData> sharedData;
RefPtr<BitmapTexture> currentSurface;
HashMap<const void*, Platform3DObject> vbos;
+#if ENABLE(CSS_FILTERS)
+ const BitmapTextureGL::FilterInfo* filterInfo;
+#endif
};
Platform3DObject TextureMapperGLData::getStaticVBO(GC3Denum target, GC3Dsizeiptr size, const void* data)
@@ -413,6 +420,157 @@
#endif
}
+#if ENABLE(CSS_FILTERS)
+
+static TextureMapperShaderProgram::Options optionsForFilterType(FilterOperation::OperationType type, unsigned pass)
+{
+ switch (type) {
+ case FilterOperation::GRAYSCALE:
+ return TextureMapperShaderProgram::Texture | TextureMapperShaderProgram::GrayscaleFilter;
+ case FilterOperation::SEPIA:
+ return TextureMapperShaderProgram::Texture | TextureMapperShaderProgram::SepiaFilter;
+ case FilterOperation::SATURATE:
+ return TextureMapperShaderProgram::Texture | TextureMapperShaderProgram::SaturateFilter;
+ case FilterOperation::HUE_ROTATE:
+ return TextureMapperShaderProgram::Texture | TextureMapperShaderProgram::HueRotateFilter;
+ case FilterOperation::INVERT:
+ return TextureMapperShaderProgram::Texture | TextureMapperShaderProgram::InvertFilter;
+ case FilterOperation::BRIGHTNESS:
+ return TextureMapperShaderProgram::Texture | TextureMapperShaderProgram::BrightnessFilter;
+ case FilterOperation::CONTRAST:
+ return TextureMapperShaderProgram::Texture | TextureMapperShaderProgram::ContrastFilter;
+ case FilterOperation::OPACITY:
+ return TextureMapperShaderProgram::Texture | TextureMapperShaderProgram::OpacityFilter;
+ case FilterOperation::BLUR:
+ return TextureMapperShaderProgram::BlurFilter;
+ case FilterOperation::DROP_SHADOW:
+ return TextureMapperShaderProgram::AlphaBlur
+ | (pass ? TextureMapperShaderProgram::ContentTexture | TextureMapperShaderProgram::SolidColor: 0);
+ default:
+ ASSERT_NOT_REACHED();
+ return 0;
+ }
+}
+
+static unsigned getPassesRequiredForFilter(FilterOperation::OperationType type)
+{
+ switch (type) {
+ case FilterOperation::GRAYSCALE:
+ case FilterOperation::SEPIA:
+ case FilterOperation::SATURATE:
+ case FilterOperation::HUE_ROTATE:
+ case FilterOperation::INVERT:
+ case FilterOperation::BRIGHTNESS:
+ case FilterOperation::CONTRAST:
+ case FilterOperation::OPACITY:
+#if ENABLE(CSS_SHADERS)
+ case FilterOperation::CUSTOM:
+ case FilterOperation::VALIDATED_CUSTOM:
+#endif
+ return 1;
+ case FilterOperation::BLUR:
+ case FilterOperation::DROP_SHADOW:
+ // We use two-passes (vertical+horizontal) for blur and drop-shadow.
+ return 2;
+ default:
+ return 0;
+ }
+}
+
+// Create a normal distribution of 21 values between -2 and 2.
+static const unsigned GaussianKernelHalfWidth = 11;
+static const float GaussianKernelStep = 0.2;
+
+static inline float gauss(float x)
+{
+ return exp(-(x * x) / 2.);
+}
+
+static float* gaussianKernel()
+{
+ static bool prepared = false;
+ static float kernel[GaussianKernelHalfWidth] = {0, };
+
+ if (prepared)
+ return kernel;
+
+ kernel[0] = gauss(0);
+ float sum = kernel[0];
+ for (unsigned i = 1; i < GaussianKernelHalfWidth; ++i) {
+ kernel[i] = gauss(i * GaussianKernelStep);
+ sum += 2 * kernel[i];
+ }
+
+ // Normalize the kernel.
+ float scale = 1 / sum;
+ for (unsigned i = 0; i < GaussianKernelHalfWidth; ++i)
+ kernel[i] *= scale;
+
+ prepared = true;
+ return kernel;
+}
+
+static void prepareFilterProgram(TextureMapperShaderProgram* program, const FilterOperation& operation, unsigned pass, const IntSize& size, GC3Duint contentTexture)
+{
+ RefPtr<GraphicsContext3D> context = program->context();
+ context->useProgram(program->programID());
+
+ switch (operation.getOperationType()) {
+ case FilterOperation::GRAYSCALE:
+ case FilterOperation::SEPIA:
+ case FilterOperation::SATURATE:
+ case FilterOperation::HUE_ROTATE:
+ context->uniform1f(program->filterAmountLocation(), static_cast<const BasicColorMatrixFilterOperation&>(operation).amount());
+ break;
+ case FilterOperation::INVERT:
+ case FilterOperation::BRIGHTNESS:
+ case FilterOperation::CONTRAST:
+ case FilterOperation::OPACITY:
+ context->uniform1f(program->filterAmountLocation(), static_cast<const BasicComponentTransferFilterOperation&>(operation).amount());
+ break;
+ case FilterOperation::BLUR: {
+ const BlurFilterOperation& blur = static_cast<const BlurFilterOperation&>(operation);
+ FloatSize radius;
+
+ // Blur is done in two passes, first horizontally and then vertically. The same shader is used for both.
+ if (pass)
+ radius.setHeight(floatValueForLength(blur.stdDeviation(), size.height()) / size.height());
+ else
+ radius.setWidth(floatValueForLength(blur.stdDeviation(), size.width()) / size.width());
+
+ context->uniform2f(program->blurRadiusLocation(), radius.width(), radius.height());
+ context->uniform1fv(program->gaussianKernelLocation(), GaussianKernelHalfWidth, gaussianKernel());
+ break;
+ }
+ case FilterOperation::DROP_SHADOW: {
+ const DropShadowFilterOperation& shadow = static_cast<const DropShadowFilterOperation&>(operation);
+ context->uniform1fv(program->gaussianKernelLocation(), GaussianKernelHalfWidth, gaussianKernel());
+ switch (pass) {
+ case 0:
+ // First pass: horizontal alpha blur.
+ context->uniform2f(program->blurRadiusLocation(), shadow.stdDeviation() / float(size.width()), 0);
+ context->uniform2f(program->shadowOffsetLocation(), float(shadow.location().x()) / float(size.width()), float(shadow.location().y()) / float(size.height()));
+ break;
+ case 1:
+ // Second pass: we need the shadow color and the content texture for compositing.
+ float r, g, b, a;
+ Color(premultipliedARGBFromColor(shadow.color())).getRGBA(r, g, b, a);
+ context->uniform4f(program->colorLocation(), r, g, b, a);
+ context->uniform2f(program->blurRadiusLocation(), 0, shadow.stdDeviation() / float(size.height()));
+ context->uniform2f(program->shadowOffsetLocation(), 0, 0);
+ context->activeTexture(GraphicsContext3D::TEXTURE1);
+ context->bindTexture(GraphicsContext3D::TEXTURE_2D, contentTexture);
+ context->uniform1i(program->contentTextureLocation(), 1);
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}
+#endif
+
void TextureMapperGL::drawTexture(const BitmapTexture& texture, const FloatRect& targetRect, const TransformationMatrix& matrix, float opacity, unsigned exposedEdges)
{
if (!texture.isValid())
@@ -422,6 +580,10 @@
return;
const BitmapTextureGL& textureGL = static_cast<const BitmapTextureGL&>(texture);
+#if ENABLE(CSS_FILTERS)
+ TemporaryChange<const BitmapTextureGL::FilterInfo*> filterInfo(data().filterInfo, textureGL.filterInfo());
+#endif
+
drawTexture(textureGL.id(), textureGL.isOpaque() ? 0 : ShouldBlend, textureGL.size(), targetRect, matrix, opacity, exposedEdges);
}
@@ -442,11 +604,30 @@
flags |= ShouldAntialias;
}
+#if ENABLE(CSS_FILTERS)
+ RefPtr<FilterOperation> filter = data().filterInfo ? data().filterInfo->filter: 0;
+ GC3Duint filterContentTextureID = 0;
+
+ if (filter) {
+ if (data().filterInfo->contentTexture)
+ filterContentTextureID = toBitmapTextureGL(data().filterInfo->contentTexture.get())->id();
+ options |= optionsForFilterType(filter->getOperationType(), data().filterInfo->pass);
+ if (filter->affectsOpacity())
+ flags |= ShouldBlend;
+ }
+#endif
+
if (useAntialiasing || opacity < 1)
flags |= ShouldBlend;
RefPtr<TextureMapperShaderProgram> program;
program = data().sharedGLData().getShaderProgram(options);
+
+#if ENABLE(CSS_FILTERS)
+ if (filter)
+ prepareFilterProgram(program.get(), *filter.get(), data().filterInfo->pass, textureSize, filterContentTextureID);
+#endif
+
drawTexturedQuadWithProgram(program.get(), texture, flags, textureSize, targetRect, modelViewMatrix, opacity);
}
@@ -737,157 +918,7 @@
updateContents(imageData, targetRect, offset, bytesPerLine, updateContentsFlag);
}
-#if ENABLE(CSS_FILTERS)
-
-static TextureMapperShaderProgram::Options optionsForFilterType(FilterOperation::OperationType type, unsigned pass)
-{
- switch (type) {
- case FilterOperation::GRAYSCALE:
- return TextureMapperShaderProgram::Texture | TextureMapperShaderProgram::GrayscaleFilter;
- case FilterOperation::SEPIA:
- return TextureMapperShaderProgram::Texture | TextureMapperShaderProgram::SepiaFilter;
- case FilterOperation::SATURATE:
- return TextureMapperShaderProgram::Texture | TextureMapperShaderProgram::SaturateFilter;
- case FilterOperation::HUE_ROTATE:
- return TextureMapperShaderProgram::Texture | TextureMapperShaderProgram::HueRotateFilter;
- case FilterOperation::INVERT:
- return TextureMapperShaderProgram::Texture | TextureMapperShaderProgram::InvertFilter;
- case FilterOperation::BRIGHTNESS:
- return TextureMapperShaderProgram::Texture | TextureMapperShaderProgram::BrightnessFilter;
- case FilterOperation::CONTRAST:
- return TextureMapperShaderProgram::Texture | TextureMapperShaderProgram::ContrastFilter;
- case FilterOperation::OPACITY:
- return TextureMapperShaderProgram::Texture | TextureMapperShaderProgram::OpacityFilter;
- case FilterOperation::BLUR:
- return TextureMapperShaderProgram::BlurFilter;
- case FilterOperation::DROP_SHADOW:
- return TextureMapperShaderProgram::AlphaBlur
- | (pass ? TextureMapperShaderProgram::ContentTexture | TextureMapperShaderProgram::SolidColor: 0);
- default:
- ASSERT_NOT_REACHED();
- return 0;
- }
-}
-
-static unsigned getPassesRequiredForFilter(FilterOperation::OperationType type)
-{
- switch (type) {
- case FilterOperation::GRAYSCALE:
- case FilterOperation::SEPIA:
- case FilterOperation::SATURATE:
- case FilterOperation::HUE_ROTATE:
- case FilterOperation::INVERT:
- case FilterOperation::BRIGHTNESS:
- case FilterOperation::CONTRAST:
- case FilterOperation::OPACITY:
#if ENABLE(CSS_SHADERS)
- case FilterOperation::CUSTOM:
- case FilterOperation::VALIDATED_CUSTOM:
-#endif
- return 1;
- case FilterOperation::BLUR:
- case FilterOperation::DROP_SHADOW:
- // We use two-passes (vertical+horizontal) for blur and drop-shadow.
- return 2;
- default:
- return 0;
- }
-}
-
-// Create a normal distribution of 21 values between -2 and 2.
-static const unsigned GaussianKernelHalfWidth = 11;
-static const float GaussianKernelStep = 0.2;
-
-static inline float gauss(float x)
-{
- return exp(-(x * x) / 2.);
-}
-
-static float* gaussianKernel()
-{
- static bool prepared = false;
- static float kernel[GaussianKernelHalfWidth] = {0, };
-
- if (prepared)
- return kernel;
-
- kernel[0] = gauss(0);
- float sum = kernel[0];
- for (unsigned i = 1; i < GaussianKernelHalfWidth; ++i) {
- kernel[i] = gauss(i * GaussianKernelStep);
- sum += 2 * kernel[i];
- }
-
- // Normalize the kernel.
- float scale = 1 / sum;
- for (unsigned i = 0; i < GaussianKernelHalfWidth; ++i)
- kernel[i] *= scale;
-
- prepared = true;
- return kernel;
-}
-
-static void prepareFilterProgram(TextureMapperShaderProgram* program, const FilterOperation& operation, unsigned pass, const IntSize& size, GC3Duint contentTexture)
-{
- RefPtr<GraphicsContext3D> context = program->context();
- context->useProgram(program->programID());
-
- switch (operation.getOperationType()) {
- case FilterOperation::GRAYSCALE:
- case FilterOperation::SEPIA:
- case FilterOperation::SATURATE:
- case FilterOperation::HUE_ROTATE:
- context->uniform1f(program->filterAmountLocation(), static_cast<const BasicColorMatrixFilterOperation&>(operation).amount());
- break;
- case FilterOperation::INVERT:
- case FilterOperation::BRIGHTNESS:
- case FilterOperation::CONTRAST:
- case FilterOperation::OPACITY:
- context->uniform1f(program->filterAmountLocation(), static_cast<const BasicComponentTransferFilterOperation&>(operation).amount());
- break;
- case FilterOperation::BLUR: {
- const BlurFilterOperation& blur = static_cast<const BlurFilterOperation&>(operation);
- FloatSize radius;
-
- // Blur is done in two passes, first horizontally and then vertically. The same shader is used for both.
- if (pass)
- radius.setHeight(floatValueForLength(blur.stdDeviation(), size.height()) / size.height());
- else
- radius.setWidth(floatValueForLength(blur.stdDeviation(), size.width()) / size.width());
-
- context->uniform2f(program->blurRadiusLocation(), radius.width(), radius.height());
- context->uniform1fv(program->gaussianKernelLocation(), GaussianKernelHalfWidth, gaussianKernel());
- break;
- }
- case FilterOperation::DROP_SHADOW: {
- const DropShadowFilterOperation& shadow = static_cast<const DropShadowFilterOperation&>(operation);
- context->uniform1fv(program->gaussianKernelLocation(), GaussianKernelHalfWidth, gaussianKernel());
- switch (pass) {
- case 0:
- // First pass: horizontal alpha blur.
- context->uniform2f(program->blurRadiusLocation(), shadow.stdDeviation() / float(size.width()), 0);
- context->uniform2f(program->shadowOffsetLocation(), float(shadow.location().x()) / float(size.width()), float(shadow.location().y()) / float(size.height()));
- break;
- case 1:
- // Second pass: we need the shadow color and the content texture for compositing.
- float r, g, b, a;
- Color(premultipliedARGBFromColor(shadow.color())).getRGBA(r, g, b, a);
- context->uniform4f(program->colorLocation(), r, g, b, a);
- context->uniform2f(program->blurRadiusLocation(), 0, shadow.stdDeviation() / float(size.height()));
- context->uniform2f(program->shadowOffsetLocation(), 0, 0);
- context->activeTexture(GraphicsContext3D::TEXTURE1);
- context->bindTexture(GraphicsContext3D::TEXTURE_2D, contentTexture);
- context->uniform1i(program->contentTextureLocation(), 1);
- break;
- }
- break;
- }
- default:
- break;
- }
-}
-
-#if ENABLE(CSS_SHADERS)
void TextureMapperGL::removeCachedCustomFilterProgram(CustomFilterProgram* program)
{
m_customFilterPrograms.remove(program->programInfo());
@@ -946,53 +977,79 @@
}
#endif
-void TextureMapperGL::drawFiltered(const BitmapTexture& sampler, const BitmapTexture& contentTexture, const FilterOperation& filter, int pass)
+#if ENABLE(CSS_FILTERS)
+void TextureMapperGL::drawFiltered(const BitmapTexture& sampler, const BitmapTexture* contentTexture, const FilterOperation& filter, int pass)
{
// For standard filters, we always draw the whole texture without transformations.
TextureMapperShaderProgram::Options options = optionsForFilterType(filter.getOperationType(), pass);
RefPtr<TextureMapperShaderProgram> program = data().sharedGLData().getShaderProgram(options);
ASSERT(program);
- prepareFilterProgram(program.get(), filter, pass, sampler.contentSize(), static_cast<const BitmapTextureGL&>(contentTexture).id());
+ prepareFilterProgram(program.get(), filter, pass, sampler.contentSize(), contentTexture ? static_cast<const BitmapTextureGL*>(contentTexture)->id() : 0);
FloatRect targetRect(IntPoint::zero(), sampler.contentSize());
drawTexturedQuadWithProgram(program.get(), static_cast<const BitmapTextureGL&>(sampler).id(), 0, IntSize(1, 1), targetRect, TransformationMatrix(), 1);
}
-PassRefPtr<BitmapTexture> BitmapTextureGL::applyFilters(TextureMapper* textureMapper, const BitmapTexture& contentTexture, const FilterOperations& filters)
+static bool isCustomFilter(FilterOperation::OperationType type)
{
- TextureMapperGL* textureMapperGL = static_cast<TextureMapperGL*>(textureMapper);
- RefPtr<BitmapTexture> previousSurface = textureMapperGL->data().currentSurface;
+#if ENABLE(CSS_SHADERS)
+ return type == FilterOperation::CUSTOM || type == FilterOperation::VALIDATED_CUSTOM;
+#else
+ return false;
+#endif
+}
- RefPtr<BitmapTexture> source = this;
- RefPtr<BitmapTexture> target = textureMapper->acquireTextureFromPool(m_textureSize);
+PassRefPtr<BitmapTexture> BitmapTextureGL::applyFilters(TextureMapper* textureMapper, const FilterOperations& filters)
+{
+ if (filters.isEmpty())
+ return this;
- bool useContentTexture = true;
+ TextureMapperGL* texmapGL = static_cast<TextureMapperGL*>(textureMapper);
+ RefPtr<BitmapTexture> previousSurface = texmapGL->data().currentSurface;
+ RefPtr<BitmapTexture> resultSurface = this;
+ RefPtr<BitmapTexture> intermediateSurface;
+ RefPtr<BitmapTexture> spareSurface;
+
+ m_filterInfo = FilterInfo();
+
for (size_t i = 0; i < filters.size(); ++i) {
- const FilterOperation* filter = filters.at(i);
+ RefPtr<FilterOperation> filter = filters.operations()[i];
ASSERT(filter);
+ bool custom = isCustomFilter(filter->getOperationType());
+
int numPasses = getPassesRequiredForFilter(filter->getOperationType());
for (int j = 0; j < numPasses; ++j) {
- textureMapperGL->bindSurface(target.get());
- const BitmapTexture& sourceTexture = useContentTexture ? contentTexture : *source;
+ bool last = (i == filters.size() - 1) && (j == numPasses - 1);
+ if (custom || !last) {
+ if (!intermediateSurface)
+ intermediateSurface = texmapGL->acquireTextureFromPool(contentSize());
+ texmapGL->bindSurface(intermediateSurface.get());
+ }
+
#if ENABLE(CSS_SHADERS)
- if (filter->getOperationType() == FilterOperation::CUSTOM || filter->getOperationType() == FilterOperation::VALIDATED_CUSTOM) {
- if (textureMapperGL->drawUsingCustomFilter(*target, sourceTexture, *filter)) {
- // Only swap if the draw was successful.
- std::swap(source, target);
- useContentTexture = false;
- }
+ if (custom) {
+ if (texmapGL->drawUsingCustomFilter(*intermediateSurface.get(), *resultSurface.get(), *filter))
+ std::swap(resultSurface, intermediateSurface);
continue;
}
#endif
- textureMapperGL->drawFiltered(sourceTexture, contentTexture, *filter, j);
- std::swap(source, target);
- useContentTexture = false;
+ if (last) {
+ toBitmapTextureGL(resultSurface.get())->m_filterInfo = BitmapTextureGL::FilterInfo(filter, j, spareSurface);
+ break;
+ }
+
+ texmapGL->drawFiltered(*resultSurface.get(), spareSurface.get(), *filter, j);
+ if (!j && filter->getOperationType() == FilterOperation::DROP_SHADOW) {
+ spareSurface = resultSurface;
+ resultSurface.clear();
+ }
+ std::swap(resultSurface, intermediateSurface);
}
}
- textureMapperGL->bindSurface(previousSurface.get());
- return source;
+ texmapGL->bindSurface(previousSurface.get());
+ return resultSurface;
}
#endif