Commit 2be2dfce authored by achicu@adobe.com's avatar achicu@adobe.com

[CSS Shaders] Implement a StyleCustomFilterProgram cache

https://bugs.webkit.org/show_bug.cgi?id=112602

Reviewed by Dean Jackson.

Source/WebCore:

When the style is recalculated, the new computed RenderStyle is saved as the m_style of the
RenderObject, even if the style was not different.

In the case of Custom Filters, a new StyleCustomFilterProgram was created at all times, but the
actual equality check was done by comparing the pair of cached shaders from inside the StyleCustomFilterProgram.

Because of that the RenderLayer::styleChanged was not called when the new StyleCustomFilterProgram was created, so it
will end up still knowing only about the previous StyleCustomFilterProgram.

The RenderLayer sets itself as a client of the StyleCustomFilterProgram, so that it can repaint itself
when the program is loaded, but because RenderLayer::styleChanged is not called, it will not add itself as a client of the new
StyleCustomFilterProgram.

StyleCustomFilterProgram waits until the first client to load the programs, so in this case it will just remain unloaded.

There was no crash, but just an assert in debug mode. Also, as a visible side-effect some frames were rendered using blank shaders,
resulting in a pass-through filter.

The fix would be to actually make the RenderStyle::diff detect the change of the StyleCustomFilterProgram
using the pointer value and not the values. However, that will always invalidate the "filter" property because
of the StyleCustomFilterProgram that always gets created during the recalculation time.

I've added StyleCustomFilterProgramCache to cache all the instances of the StyleCustomFilterPrograms that a
StyleResolver allocates. This way, next time it will try to reuse previously allocated StyleCustomFilterPrograms.
The key of the cache is the CustomFilterProgramInfo, that combines the URLs to the shaders and a couple of other program settings.

StyleCustomFilterProgramCache is owned by the StyleResovler and StyleCustomFilterPrograms are responsible with
removing themselves from the cache when the last reference goes away.

This change makes the previous "platform level" program cache obsolete and I will remove that in a future patch.
https://bugs.webkit.org/show_bug.cgi?id=112844

Test: css3/filters/custom/custom-filter-reload.html

