[SCM] WebKit Debian packaging branch, webkit-1.2, updated. upstream/1.1.90-6072-g9a69373

eric at webkit.org eric at webkit.org
Thu Apr 8 00:38:36 UTC 2010


The following commit has been merged in the webkit-1.2 branch:
commit 2b3a371653c8b5239e0d1a4c91589b6b367d4882
Author: eric at webkit.org <eric at webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Wed Dec 16 18:50:55 2009 +0000

    2009-12-16  Kenneth Russell  <kbr at google.com>
    
            Reviewed by Darin Fisher.
    
            Performance problems with index validation code for drawElements
            https://bugs.webkit.org/show_bug.cgi?id=32466
    
            Added a cache of the maximum index for each element type to
            WebGLBuffer, querying it before iterating through the indices in
            the client-side copy of the buffer's data. Hoisted checks of the
            size of the element array itself into validateElementArraySize to
            avoid duplicating code.
    
            The performance improvement has been measured with manual tests.
            Existing layout tests cover the index validation functionality
            and continue to pass as before.
    
            * html/canvas/WebGLBuffer.cpp:
            (WebCore::WebGLBuffer::WebGLBuffer):
            (WebCore::WebGLBuffer::associateBufferData):
            (WebCore::WebGLBuffer::associateBufferSubData):
            (WebCore::WebGLBuffer::getCachedMaxIndex):
            (WebCore::WebGLBuffer::setCachedMaxIndex):
            (WebCore::WebGLBuffer::clearCachedMaxIndices):
            * html/canvas/WebGLBuffer.h:
            * html/canvas/WebGLRenderingContext.cpp:
            (WebCore::WebGLRenderingContext::validateElementArraySize):
            (WebCore::WebGLRenderingContext::validateIndexArrayConservative):
            (WebCore::WebGLRenderingContext::validateIndexArrayPrecise):
            (WebCore::WebGLRenderingContext::validateRenderingState):
            (WebCore::WebGLRenderingContext::drawElements):
            * html/canvas/WebGLRenderingContext.h:
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@52205 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index 288b665..8d898fd 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,36 @@
+2009-12-16  Kenneth Russell  <kbr at google.com>
+
+        Reviewed by Darin Fisher.
+
+        Performance problems with index validation code for drawElements
+        https://bugs.webkit.org/show_bug.cgi?id=32466
+
+        Added a cache of the maximum index for each element type to
+        WebGLBuffer, querying it before iterating through the indices in
+        the client-side copy of the buffer's data. Hoisted checks of the
+        size of the element array itself into validateElementArraySize to
+        avoid duplicating code.
+
+        The performance improvement has been measured with manual tests.
+        Existing layout tests cover the index validation functionality
+        and continue to pass as before.
+
+        * html/canvas/WebGLBuffer.cpp:
+        (WebCore::WebGLBuffer::WebGLBuffer):
+        (WebCore::WebGLBuffer::associateBufferData):
+        (WebCore::WebGLBuffer::associateBufferSubData):
+        (WebCore::WebGLBuffer::getCachedMaxIndex):
+        (WebCore::WebGLBuffer::setCachedMaxIndex):
+        (WebCore::WebGLBuffer::clearCachedMaxIndices):
+        * html/canvas/WebGLBuffer.h:
+        * html/canvas/WebGLRenderingContext.cpp:
+        (WebCore::WebGLRenderingContext::validateElementArraySize):
+        (WebCore::WebGLRenderingContext::validateIndexArrayConservative):
+        (WebCore::WebGLRenderingContext::validateIndexArrayPrecise):
+        (WebCore::WebGLRenderingContext::validateRenderingState):
+        (WebCore::WebGLRenderingContext::drawElements):
+        * html/canvas/WebGLRenderingContext.h:
+
 2009-12-16  Zelidrag Hornung  <zelidrag at chromium.org>
 
         Reviewed by Darin Adler.
diff --git a/WebCore/html/canvas/WebGLBuffer.cpp b/WebCore/html/canvas/WebGLBuffer.cpp
index cbad6a0..88d07de 100644
--- a/WebCore/html/canvas/WebGLBuffer.cpp
+++ b/WebCore/html/canvas/WebGLBuffer.cpp
@@ -47,14 +47,18 @@ WebGLBuffer::WebGLBuffer(WebGLRenderingContext* ctx)
     , m_elementArrayBufferByteLength(0)
     , m_arrayBufferByteLength(0)
     , m_elementArrayBufferCloned(false)
+    , m_nextAvailableCacheEntry(0)
 {
     setObject(context()->graphicsContext3D()->createBuffer());
+    clearCachedMaxIndices();
 }
 
 WebGLBuffer::WebGLBuffer(WebGLRenderingContext* ctx, Platform3DObject obj)
     : CanvasObject(ctx)
+    , m_nextAvailableCacheEntry(0)
 {
     setObject(obj, false);
+    clearCachedMaxIndices();
 }
 
 void WebGLBuffer::_deleteObject(Platform3DObject object)
@@ -83,6 +87,7 @@ bool WebGLBuffer::associateBufferData(unsigned long target, WebGLArray* array)
         return false;
         
     if (target == GraphicsContext3D::ELEMENT_ARRAY_BUFFER) {
+        clearCachedMaxIndices();
         m_elementArrayBufferByteLength = array->byteLength();
         m_elementArrayBuffer = array->buffer();
         m_elementArrayBufferCloned = false;
@@ -103,6 +108,8 @@ bool WebGLBuffer::associateBufferSubData(unsigned long target, long offset, WebG
         return false;
         
     if (target == GraphicsContext3D::ELEMENT_ARRAY_BUFFER) {
+        clearCachedMaxIndices();
+
         // We need to protect against integer overflow with these tests
         if (offset < 0)
             return false;
@@ -132,6 +139,33 @@ unsigned WebGLBuffer::byteLength(unsigned long target) const
     return (target == GraphicsContext3D::ARRAY_BUFFER) ? m_arrayBufferByteLength : m_elementArrayBufferByteLength;
 }
 
+long WebGLBuffer::getCachedMaxIndex(unsigned long type)
+{
+    size_t numEntries = sizeof(m_maxIndexCache) / sizeof(MaxIndexCacheEntry);
+    for (size_t i = 0; i < numEntries; i++)
+        if (m_maxIndexCache[i].type == type)
+            return m_maxIndexCache[i].maxIndex;
+    return -1;
+}
+
+void WebGLBuffer::setCachedMaxIndex(unsigned long type, long value)
+{
+    int numEntries = sizeof(m_maxIndexCache) / sizeof(MaxIndexCacheEntry);
+    for (int i = 0; i < numEntries; i++)
+        if (m_maxIndexCache[i].type == type) {
+            m_maxIndexCache[i].maxIndex = value;
+            return;
+        }
+    m_maxIndexCache[m_nextAvailableCacheEntry].type = type;
+    m_maxIndexCache[m_nextAvailableCacheEntry].maxIndex = value;
+    m_nextAvailableCacheEntry = (m_nextAvailableCacheEntry + 1) % numEntries;
+}
+
+void WebGLBuffer::clearCachedMaxIndices()
+{
+    memset(m_maxIndexCache, 0, sizeof(m_maxIndexCache));
+}
+
 }
 
 #endif // ENABLE(3D_CANVAS)
diff --git a/WebCore/html/canvas/WebGLBuffer.h b/WebCore/html/canvas/WebGLBuffer.h
index cb953c6..4c3f04a 100644
--- a/WebCore/html/canvas/WebGLBuffer.h
+++ b/WebCore/html/canvas/WebGLBuffer.h
@@ -51,6 +51,12 @@ namespace WebCore {
         unsigned byteLength(unsigned long target) const;
         const WebGLArrayBuffer* elementArrayBuffer() const { return m_elementArrayBuffer.get(); }
                         
+        // Gets the cached max index for the given type. Returns -1 if
+        // none has been set.
+        long getCachedMaxIndex(unsigned long type);
+        // Sets the cached max index for the given type.
+        void setCachedMaxIndex(unsigned long type, long value);
+
     protected:
         WebGLBuffer(WebGLRenderingContext*);
         WebGLBuffer(WebGLRenderingContext*, Platform3DObject obj);
@@ -62,6 +68,26 @@ namespace WebCore {
         unsigned m_elementArrayBufferByteLength;
         unsigned m_arrayBufferByteLength;
         bool m_elementArrayBufferCloned;
+
+        // Optimization for index validation. For each type of index
+        // (i.e., UNSIGNED_SHORT), cache the maximum index in the
+        // entire buffer.
+        // 
+        // This is sufficient to eliminate a lot of work upon each
+        // draw call as long as all bound array buffers are at least
+        // that size.
+        struct MaxIndexCacheEntry {
+            unsigned long type;
+            long maxIndex;
+        };
+        // OpenGL ES 2.0 only has two valid index types (UNSIGNED_BYTE
+        // and UNSIGNED_SHORT), but might as well leave open the
+        // possibility of adding others.
+        MaxIndexCacheEntry m_maxIndexCache[4];
+        unsigned m_nextAvailableCacheEntry;
+
+        // Clears all of the cached max indices.
+        void clearCachedMaxIndices();
     };
     
 } // namespace WebCore
diff --git a/WebCore/html/canvas/WebGLRenderingContext.cpp b/WebCore/html/canvas/WebGLRenderingContext.cpp
index a8952c5..bb8e40a 100644
--- a/WebCore/html/canvas/WebGLRenderingContext.cpp
+++ b/WebCore/html/canvas/WebGLRenderingContext.cpp
@@ -574,31 +574,95 @@ void WebGLRenderingContext::disableVertexAttribArray(unsigned long index, Except
     cleanupAfterGraphicsCall(false);
 }
 
-bool WebGLRenderingContext::validateIndexArray(unsigned long count, unsigned long type, long offset, long& numElements)
+bool WebGLRenderingContext::validateElementArraySize(unsigned long count, unsigned long type, long offset)
 {
-    long lastIndex = -1;
     if (!m_boundElementArrayBuffer)
         return false;
-        
+
     if (offset < 0)
         return false;
-        
-    // The GL spec says that count must be "greater
-    
+
     unsigned long uoffset = static_cast<unsigned long>(offset);
-    
+
     if (type == GraphicsContext3D::UNSIGNED_SHORT) {
         // For an unsigned short array, offset must be divisible by 2 for alignment reasons.
         if (uoffset & 1)
             return false;
-        
+
         // Make uoffset an element offset.
         uoffset /= 2;
-    
+
         unsigned long n = m_boundElementArrayBuffer->byteLength(GraphicsContext3D::ELEMENT_ARRAY_BUFFER) / 2;
         if (uoffset > n || count > n - uoffset)
             return false;
-            
+    } else if (type == GraphicsContext3D::UNSIGNED_BYTE) {
+        unsigned long n = m_boundElementArrayBuffer->byteLength(GraphicsContext3D::ELEMENT_ARRAY_BUFFER);
+        if (uoffset > n || count > n - uoffset)
+            return false;
+    }
+    return true;
+}
+
+bool WebGLRenderingContext::validateIndexArrayConservative(unsigned long type, long& numElementsRequired)
+{
+    // Performs conservative validation by caching a maximum index of
+    // the given type per element array buffer. If all of the bound
+    // array buffers have enough elements to satisfy that maximum
+    // index, skips the expensive per-draw-call iteration in
+    // validateIndexArrayPrecise.
+
+    long maxIndex = m_boundElementArrayBuffer->getCachedMaxIndex(type);
+    if (maxIndex < 0) {
+        // Compute the maximum index in the entire buffer for the given type of index.
+        switch (type) {
+        case GraphicsContext3D::UNSIGNED_BYTE: {
+            unsigned numElements = m_boundElementArrayBuffer->byteLength(GraphicsContext3D::ELEMENT_ARRAY_BUFFER);
+            const unsigned char* p = static_cast<const unsigned char*>(m_boundElementArrayBuffer->elementArrayBuffer()->data());
+            for (unsigned i = 0; i < numElements; i++)
+                maxIndex = max(maxIndex, static_cast<long>(p[i]));
+            break;
+        }
+        case GraphicsContext3D::UNSIGNED_SHORT: {
+            unsigned numElements = m_boundElementArrayBuffer->byteLength(GraphicsContext3D::ELEMENT_ARRAY_BUFFER) / sizeof(unsigned short);
+            const unsigned short* p = static_cast<const unsigned short*>(m_boundElementArrayBuffer->elementArrayBuffer()->data());
+            for (unsigned i = 0; i < numElements; i++)
+                maxIndex = max(maxIndex, static_cast<long>(p[i]));
+            break;
+        }
+        default:
+            return false;
+        }
+        m_boundElementArrayBuffer->setCachedMaxIndex(type, maxIndex);
+    }
+
+    if (maxIndex >= 0) {
+        // The number of required elements is one more than the maximum
+        // index that will be accessed.
+        numElementsRequired = maxIndex + 1;
+        return true;
+    }
+
+    return false;
+}
+
+bool WebGLRenderingContext::validateIndexArrayPrecise(unsigned long count, unsigned long type, long offset, long& numElementsRequired)
+{
+    // FIXME: "count" should need to be used in the computation below
+    UNUSED_PARAM(count);
+    long lastIndex = -1;
+
+    if (!m_boundElementArrayBuffer)
+        return false;
+        
+    // The GL spec says that count must be "greater
+    
+    unsigned long uoffset = static_cast<unsigned long>(offset);
+    
+    if (type == GraphicsContext3D::UNSIGNED_SHORT) {
+        // Make uoffset an element offset.
+        uoffset /= 2;
+    
+        unsigned long n = m_boundElementArrayBuffer->byteLength(GraphicsContext3D::ELEMENT_ARRAY_BUFFER) / 2;
         const unsigned short* p = static_cast<const unsigned short*>(m_boundElementArrayBuffer->elementArrayBuffer()->data());
         while (n-- > 0) {
             if (*p > lastIndex)
@@ -607,9 +671,6 @@ bool WebGLRenderingContext::validateIndexArray(unsigned long count, unsigned lon
         }
     } else if (type == GraphicsContext3D::UNSIGNED_BYTE) {
         unsigned long n = m_boundElementArrayBuffer->byteLength(GraphicsContext3D::ELEMENT_ARRAY_BUFFER);
-        if (uoffset > n || count > n - uoffset)
-            return false;
-            
         const unsigned char* p = static_cast<const unsigned char*>(m_boundElementArrayBuffer->elementArrayBuffer()->data());
         while (n-- > 0) {
             if (*p > lastIndex)
@@ -619,11 +680,11 @@ bool WebGLRenderingContext::validateIndexArray(unsigned long count, unsigned lon
     }    
         
     // Then set the last index in the index array and make sure it is valid.
-    numElements = lastIndex + 1;
-    return numElements > 0;
+    numElementsRequired = lastIndex + 1;
+    return numElementsRequired > 0;
 }
 
-bool WebGLRenderingContext::validateRenderingState(long numElements)
+bool WebGLRenderingContext::validateRenderingState(long numElementsRequired)
 {
     // Look in each enabled vertex attrib and find the smallest buffer size
     long smallestNumElements = LONG_MAX;
@@ -636,7 +697,7 @@ bool WebGLRenderingContext::validateRenderingState(long numElements)
     if (smallestNumElements == LONG_MAX)
         smallestNumElements = 0;
     
-    return numElements <= smallestNumElements;
+    return numElementsRequired <= smallestNumElements;
 }
 
 void WebGLRenderingContext::drawArrays(unsigned long mode, long first, long count, ExceptionCode& ec)
@@ -658,10 +719,16 @@ void WebGLRenderingContext::drawElements(unsigned long mode, unsigned long count
     // Ensure we have a valid rendering state
     long numElements;
     
-    if (offset < 0 || !validateIndexArray(count, type, offset, numElements) || !validateRenderingState(numElements)) {
+    if (offset < 0 || !validateElementArraySize(count, type, offset)) {
         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
         return;
     }
+
+    if (!validateIndexArrayConservative(type, numElements) || !validateRenderingState(numElements))
+        if (!validateIndexArrayPrecise(count, type, offset, numElements) || !validateRenderingState(numElements)) {
+            m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
+            return;
+        }
     
     m_context->drawElements(mode, count, type, offset);
     cleanupAfterGraphicsCall(true);
diff --git a/WebCore/html/canvas/WebGLRenderingContext.h b/WebCore/html/canvas/WebGLRenderingContext.h
index 3335eba..dd54cc2 100644
--- a/WebCore/html/canvas/WebGLRenderingContext.h
+++ b/WebCore/html/canvas/WebGLRenderingContext.h
@@ -301,7 +301,14 @@ class WebKitCSSMatrix;
                 markContextChanged();
         }
         
-        bool validateIndexArray(unsigned long count, unsigned long type, long offset, long& numElements);
+        // Basic validation of count and offset against number of elements in element array buffer
+        bool validateElementArraySize(unsigned long count, unsigned long type, long offset);
+
+        // Conservative but quick index validation
+        bool validateIndexArrayConservative(unsigned long type, long& numElementsRequired);
+
+        // Precise but slow index validation -- only done if conservative checks fail
+        bool validateIndexArrayPrecise(unsigned long count, unsigned long type, long offset, long& numElementsRequired);
         bool validateRenderingState(long numElements);
 
         OwnPtr<GraphicsContext3D> m_context;

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list