Changeset 52205 in webkit
- Timestamp:
- Dec 16, 2009 10:50:55 AM (14 years ago)
- Location:
- trunk/WebCore
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/WebCore/ChangeLog
r52204 r52205 1 2009-12-16 Kenneth Russell <kbr@google.com> 2 3 Reviewed by Darin Fisher. 4 5 Performance problems with index validation code for drawElements 6 https://bugs.webkit.org/show_bug.cgi?id=32466 7 8 Added a cache of the maximum index for each element type to 9 WebGLBuffer, querying it before iterating through the indices in 10 the client-side copy of the buffer's data. Hoisted checks of the 11 size of the element array itself into validateElementArraySize to 12 avoid duplicating code. 13 14 The performance improvement has been measured with manual tests. 15 Existing layout tests cover the index validation functionality 16 and continue to pass as before. 17 18 * html/canvas/WebGLBuffer.cpp: 19 (WebCore::WebGLBuffer::WebGLBuffer): 20 (WebCore::WebGLBuffer::associateBufferData): 21 (WebCore::WebGLBuffer::associateBufferSubData): 22 (WebCore::WebGLBuffer::getCachedMaxIndex): 23 (WebCore::WebGLBuffer::setCachedMaxIndex): 24 (WebCore::WebGLBuffer::clearCachedMaxIndices): 25 * html/canvas/WebGLBuffer.h: 26 * html/canvas/WebGLRenderingContext.cpp: 27 (WebCore::WebGLRenderingContext::validateElementArraySize): 28 (WebCore::WebGLRenderingContext::validateIndexArrayConservative): 29 (WebCore::WebGLRenderingContext::validateIndexArrayPrecise): 30 (WebCore::WebGLRenderingContext::validateRenderingState): 31 (WebCore::WebGLRenderingContext::drawElements): 32 * html/canvas/WebGLRenderingContext.h: 33 1 34 2009-12-16 Zelidrag Hornung <zelidrag@chromium.org> 2 35 -
trunk/WebCore/html/canvas/WebGLBuffer.cpp
r51348 r52205 48 48 , m_arrayBufferByteLength(0) 49 49 , m_elementArrayBufferCloned(false) 50 , m_nextAvailableCacheEntry(0) 50 51 { 51 52 setObject(context()->graphicsContext3D()->createBuffer()); 53 clearCachedMaxIndices(); 52 54 } 53 55 54 56 WebGLBuffer::WebGLBuffer(WebGLRenderingContext* ctx, Platform3DObject obj) 55 57 : CanvasObject(ctx) 58 , m_nextAvailableCacheEntry(0) 56 59 { 57 60 setObject(obj, false); 61 clearCachedMaxIndices(); 58 62 } 59 63 … … 84 88 85 89 if (target == GraphicsContext3D::ELEMENT_ARRAY_BUFFER) { 90 clearCachedMaxIndices(); 86 91 m_elementArrayBufferByteLength = array->byteLength(); 87 92 m_elementArrayBuffer = array->buffer(); … … 104 109 105 110 if (target == GraphicsContext3D::ELEMENT_ARRAY_BUFFER) { 111 clearCachedMaxIndices(); 112 106 113 // We need to protect against integer overflow with these tests 107 114 if (offset < 0) … … 133 140 } 134 141 142 long WebGLBuffer::getCachedMaxIndex(unsigned long type) 143 { 144 size_t numEntries = sizeof(m_maxIndexCache) / sizeof(MaxIndexCacheEntry); 145 for (size_t i = 0; i < numEntries; i++) 146 if (m_maxIndexCache[i].type == type) 147 return m_maxIndexCache[i].maxIndex; 148 return -1; 149 } 150 151 void WebGLBuffer::setCachedMaxIndex(unsigned long type, long value) 152 { 153 int numEntries = sizeof(m_maxIndexCache) / sizeof(MaxIndexCacheEntry); 154 for (int i = 0; i < numEntries; i++) 155 if (m_maxIndexCache[i].type == type) { 156 m_maxIndexCache[i].maxIndex = value; 157 return; 158 } 159 m_maxIndexCache[m_nextAvailableCacheEntry].type = type; 160 m_maxIndexCache[m_nextAvailableCacheEntry].maxIndex = value; 161 m_nextAvailableCacheEntry = (m_nextAvailableCacheEntry + 1) % numEntries; 162 } 163 164 void WebGLBuffer::clearCachedMaxIndices() 165 { 166 memset(m_maxIndexCache, 0, sizeof(m_maxIndexCache)); 167 } 168 135 169 } 136 170 -
trunk/WebCore/html/canvas/WebGLBuffer.h
r51348 r52205 52 52 const WebGLArrayBuffer* elementArrayBuffer() const { return m_elementArrayBuffer.get(); } 53 53 54 // Gets the cached max index for the given type. Returns -1 if 55 // none has been set. 56 long getCachedMaxIndex(unsigned long type); 57 // Sets the cached max index for the given type. 58 void setCachedMaxIndex(unsigned long type, long value); 59 54 60 protected: 55 61 WebGLBuffer(WebGLRenderingContext*); … … 63 69 unsigned m_arrayBufferByteLength; 64 70 bool m_elementArrayBufferCloned; 71 72 // Optimization for index validation. For each type of index 73 // (i.e., UNSIGNED_SHORT), cache the maximum index in the 74 // entire buffer. 75 // 76 // This is sufficient to eliminate a lot of work upon each 77 // draw call as long as all bound array buffers are at least 78 // that size. 79 struct MaxIndexCacheEntry { 80 unsigned long type; 81 long maxIndex; 82 }; 83 // OpenGL ES 2.0 only has two valid index types (UNSIGNED_BYTE 84 // and UNSIGNED_SHORT), but might as well leave open the 85 // possibility of adding others. 86 MaxIndexCacheEntry m_maxIndexCache[4]; 87 unsigned m_nextAvailableCacheEntry; 88 89 // Clears all of the cached max indices. 90 void clearCachedMaxIndices(); 65 91 }; 66 92 -
trunk/WebCore/html/canvas/WebGLRenderingContext.cpp
r52164 r52205 575 575 } 576 576 577 bool WebGLRenderingContext::validateIndexArray(unsigned long count, unsigned long type, long offset, long& numElements) 578 { 579 long lastIndex = -1; 577 bool WebGLRenderingContext::validateElementArraySize(unsigned long count, unsigned long type, long offset) 578 { 580 579 if (!m_boundElementArrayBuffer) 581 580 return false; 582 581 583 582 if (offset < 0) 584 583 return false; 585 586 // The GL spec says that count must be "greater 587 584 588 585 unsigned long uoffset = static_cast<unsigned long>(offset); 589 586 590 587 if (type == GraphicsContext3D::UNSIGNED_SHORT) { 591 588 // For an unsigned short array, offset must be divisible by 2 for alignment reasons. 592 589 if (uoffset & 1) 593 590 return false; 594 591 595 592 // Make uoffset an element offset. 596 593 uoffset /= 2; 597 594 598 595 unsigned long n = m_boundElementArrayBuffer->byteLength(GraphicsContext3D::ELEMENT_ARRAY_BUFFER) / 2; 599 596 if (uoffset > n || count > n - uoffset) 600 597 return false; 601 598 } else if (type == GraphicsContext3D::UNSIGNED_BYTE) { 599 unsigned long n = m_boundElementArrayBuffer->byteLength(GraphicsContext3D::ELEMENT_ARRAY_BUFFER); 600 if (uoffset > n || count > n - uoffset) 601 return false; 602 } 603 return true; 604 } 605 606 bool WebGLRenderingContext::validateIndexArrayConservative(unsigned long type, long& numElementsRequired) 607 { 608 // Performs conservative validation by caching a maximum index of 609 // the given type per element array buffer. If all of the bound 610 // array buffers have enough elements to satisfy that maximum 611 // index, skips the expensive per-draw-call iteration in 612 // validateIndexArrayPrecise. 613 614 long maxIndex = m_boundElementArrayBuffer->getCachedMaxIndex(type); 615 if (maxIndex < 0) { 616 // Compute the maximum index in the entire buffer for the given type of index. 617 switch (type) { 618 case GraphicsContext3D::UNSIGNED_BYTE: { 619 unsigned numElements = m_boundElementArrayBuffer->byteLength(GraphicsContext3D::ELEMENT_ARRAY_BUFFER); 620 const unsigned char* p = static_cast<const unsigned char*>(m_boundElementArrayBuffer->elementArrayBuffer()->data()); 621 for (unsigned i = 0; i < numElements; i++) 622 maxIndex = max(maxIndex, static_cast<long>(p[i])); 623 break; 624 } 625 case GraphicsContext3D::UNSIGNED_SHORT: { 626 unsigned numElements = m_boundElementArrayBuffer->byteLength(GraphicsContext3D::ELEMENT_ARRAY_BUFFER) / sizeof(unsigned short); 627 const unsigned short* p = static_cast<const unsigned short*>(m_boundElementArrayBuffer->elementArrayBuffer()->data()); 628 for (unsigned i = 0; i < numElements; i++) 629 maxIndex = max(maxIndex, static_cast<long>(p[i])); 630 break; 631 } 632 default: 633 return false; 634 } 635 m_boundElementArrayBuffer->setCachedMaxIndex(type, maxIndex); 636 } 637 638 if (maxIndex >= 0) { 639 // The number of required elements is one more than the maximum 640 // index that will be accessed. 641 numElementsRequired = maxIndex + 1; 642 return true; 643 } 644 645 return false; 646 } 647 648 bool WebGLRenderingContext::validateIndexArrayPrecise(unsigned long count, unsigned long type, long offset, long& numElementsRequired) 649 { 650 // FIXME: "count" should need to be used in the computation below 651 UNUSED_PARAM(count); 652 long lastIndex = -1; 653 654 if (!m_boundElementArrayBuffer) 655 return false; 656 657 // The GL spec says that count must be "greater 658 659 unsigned long uoffset = static_cast<unsigned long>(offset); 660 661 if (type == GraphicsContext3D::UNSIGNED_SHORT) { 662 // Make uoffset an element offset. 663 uoffset /= 2; 664 665 unsigned long n = m_boundElementArrayBuffer->byteLength(GraphicsContext3D::ELEMENT_ARRAY_BUFFER) / 2; 602 666 const unsigned short* p = static_cast<const unsigned short*>(m_boundElementArrayBuffer->elementArrayBuffer()->data()); 603 667 while (n-- > 0) { … … 608 672 } else if (type == GraphicsContext3D::UNSIGNED_BYTE) { 609 673 unsigned long n = m_boundElementArrayBuffer->byteLength(GraphicsContext3D::ELEMENT_ARRAY_BUFFER); 610 if (uoffset > n || count > n - uoffset)611 return false;612 613 674 const unsigned char* p = static_cast<const unsigned char*>(m_boundElementArrayBuffer->elementArrayBuffer()->data()); 614 675 while (n-- > 0) { … … 620 681 621 682 // Then set the last index in the index array and make sure it is valid. 622 numElements = lastIndex + 1;623 return numElements > 0;624 } 625 626 bool WebGLRenderingContext::validateRenderingState(long numElements )683 numElementsRequired = lastIndex + 1; 684 return numElementsRequired > 0; 685 } 686 687 bool WebGLRenderingContext::validateRenderingState(long numElementsRequired) 627 688 { 628 689 // Look in each enabled vertex attrib and find the smallest buffer size … … 637 698 smallestNumElements = 0; 638 699 639 return numElements <= smallestNumElements;700 return numElementsRequired <= smallestNumElements; 640 701 } 641 702 … … 659 720 long numElements; 660 721 661 if (offset < 0 || !validateIndexArray(count, type, offset, numElements) || !validateRenderingState(numElements)) { 662 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 663 return; 664 } 722 if (offset < 0 || !validateElementArraySize(count, type, offset)) { 723 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 724 return; 725 } 726 727 if (!validateIndexArrayConservative(type, numElements) || !validateRenderingState(numElements)) 728 if (!validateIndexArrayPrecise(count, type, offset, numElements) || !validateRenderingState(numElements)) { 729 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 730 return; 731 } 665 732 666 733 m_context->drawElements(mode, count, type, offset); -
trunk/WebCore/html/canvas/WebGLRenderingContext.h
r51970 r52205 302 302 } 303 303 304 bool validateIndexArray(unsigned long count, unsigned long type, long offset, long& numElements); 304 // Basic validation of count and offset against number of elements in element array buffer 305 bool validateElementArraySize(unsigned long count, unsigned long type, long offset); 306 307 // Conservative but quick index validation 308 bool validateIndexArrayConservative(unsigned long type, long& numElementsRequired); 309 310 // Precise but slow index validation -- only done if conservative checks fail 311 bool validateIndexArrayPrecise(unsigned long count, unsigned long type, long offset, long& numElementsRequired); 305 312 bool validateRenderingState(long numElements); 306 313
Note: See TracChangeset
for help on using the changeset viewer.