Modified: trunk/Source/WebCore/ChangeLog (156351 => 156352)
--- trunk/Source/WebCore/ChangeLog 2013-09-24 19:43:22 UTC (rev 156351)
+++ trunk/Source/WebCore/ChangeLog 2013-09-24 19:43:25 UTC (rev 156352)
@@ -1,5 +1,36 @@
2013-09-24 Dean Jackson <[email protected]>
+ Implement symbol name hashing for WebGL shaders
+ https://bugs.webkit.org/show_bug.cgi?id=121849
+
+ Reviewed by Anders Carlsson.
+
+ Turn on ANGLE's symbol name mapping for shader programs.
+ This avoids compilation failures (or worse, crashers)
+ on some hardware that doesn't like it when shaders redefine
+ symbols like "sin", even though that is valid.
+
+ The way ANGLE exposes this is via setting a pointer
+ to a char* -> uint64_t hash function. Since we only have
+ a 32-bit hash in WebKit, I combine the 32-bit value with
+ a counter value that exists over the lifetime of a GC3D context.
+ Before calling ANGLE, I point the global hash map to the local
+ hash map, and then clean up after we're done. This introduces
+ a memory hit, in that the symbol table will build up until
+ the context is released.
+
+ Covered by Khronos WebGL tests, including
+ conformance/glsl/misc/shader-with-non-reserved-words.html
+
+ * platform/graphics/GraphicsContext3D.h: Define a ShaderNameHash type,
+ and add an OwnPtr to one as a member variable.
+ * platform/graphics/opengl/GraphicsContext3DOpenGLCommon.cpp:
+ (WebCore::nameHashForShader): Global function used for ANGLE hashing.
+ (WebCore::GraphicsContext3D::compileShader): Set up the ANGLE properties,
+ point to the local hash map, and call compile/translate.
+
+2013-09-24 Dean Jackson <[email protected]>
+
Use mapped name in attribute location binding
https://bugs.webkit.org/show_bug.cgi?id=121847
<rdar://problem/15067526>
Modified: trunk/Source/WebCore/platform/graphics/GraphicsContext3D.h (156351 => 156352)
--- trunk/Source/WebCore/platform/graphics/GraphicsContext3D.h 2013-09-24 19:43:22 UTC (rev 156351)
+++ trunk/Source/WebCore/platform/graphics/GraphicsContext3D.h 2013-09-24 19:43:25 UTC (rev 156352)
@@ -108,6 +108,8 @@
class GraphicsContext;
#endif
+typedef WTF::HashMap<CString, uint64_t> ShaderNameHash;
+
struct ActiveInfo {
String name;
GC3Denum type;
@@ -1024,6 +1026,8 @@
String originalSymbolName(Platform3DObject program, ANGLEShaderSymbolType, const String& name);
ANGLEWebKitBridge m_compiler;
+
+ OwnPtr<ShaderNameHash> nameHashMapForShaders;
#endif
#if PLATFORM(BLACKBERRY) || (PLATFORM(QT) && defined(QT_OPENGL_ES_2)) || ((PLATFORM(GTK) || PLATFORM(EFL) || PLATFORM(WIN)) && USE(OPENGL_ES_2))
Modified: trunk/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGLCommon.cpp (156351 => 156352)
--- trunk/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGLCommon.cpp 2013-09-24 19:43:22 UTC (rev 156351)
+++ trunk/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGLCommon.cpp 2013-09-24 19:43:25 UTC (rev 156352)
@@ -67,6 +67,42 @@
namespace WebCore {
+static ShaderNameHash* currentNameHashMapForShader;
+
+// Hash function used by the ANGLE translator/compiler to do
+// symbol name mangling. Since this is a static method, before
+// calling compileShader we set currentNameHashMapForShader
+// to point to the map kept by the current instance of GraphicsContext3D.
+
+static uint64_t nameHashForShader(const char* name, size_t length)
+{
+ if (!length)
+ return 0;
+
+ CString nameAsCString = CString(name);
+
+ // Look up name in our local map.
+ if (currentNameHashMapForShader) {
+ ShaderNameHash::iterator result = currentNameHashMapForShader->find(nameAsCString);
+ if (result != currentNameHashMapForShader->end())
+ return result->value;
+ }
+
+ unsigned hashValue = nameAsCString.hash();
+
+ // Convert the 32-bit hash from CString::hash into a 64-bit result
+ // by shifting then adding the size of our table. Overflow would
+ // only be a problem if we're already hashing to the same value (and
+ // we're hoping that over the lifetime of the context we
+ // don't have that many symbols).
+
+ uint64_t result = hashValue;
+ result = (result << 32) + (currentNameHashMapForShader->size() + 1);
+
+ currentNameHashMapForShader->set(nameAsCString, result);
+ return result;
+}
+
PassRefPtr<GraphicsContext3D> GraphicsContext3D::createForCurrentGLContext()
{
RefPtr<GraphicsContext3D> context = adoptRef(new GraphicsContext3D(Attributes(), 0, GraphicsContext3D::RenderToCurrentGLContext));
@@ -443,15 +479,33 @@
ASSERT(shader);
makeContextCurrent();
+ // Turn on name mapping. Due to the way ANGLE name hashing works, we
+ // point a global hashmap to the map owned by this context.
+ ShBuiltInResources ANGLEResources = m_compiler.getResources();
+ ShHashFunction64 previousHashFunction = ANGLEResources.HashFunction;
+ ANGLEResources.HashFunction = nameHashForShader;
+
+ if (!nameHashMapForShaders)
+ nameHashMapForShaders = adoptPtr(new ShaderNameHash);
+ currentNameHashMapForShader = nameHashMapForShaders.get();
+ m_compiler.setResources(ANGLEResources);
+
String translatedShaderSource = m_extensions->getTranslatedShaderSourceANGLE(shader);
+ ANGLEResources.HashFunction = previousHashFunction;
+ m_compiler.setResources(ANGLEResources);
+ currentNameHashMapForShader = nullptr;
+
if (!translatedShaderSource.length())
return;
const CString& translatedShaderCString = translatedShaderSource.utf8();
const char* translatedShaderPtr = translatedShaderCString.data();
int translatedShaderLength = translatedShaderCString.length();
-
+
+ LOG(WebGL, "--- begin original shader source ---\n%s\n--- end original shader source ---\n", getShaderSource(shader).utf8().data());
+ LOG(WebGL, "--- begin translated shader source ---\n%s\n--- end translated shader source ---", translatedShaderPtr);
+
::glShaderSource(shader, 1, &translatedShaderPtr, &translatedShaderLength);
::glCompileShader(shader);
@@ -460,32 +514,28 @@
::glGetShaderiv(shader, COMPILE_STATUS, &GLCompileSuccess);
+ ShaderSourceMap::iterator result = m_shaderSourceMap.find(shader);
+ GraphicsContext3D::ShaderSourceEntry& entry = result->value;
+
// Populate the shader log
GLint length = 0;
::glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
if (length) {
- ShaderSourceMap::iterator result = m_shaderSourceMap.find(shader);
- GraphicsContext3D::ShaderSourceEntry& entry = result->value;
-
GLsizei size = 0;
auto info = std::make_unique<GLchar[]>(length);
::glGetShaderInfoLog(shader, length, &size, info.get());
entry.log = info.get();
+ }
- if (GLCompileSuccess != GL_TRUE) {
- entry.isValid = false;
- LOG(WebGL, "Error: shader translator produced a shader that OpenGL would not compile.");
- LOG(WebGL, "--- begin original shader source ---\n%s\n--- end original shader source ---\n", getShaderSource(shader).utf8().data());
- LOG(WebGL, "--- begin translated shader source ---\n%s\n--- end translated shader source ---", translatedShaderPtr);
- }
- }
-
+ if (GLCompileSuccess != GL_TRUE) {
+ entry.isValid = false;
+ LOG(WebGL, "Error: shader translator produced a shader that OpenGL would not compile.");
#if PLATFORM(BLACKBERRY) && !defined(NDEBUG)
- if (GLCompileSuccess != GL_TRUE)
BBLOG(BlackBerry::Platform::LogLevelWarn, "The shader validated, but didn't compile.\n");
#endif
+ }
}
void GraphicsContext3D::copyTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Dint border)