* GNUmakefile.list.am:
* Target.pri:
* WebCore.gypi:
* WebCore.vcproj/WebCore.vcproj:
* WebCore.xcodeproj/project.pbxproj:
* css/StyleResolver.cpp:
(WebCore::StyleResolver::lookupCustomFilterProgram): Lookup any similar programs in the cache. It will create a new pending
StyleCustomFilterProgram if there is no pre-cached version of the program.
if no program is found. loadPendingShaders is responsible for adding the program in the cache if it is actually going to be used.
(WebCore::StyleResolver::loadPendingShaders): At this point the program is final, so it's safe to add it to the cache.
(WebCore::StyleResolver::createCustomFilterOperationWithInlineSyntax):
* css/StyleResolver.h:
(StyleResolver):
* css/WebKitCSSShaderValue.cpp:
(WebCore::WebKitCSSShaderValue::completeURL): Factored out the function to compute the complete URL of the resource.
(WebCore::WebKitCSSShaderValue::cachedShader):
* css/WebKitCSSShaderValue.h:
(WebCore::toWebKitCSSShaderValue):
(WebKitCSSShaderValue):
* platform/graphics/filters/CustomFilterOperation.cpp:
(WebCore::CustomFilterOperation::blend):
* platform/graphics/filters/CustomFilterOperation.h:
(WebCore::CustomFilterOperation::operator==): Removed. Programs should now compare by pointer. Kept it as
private to catch any potential use of it.
* rendering/style/StyleCustomFilterProgram.cpp: Copied from Source/WebCore/css/WebKitCSSShaderValue.h.
(WebCore::StyleCustomFilterProgram::~StyleCustomFilterProgram): Destructor removes the program from the cache.
* rendering/style/StyleCustomFilterProgram.h:
(WebCore::StyleCustomFilterProgram::setVertexShader): Added an assert to check that the shader is not in the
cache while the mutation happens. Otherwise the cache might have the wrong key.
(WebCore::StyleCustomFilterProgram::setFragmentShader): Ditto.
(WebCore::StyleCustomFilterProgram::isLoaded): Added more asserts to catch cases when the program is used with no clients.
(StyleCustomFilterProgram):
(WebCore::StyleCustomFilterProgram::hasPendingShaders):
(WebCore::StyleCustomFilterProgram::inCache):
(WebCore::StyleCustomFilterProgram::setCache): Function called when a program is added to / removed from the cache.
(WebCore::StyleCustomFilterProgram::vertexShaderURL): Added methods to store the KURL that we used as keys in the cache.
The same KURLs will be used to lookup and remove the filter at the end.
(WebCore::StyleCustomFilterProgram::setVertexShaderURL):
(WebCore::StyleCustomFilterProgram::fragmentShaderURL):
(WebCore::StyleCustomFilterProgram::setFragmentShaderURL):
(WebCore::StyleCustomFilterProgram::StyleCustomFilterProgram):
* rendering/style/StyleCustomFilterProgramCache.cpp: Added.
(WebCore::StyleCustomFilterProgramCache::programCacheKey):
(WebCore::StyleCustomFilterProgramCache::StyleCustomFilterProgramCache):
(WebCore::StyleCustomFilterProgramCache::~StyleCustomFilterProgramCache): Destructor removes itself from all the
referenced StyleCustomFilterPrograms. This is to avoid issues with different destruction orders.
(WebCore::StyleCustomFilterProgramCache::lookup):
(WebCore::StyleCustomFilterProgramCache::add):
(WebCore::StyleCustomFilterProgramCache::remove):
* rendering/style/StyleCustomFilterProgramCache.h:
(StyleCustomFilterProgramCache):
* platform/graphics/texmap/coordinated/CoordinatedCustomFilterProgram.h:
(WebCore::CoordinatedCustomFilterProgram::operator==: Removed. Programs should now compare by pointer.

LayoutTests:

Added a new test to check for the case when the style is recalculated but the
filter property is not changed. All the other cases for the new StyleCustomFilterProgramCache
class should be tested by existing tests.

* css3/filters/custom/custom-filter-reload-expected.txt: Added.
* css3/filters/custom/custom-filter-reload.html: Added.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@146529 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 49ae7448
2013-03-21 Alexandru Chiculita <achicu@adobe.com>
[CSS Shaders] Implement a StyleCustomFilterProgram cache
https://bugs.webkit.org/show_bug.cgi?id=112602
Reviewed by Dean Jackson.
Added a new test to check for the case when the style is recalculated but the
filter property is not changed. All the other cases for the new StyleCustomFilterProgramCache
class should be tested by existing tests.
* css3/filters/custom/custom-filter-reload-expected.txt: Added.
* css3/filters/custom/custom-filter-reload.html: Added.
2013-03-21 Jochen Eisinger <jochen@chromium.org>
Skip triaged crashes on content shell
<!DOCTYPE html>
<!--
This tests verifies that we don't assert when the style is recalculated but the filter property doesn't change.
-->
<html>
<head>
<script>
if (window.testRunner) {
window.testRunner.overridePreference("WebKitCSSCustomFilterEnabled", "1");
window.testRunner.overridePreference("WebKitWebGLEnabled", "1");
window.testRunner.dumpAsText();
window.testRunner.waitUntilDone();
}
function test()
{
// Force a layout.
document.body.clientHeight;
var boxes = document.querySelectorAll(".box");
for (var i = 0; i < boxes.length; ++i)
boxes[i].classList.add("trigger-style-recalc");
// Switch the parent to composited mode, so that we can trigger
// a rebuild of the compositing layer tree.
document.body.style.webkitTransform = "translateZ(0px)"
// Force a layout.
document.body.clientHeight;
// If we get this far with no assert, the test passed.
if (window.testRunner)
window.testRunner.notifyDone();
}
</script>
<style>
.box {
height: 50px;
width: 50px;
background-color: green;
-webkit-transform: translateZ(0);
}
.vertex_shader
{
-webkit-filter: custom(url('../resources/vertex-offset.vs'));
}
.fragment_shader
{
-webkit-filter: custom(none mix(url('../resources/color-offset.fs') normal source-atop));
}
.both_shaders
{
-webkit-filter: custom(url('../resources/vertex-offset.vs') mix(url('../resources/color-offset.fs') normal source-atop));
}
.trigger-style-recalc {
/* No change, we just need a new style recalculation. */
}
</style>
</head>
<body onload="test()">
<!--
You should see three green boxes. Last two boxes have a different shade of green. Last box is slightly bigger on the left side.
The test passes if there is no crash or assert.
-->
<div class="box vertex_shader"></div>
<div class="box both_shaders"></div>
<div class="box fragment_shader"></div>
</body>
</html>
2013-03-21 Alexandru Chiculita <achicu@adobe.com>
[CSS Shaders] Implement a StyleCustomFilterProgram cache
https://bugs.webkit.org/show_bug.cgi?id=112602
Reviewed by Dean Jackson.
When the style is recalculated, the new computed RenderStyle is saved as the m_style of the
RenderObject, even if the style was not different.
In the case of Custom Filters, a new StyleCustomFilterProgram was created at all times, but the
actual equality check was done by comparing the pair of cached shaders from inside the StyleCustomFilterProgram.
Because of that the RenderLayer::styleChanged was not called when the new StyleCustomFilterProgram was created, so it
will end up still knowing only about the previous StyleCustomFilterProgram.
The RenderLayer sets itself as a client of the StyleCustomFilterProgram, so that it can repaint itself
when the program is loaded, but because RenderLayer::styleChanged is not called, it will not add itself as a client of the new
StyleCustomFilterProgram.
StyleCustomFilterProgram waits until the first client to load the programs, so in this case it will just remain unloaded.
There was no crash, but just an assert in debug mode. Also, as a visible side-effect some frames were rendered using blank shaders,
resulting in a pass-through filter.
The fix would be to actually make the RenderStyle::diff detect the change of the StyleCustomFilterProgram
using the pointer value and not the values. However, that will always invalidate the "filter" property because
of the StyleCustomFilterProgram that always gets created during the recalculation time.
I've added StyleCustomFilterProgramCache to cache all the instances of the StyleCustomFilterPrograms that a
StyleResolver allocates. This way, next time it will try to reuse previously allocated StyleCustomFilterPrograms.
The key of the cache is the CustomFilterProgramInfo, that combines the URLs to the shaders and a couple of other program settings.
StyleCustomFilterProgramCache is owned by the StyleResovler and StyleCustomFilterPrograms are responsible with
removing themselves from the cache when the last reference goes away.
This change makes the previous "platform level" program cache obsolete and I will remove that in a future patch.
https://bugs.webkit.org/show_bug.cgi?id=112844
Test: css3/filters/custom/custom-filter-reload.html
* GNUmakefile.list.am:
* Target.pri:
* WebCore.gypi:
* WebCore.vcproj/WebCore.vcproj:
* WebCore.xcodeproj/project.pbxproj:
* css/StyleResolver.cpp:
(WebCore::StyleResolver::lookupCustomFilterProgram): Lookup any similar programs in the cache. It will create a new pending
StyleCustomFilterProgram if there is no pre-cached version of the program.
if no program is found. loadPendingShaders is responsible for adding the program in the cache if it is actually going to be used.
(WebCore::StyleResolver::loadPendingShaders): At this point the program is final, so it's safe to add it to the cache.
(WebCore::StyleResolver::createCustomFilterOperationWithInlineSyntax):
* css/StyleResolver.h:
(StyleResolver):
* css/WebKitCSSShaderValue.cpp:
(WebCore::WebKitCSSShaderValue::completeURL): Factored out the function to compute the complete URL of the resource.
(WebCore::WebKitCSSShaderValue::cachedShader):
* css/WebKitCSSShaderValue.h:
(WebCore::toWebKitCSSShaderValue):
(WebKitCSSShaderValue):
* platform/graphics/filters/CustomFilterOperation.cpp:
(WebCore::CustomFilterOperation::blend):
* platform/graphics/filters/CustomFilterOperation.h:
(WebCore::CustomFilterOperation::operator==): Removed. Programs should now compare by pointer. Kept it as
private to catch any potential use of it.
* rendering/style/StyleCustomFilterProgram.cpp: Copied from Source/WebCore/css/WebKitCSSShaderValue.h.
(WebCore::StyleCustomFilterProgram::~StyleCustomFilterProgram): Destructor removes the program from the cache.
* rendering/style/StyleCustomFilterProgram.h:
(WebCore::StyleCustomFilterProgram::setVertexShader): Added an assert to check that the shader is not in the
cache while the mutation happens. Otherwise the cache might have the wrong key.
(WebCore::StyleCustomFilterProgram::setFragmentShader): Ditto.
(WebCore::StyleCustomFilterProgram::isLoaded): Added more asserts to catch cases when the program is used with no clients.
(StyleCustomFilterProgram):
(WebCore::StyleCustomFilterProgram::hasPendingShaders):
(WebCore::StyleCustomFilterProgram::inCache):
(WebCore::StyleCustomFilterProgram::setCache): Function called when a program is added to / removed from the cache.
(WebCore::StyleCustomFilterProgram::vertexShaderURL): Added methods to store the KURL that we used as keys in the cache.
The same KURLs will be used to lookup and remove the filter at the end.
(WebCore::StyleCustomFilterProgram::setVertexShaderURL):
(WebCore::StyleCustomFilterProgram::fragmentShaderURL):
(WebCore::StyleCustomFilterProgram::setFragmentShaderURL):
(WebCore::StyleCustomFilterProgram::StyleCustomFilterProgram):
* rendering/style/StyleCustomFilterProgramCache.cpp: Added.
(WebCore::StyleCustomFilterProgramCache::programCacheKey):
(WebCore::StyleCustomFilterProgramCache::StyleCustomFilterProgramCache):
(WebCore::StyleCustomFilterProgramCache::~StyleCustomFilterProgramCache): Destructor removes itself from all the
referenced StyleCustomFilterPrograms. This is to avoid issues with different destruction orders.
(WebCore::StyleCustomFilterProgramCache::lookup):
(WebCore::StyleCustomFilterProgramCache::add):
(WebCore::StyleCustomFilterProgramCache::remove):
* rendering/style/StyleCustomFilterProgramCache.h:
(StyleCustomFilterProgramCache):
* platform/graphics/texmap/coordinated/CoordinatedCustomFilterProgram.h:
(WebCore::CoordinatedCustomFilterProgram::operator==: Removed. Programs should now compare by pointer.
2013-03-21 Joshua Bell <jsbell@chromium.org>
IndexedDB: Ensure all API methods have IDB_TRACE macros
......@@ -4663,7 +4663,10 @@ webcore_sources += \
Source/WebCore/rendering/style/StyleCachedImageSet.h \
Source/WebCore/rendering/style/StyleCachedShader.cpp \
Source/WebCore/rendering/style/StyleCachedShader.h \
Source/WebCore/rendering/style/StyleCustomFilterProgram.cpp \
Source/WebCore/rendering/style/StyleCustomFilterProgram.h \
Source/WebCore/rendering/style/StyleCustomFilterProgramCache.cpp \
Source/WebCore/rendering/style/StyleCustomFilterProgramCache.h \
Source/WebCore/rendering/style/StyleDashboardRegion.h \
Source/WebCore/rendering/style/StyleDeprecatedFlexibleBoxData.cpp \
Source/WebCore/rendering/style/StyleDeprecatedFlexibleBoxData.h \
......
......@@ -1286,6 +1286,8 @@ SOURCES += \
rendering/style/StyleCachedImage.cpp \
rendering/style/StyleCachedImageSet.cpp \
rendering/style/StyleCachedShader.cpp \
rendering/style/StyleCustomFilterProgram.cpp \
rendering/style/StyleCustomFilterProgramCache.cpp \
rendering/style/StyleDeprecatedFlexibleBoxData.cpp \
rendering/style/StyleFilterData.cpp \
rendering/style/StyleFlexibleBoxData.cpp \
......@@ -2583,6 +2585,7 @@ HEADERS += \
rendering/style/StyleCachedImage.h \
rendering/style/StyleCachedShader.h \
rendering/style/StyleCustomFilterProgram.h \
rendering/style/StyleCustomFilterProgramCache.h \
rendering/style/StyleDeprecatedFlexibleBoxData.h \
rendering/style/StyleFilterData.h \
rendering/style/StyleFlexibleBoxData.h \
......
......@@ -2656,6 +2656,9 @@
'rendering/style/StyleCachedImageSet.cpp',
'rendering/style/StyleCachedShader.h',
'rendering/style/StyleCachedShader.cpp',
'rendering/style/StyleCustomFilterProgramCache.cpp',
'rendering/style/StyleCustomFilterProgramCache.h',
'rendering/style/StyleCustomFilterProgram.cpp',
'rendering/style/StyleCustomFilterProgram.h',
'rendering/style/StyleDeprecatedFlexibleBoxData.cpp',
'rendering/style/StyleFilterData.cpp',
......
......@@ -46967,6 +46967,18 @@
RelativePath="..\rendering\style\StyleCustomFilterProgram.h"
>
</File>
<File
RelativePath="..\rendering\style\StyleCustomFilterProgram.cpp"
>
</File>
<File
RelativePath="..\rendering\style\StyleCustomFilterProgramCache.h"
>
</File>
<File
RelativePath="..\rendering\style\StyleCustomFilterProgramCache.cpp"
>
</File>
<File
RelativePath="..\rendering\style\StyleDeprecatedFlexibleBoxData.cpp"
>
......@@ -1571,6 +1571,9 @@
50D40612147D49DE00D30BB5 /* CustomFilterCompiledProgram.h in Headers */ = {isa = PBXBuildFile; fileRef = 50D40610147D49DE00D30BB5 /* CustomFilterCompiledProgram.h */; };
50D88CB515BDFDAA001809F4 /* CustomFilterProgramInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 50D88CB315BDFDAA001809F4 /* CustomFilterProgramInfo.cpp */; };
50D88CB615BDFDAA001809F4 /* CustomFilterProgramInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 50D88CB415BDFDAA001809F4 /* CustomFilterProgramInfo.h */; };
50E18CD816F9285800C65486 /* StyleCustomFilterProgram.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 50E18CD516F9285800C65486 /* StyleCustomFilterProgram.cpp */; };
50E18CD916F9285800C65486 /* StyleCustomFilterProgramCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 50E18CD616F9285800C65486 /* StyleCustomFilterProgramCache.cpp */; };
50E18CDA16F9285800C65486 /* StyleCustomFilterProgramCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 50E18CD716F9285800C65486 /* StyleCustomFilterProgramCache.h */; };
510184690B08602A004A825F /* CachedPage.h in Headers */ = {isa = PBXBuildFile; fileRef = 510184670B08602A004A825F /* CachedPage.h */; settings = {ATTRIBUTES = (Private, ); }; };
5101846A0B08602A004A825F /* CachedPage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 510184680B08602A004A825F /* CachedPage.cpp */; };
510D4A33103165EE0049EA54 /* SocketStreamErrorBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 510D4A2D103165EE0049EA54 /* SocketStreamErrorBase.cpp */; };
......@@ -9044,6 +9047,9 @@
50D40610147D49DE00D30BB5 /* CustomFilterCompiledProgram.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CustomFilterCompiledProgram.h; path = filters/CustomFilterCompiledProgram.h; sourceTree = "<group>"; };
50D88CB315BDFDAA001809F4 /* CustomFilterProgramInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CustomFilterProgramInfo.cpp; path = filters/CustomFilterProgramInfo.cpp; sourceTree = "<group>"; };
50D88CB415BDFDAA001809F4 /* CustomFilterProgramInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CustomFilterProgramInfo.h; path = filters/CustomFilterProgramInfo.h; sourceTree = "<group>"; };
50E18CD516F9285800C65486 /* StyleCustomFilterProgram.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StyleCustomFilterProgram.cpp; path = style/StyleCustomFilterProgram.cpp; sourceTree = "<group>"; };
50E18CD616F9285800C65486 /* StyleCustomFilterProgramCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StyleCustomFilterProgramCache.cpp; path = style/StyleCustomFilterProgramCache.cpp; sourceTree = "<group>"; };
50E18CD716F9285800C65486 /* StyleCustomFilterProgramCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StyleCustomFilterProgramCache.h; path = style/StyleCustomFilterProgramCache.h; sourceTree = "<group>"; };
510184670B08602A004A825F /* CachedPage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CachedPage.h; sourceTree = "<group>"; };
510184680B08602A004A825F /* CachedPage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CachedPage.cpp; sourceTree = "<group>"; };
510D4A2D103165EE0049EA54 /* SocketStreamErrorBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SocketStreamErrorBase.cpp; sourceTree = "<group>"; };
......@@ -21388,6 +21394,9 @@
9393E603151A9A1800066F06 /* StyleCachedImageSet.h */,
5038BE2D1472AD230095E0D1 /* StyleCachedShader.cpp */,
5038BE2E1472AD230095E0D1 /* StyleCachedShader.h */,
50E18CD616F9285800C65486 /* StyleCustomFilterProgramCache.cpp */,
50E18CD716F9285800C65486 /* StyleCustomFilterProgramCache.h */,
50E18CD516F9285800C65486 /* StyleCustomFilterProgram.cpp */,
503D0CAD14B5B0BA00F32F57 /* StyleCustomFilterProgram.h */,
BC5EB67E0E81D4A700B25965 /* StyleDashboardRegion.h */,
BC5EB8B60E8201BD00B25965 /* StyleDeprecatedFlexibleBoxData.cpp */,
......@@ -26757,6 +26766,7 @@
FD537353137B651800008DCE /* ZeroPole.h in Headers */,
DAED203116F244480070EC0F /* PageConsole.h in Headers */,
2D5BC42716F882EE007048D0 /* SecurityPolicyViolationEvent.h in Headers */,
50E18CDA16F9285800C65486 /* StyleCustomFilterProgramCache.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
......@@ -29963,6 +29973,8 @@
FD537352137B651800008DCE /* ZeroPole.cpp in Sources */,
DAED203016F2442B0070EC0F /* PageConsole.cpp in Sources */,
E1BA003116FB92AC00BA7A35 /* ResourceHandleClient.cpp in Sources */,
50E18CD816F9285800C65486 /* StyleCustomFilterProgram.cpp in Sources */,
50E18CD916F9285800C65486 /* StyleCustomFilterProgramCache.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
......@@ -164,9 +164,11 @@
#include "CustomFilterNumberParameter.h"
#include "CustomFilterOperation.h"
#include "CustomFilterParameter.h"
#include "CustomFilterProgramInfo.h"
#include "CustomFilterTransformParameter.h"
#include "StyleCachedShader.h"
#include "StyleCustomFilterProgram.h"
#include "StyleCustomFilterProgramCache.h"
#include "StylePendingShader.h"
#include "StyleShader.h"
#include "WebKitCSSMixFunctionValue.h"
......@@ -3941,6 +3943,23 @@ StyleShader* StyleResolver::cachedOrPendingStyleShaderFromValue(WebKitCSSShaderV
return shader;
}
PassRefPtr<CustomFilterProgram> StyleResolver::lookupCustomFilterProgram(WebKitCSSShaderValue* vertexShader, WebKitCSSShaderValue* fragmentShader,
CustomFilterProgramType programType, const CustomFilterProgramMixSettings& mixSettings, CustomFilterMeshType meshType)
{
CachedResourceLoader* cachedResourceLoader = m_state.document()->cachedResourceLoader();
KURL vertexShaderURL = vertexShader ? vertexShader->completeURL(cachedResourceLoader) : KURL();
KURL fragmentShaderURL = fragmentShader ? fragmentShader->completeURL(cachedResourceLoader) : KURL();
RefPtr<StyleCustomFilterProgram> program;
if (m_customFilterProgramCache)
program = m_customFilterProgramCache->lookup(CustomFilterProgramInfo(vertexShaderURL, fragmentShaderURL, programType, mixSettings, meshType));
if (!program) {
// Create a new StyleCustomFilterProgram that will be resolved during the loadPendingShaders and added to the cache.
program = StyleCustomFilterProgram::create(vertexShaderURL, vertexShader ? styleShader(vertexShader) : 0,
fragmentShaderURL, fragmentShader ? styleShader(fragmentShader) : 0, programType, mixSettings, meshType);
}
return program.release();
}
void StyleResolver::loadPendingShaders()
{
if (!m_state.style()->hasFilter() || !m_state.hasPendingShaders())
......@@ -3955,13 +3974,26 @@ void StyleResolver::loadPendingShaders()
CustomFilterOperation* customFilter = static_cast<CustomFilterOperation*>(filterOperation.get());
ASSERT(customFilter->program());
StyleCustomFilterProgram* program = static_cast<StyleCustomFilterProgram*>(customFilter->program());
if (program->vertexShader() && program->vertexShader()->isPendingShader()) {
WebKitCSSShaderValue* shaderValue = static_cast<StylePendingShader*>(program->vertexShader())->cssShaderValue();
program->setVertexShader(shaderValue->cachedShader(cachedResourceLoader));
}
if (program->fragmentShader() && program->fragmentShader()->isPendingShader()) {
WebKitCSSShaderValue* shaderValue = static_cast<StylePendingShader*>(program->fragmentShader())->cssShaderValue();
program->setFragmentShader(shaderValue->cachedShader(cachedResourceLoader));
// Note that the StylePendingShaders could be already resolved to StyleCachedShaders. That's because the rule was matched before.
// However, the StyleCustomFilterProgram that was initially created could have been removed from the cache in the meanwhile,
// meaning that we get a new StyleCustomFilterProgram here that is not yet in the cache, but already has loaded StyleShaders.
if (!program->hasPendingShaders() && program->inCache())
continue;
if (!m_customFilterProgramCache)
m_customFilterProgramCache = adoptPtr(new StyleCustomFilterProgramCache());
RefPtr<StyleCustomFilterProgram> styleProgram = m_customFilterProgramCache->lookup(program);
if (styleProgram.get())
customFilter->setProgram(styleProgram.release());
else {
if (program->vertexShader() && program->vertexShader()->isPendingShader()) {
WebKitCSSShaderValue* shaderValue = static_cast<StylePendingShader*>(program->vertexShader())->cssShaderValue();
program->setVertexShader(shaderValue->cachedShader(cachedResourceLoader));
}
if (program->fragmentShader() && program->fragmentShader()->isPendingShader()) {
WebKitCSSShaderValue* shaderValue = static_cast<StylePendingShader*>(program->fragmentShader())->cssShaderValue();
program->setFragmentShader(shaderValue->cachedShader(cachedResourceLoader));
}
m_customFilterProgramCache->add(program);
}
}
}
......@@ -4105,20 +4137,19 @@ PassRefPtr<CustomFilterOperation> StyleResolver::createCustomFilterOperationWith
unsigned shadersListLength = shadersList->length();
ASSERT(shadersListLength);
RefPtr<StyleShader> vertexShader = styleShader(shadersList->itemWithoutBoundsCheck(0));
RefPtr<StyleShader> fragmentShader;
WebKitCSSShaderValue* vertexShader = toWebKitCSSShaderValue(shadersList->itemWithoutBoundsCheck(0));
WebKitCSSShaderValue* fragmentShader = 0;
CustomFilterProgramType programType = PROGRAM_TYPE_BLENDS_ELEMENT_TEXTURE;
CustomFilterProgramMixSettings mixSettings;
if (shadersListLength > 1) {
CSSValue* fragmentShaderOrMixFunction = shadersList->itemWithoutBoundsCheck(1);
if (fragmentShaderOrMixFunction->isWebKitCSSMixFunctionValue()) {
WebKitCSSMixFunctionValue* mixFunction = static_cast<WebKitCSSMixFunctionValue*>(fragmentShaderOrMixFunction);
CSSValueListIterator iterator(mixFunction);
ASSERT(mixFunction->length());
fragmentShader = styleShader(iterator.value());
fragmentShader = toWebKitCSSShaderValue(iterator.value());
iterator.advance();
ASSERT(mixFunction->length() <= 3);
......@@ -4134,9 +4165,12 @@ PassRefPtr<CustomFilterOperation> StyleResolver::createCustomFilterOperationWith
}
} else {
programType = PROGRAM_TYPE_NO_ELEMENT_TEXTURE;
fragmentShader = styleShader(fragmentShaderOrMixFunction);
fragmentShader = toWebKitCSSShaderValue(fragmentShaderOrMixFunction);
}
}
if (!vertexShader && !fragmentShader)
return 0;
unsigned meshRows = 1;
unsigned meshColumns = 1;
......@@ -4192,8 +4226,8 @@ PassRefPtr<CustomFilterOperation> StyleResolver::createCustomFilterOperationWith
CustomFilterParameterList parameterList;
if (parametersValue && !parseCustomFilterParameterList(parametersValue, parameterList))
return 0;
RefPtr<StyleCustomFilterProgram> program = StyleCustomFilterProgram::create(vertexShader.release(), fragmentShader.release(), programType, mixSettings, meshType);
RefPtr<CustomFilterProgram> program = lookupCustomFilterProgram(vertexShader, fragmentShader, programType, mixSettings, meshType);
return CustomFilterOperation::create(program.release(), parameterList, meshRows, meshColumns, meshType);
}
......
......@@ -43,6 +43,9 @@
#if ENABLE(CSS_FILTERS) && ENABLE(SVG)
#include "WebKitCSSSVGDocumentValue.h"
#endif
#if ENABLE(CSS_SHADERS)
#include "CustomFilterConstants.h"
#endif
#include <wtf/HashMap.h>
#include <wtf/HashSet.h>
#include <wtf/RefPtr.h>
......@@ -72,6 +75,8 @@ class ContainerNode;
class CustomFilterOperation;
class CustomFilterParameter;
class CustomFilterParameterList;
class CustomFilterProgram;
struct CustomFilterProgramMixSettings;
class Document;
class Element;
class Frame;
......@@ -87,6 +92,7 @@ class RuleData;
class RuleSet;
class Settings;
class StaticCSSRuleList;
class StyleCustomFilterProgramCache;
class StyleBuilder;
class StyleScopeResolver;
class StyleImage;
......@@ -317,6 +323,8 @@ public:
PassRefPtr<CustomFilterOperation> createCustomFilterOperationWithInlineSyntax(WebKitCSSFilterValue*);
PassRefPtr<CustomFilterOperation> createCustomFilterOperation(WebKitCSSFilterValue*);
void loadPendingShaders();
PassRefPtr<CustomFilterProgram> lookupCustomFilterProgram(WebKitCSSShaderValue* vertexShader, WebKitCSSShaderValue* fragmentShader,
CustomFilterProgramType, const CustomFilterProgramMixSettings&, CustomFilterMeshType);
#endif
#if ENABLE(SVG)
void loadPendingSVGDocuments();
......@@ -631,6 +639,10 @@ private:
State m_state;
#if ENABLE(CSS_SHADERS)
OwnPtr<StyleCustomFilterProgramCache> m_customFilterProgramCache;
#endif
friend class StyleBuilder;
friend bool operator==(const MatchedProperties&, const MatchedProperties&);
friend bool operator!=(const MatchedProperties&, const MatchedProperties&);
......
......@@ -37,6 +37,7 @@
#include "CachedResourceRequest.h"
#include "CachedResourceRequestInitiators.h"
#include "Document.h"
#include "KURL.h"
#include "StyleCachedShader.h"
#include "StylePendingShader.h"
#include "WebCoreMemoryInstrumentation.h"
......@@ -54,6 +55,11 @@ WebKitCSSShaderValue::~WebKitCSSShaderValue()
{
}
KURL WebKitCSSShaderValue::completeURL(CachedResourceLoader* loader) const
{
return loader->document()->completeURL(m_url);
}
StyleCachedShader* WebKitCSSShaderValue::cachedShader(CachedResourceLoader* loader)
{
ASSERT(loader);
......@@ -61,7 +67,7 @@ StyleCachedShader* WebKitCSSShaderValue::cachedShader(CachedResourceLoader* load
if (!m_accessedShader) {
m_accessedShader = true;
CachedResourceRequest request(ResourceRequest(loader->document()->completeURL(m_url)));
CachedResourceRequest request(ResourceRequest(completeURL(loader)));
request.setInitiator(cachedResourceRequestInitiators().css);
if (CachedResourceHandle<CachedShader> cachedShader = loader->requestShader(request))
m_shader = StyleCachedShader::create(cachedShader.get());
......
......@@ -37,6 +37,7 @@
namespace WebCore {
class CachedResourceLoader;
class KURL;
class StyleCachedShader;
class StyleShader;
......@@ -48,6 +49,7 @@ public:
const String& format() const { return m_format; }
void setFormat(const String& format) { m_format = format; }
KURL completeURL(CachedResourceLoader*) const;
StyleCachedShader* cachedShader(CachedResourceLoader*);
StyleShader* cachedOrPendingShader();
......@@ -66,6 +68,14 @@ private:
bool m_accessedShader;
};
// This will catch anyone doing an unnecessary cast.
WebKitCSSShaderValue* toWebKitCSSShaderValue(const WebKitCSSShaderValue*);
inline WebKitCSSShaderValue* toWebKitCSSShaderValue(CSSValue* value)
{
return value->isWebKitCSSShaderValue() ? static_cast<WebKitCSSShaderValue*>(value) : 0;
}
} // namespace WebCore
#endif // ENABLE(CSS_SHADERS)
......
......@@ -63,7 +63,7 @@ PassRefPtr<FilterOperation> CustomFilterOperation::blend(const FilterOperation*
return this;
const CustomFilterOperation* fromOp = static_cast<const CustomFilterOperation*>(from);
if (*m_program.get() != *fromOp->m_program.get()
if (m_program.get() != fromOp->m_program.get()
|| m_meshRows != fromOp->m_meshRows
|| m_meshColumns != fromOp->m_meshColumns
|| m_meshType != fromOp->m_meshType)
......
......@@ -76,7 +76,7 @@ private:
return false;
const CustomFilterOperation* other = static_cast<const CustomFilterOperation*>(&o);
return *m_program.get() == *other->m_program.get()
return m_program.get() == other->m_program.get()
&& m_meshRows == other->m_meshRows
&& m_meshColumns == other->m_meshColumns
&& m_meshType == other->m_meshType
......
......@@ -86,12 +86,5 @@ CustomFilterProgramInfo CustomFilterProgram::programInfo() const
return CustomFilterProgramInfo(vertexShaderString(), fragmentShaderString(), m_programType, m_mixSettings, m_meshType);
}
bool CustomFilterProgram::operator==(const CustomFilterProgram& o) const
{
return m_programType == o.m_programType
&& (m_programType != PROGRAM_TYPE_BLENDS_ELEMENT_TEXTURE || m_mixSettings == o.m_mixSettings)
&& m_meshType == o.m_meshType;
}
} // namespace WebCore
#endif // ENABLE(CSS_SHADERS)
......@@ -63,8 +63,6 @@ public:
CustomFilterProgramMixSettings mixSettings() const { return m_mixSettings; }
CustomFilterMeshType meshType() const { return m_meshType; }
virtual bool operator==(const CustomFilterProgram&) const;
bool operator!=(const CustomFilterProgram& o) const { return !(*this == o); }
protected:
// StyleCustomFilterProgram can notify the clients that the cached resources are
// loaded and it is ready to create CustomFilterCompiledProgram objects.
......@@ -77,6 +75,12 @@ protected:
CustomFilterProgram(CustomFilterProgramType, const CustomFilterProgramMixSettings&, CustomFilterMeshType);
private:
// CustomFilterPrograms are unique combinations of shaders and can be
// compared using just the pointer value instead.
// These will catch anyone doing a value equal comparison.
bool operator==(const CustomFilterProgram&) const;
bool operator!=(const CustomFilterProgram&) const;
typedef HashCountedSet<CustomFilterProgramClient*> CustomFilterProgramClientList;
CustomFilterProgramClientList m_clients;
CustomFilterProgramType m_programType;
......
......@@ -41,17 +41,6 @@ public:
virtual bool isLoaded() const OVERRIDE { return true; }
virtual bool operator==(const CustomFilterProgram& o) const OVERRIDE
{
// We don't use the != operator because that would recursively call this method.
if (!CustomFilterProgram::operator==(o))
return false;
// The following cast is ugly, but CoordinatedCustomFilterProgram is the single implementation of CustomFilterProgram on UI Process.
const CoordinatedCustomFilterProgram* other = static_cast<const CoordinatedCustomFilterProgram*>(&o);
return m_vertexShaderString == other->vertexShaderString() && m_fragmentShaderString == other->fragmentShaderString();
}
protected:
virtual String vertexShaderString() const OVERRIDE { return m_vertexShaderString; }
virtual String fragmentShaderString() const OVERRIDE { return m_fragmentShaderString; }
......
/*
* Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF