mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Backout d2242d05c93c (bug 984783) for Cpp bustage
This commit is contained in:
parent
3104006a5d
commit
c0e1ac14d9
@ -174,7 +174,7 @@ int main(int argc, char *argv[])
|
||||
// us some comfort margin.
|
||||
int repeat = std::min(maxBufferSize, 64);
|
||||
for (int i = 0; i < repeat; i++) {
|
||||
size_t size = RandomInteger<size_t>(0, maxBufferSize);
|
||||
size_t size = RandomInteger<size_t>(1, maxBufferSize);
|
||||
MakeRandomVector(v, size);
|
||||
b.BufferData(v.Elements(), size);
|
||||
CheckValidate(b, 0, size);
|
||||
|
@ -124,13 +124,21 @@ UpdateUpperBound(uint32_t* out_upperBound, uint32_t newBound)
|
||||
* case where each element array buffer is only ever used with one type, this is also addressed
|
||||
* by having WebGLElementArrayCache lazily create trees for each type only upon first use.
|
||||
*
|
||||
* Another consequence of this constraint is that when updating the trees, we have to update
|
||||
* Another consequence of this constraint is that when invalidating the trees, we have to invalidate
|
||||
* all existing trees. So if trees for types uint8_t, uint16_t and uint32_t have ever been constructed for this buffer,
|
||||
* every subsequent update will have to update all trees even if one of the types is never
|
||||
* used again. That's inefficient, but content should not put indices of different types in the
|
||||
* same element array buffer anyways. Different index types can only be consumed in separate
|
||||
* drawElements calls, so nothing particular is to be achieved by lumping them in the same
|
||||
* buffer object.
|
||||
* every subsequent invalidation will have to invalidate all trees even if one of the types is never
|
||||
* used again. This implies that it is important to minimize the cost of invalidation i.e.
|
||||
* do lazy updates upon use as opposed to immediately updating invalidated trees. This poses a problem:
|
||||
* it is nontrivial to keep track of the part of the tree that's invalidated. The current solution
|
||||
* can only keep track of an invalidated interval, from |mFirstInvalidatedLeaf| to |mLastInvalidatedLeaf|.
|
||||
* The problem is that if one does two small, far-apart partial buffer updates, the resulting invalidated
|
||||
* area is very large even though only a small part of the array really needed to be invalidated.
|
||||
* The real solution to this problem would be to use a smarter data structure to keep track of the
|
||||
* invalidated area, probably an interval tree. Meanwhile, we can probably live with the current situation
|
||||
* as the unfavorable case seems to be a small corner case: in order to run into performance issues,
|
||||
* the number of bufferSubData in between two consecutive draws must be small but greater than 1, and
|
||||
* the partial buffer updates must be small and far apart. Anything else than this corner case
|
||||
* should run fast in the current setting.
|
||||
*/
|
||||
template<typename T>
|
||||
struct WebGLElementArrayCacheTree
|
||||
@ -146,20 +154,23 @@ private:
|
||||
WebGLElementArrayCache& mParent;
|
||||
FallibleTArray<T> mTreeData;
|
||||
size_t mNumLeaves;
|
||||
size_t mParentByteSize;
|
||||
bool mInvalidated;
|
||||
size_t mFirstInvalidatedLeaf;
|
||||
size_t mLastInvalidatedLeaf;
|
||||
|
||||
public:
|
||||
WebGLElementArrayCacheTree(WebGLElementArrayCache& p)
|
||||
: mParent(p)
|
||||
, mNumLeaves(0)
|
||||
, mParentByteSize(0)
|
||||
, mInvalidated(false)
|
||||
, mFirstInvalidatedLeaf(0)
|
||||
, mLastInvalidatedLeaf(0)
|
||||
{
|
||||
if (mParent.ByteSize()) {
|
||||
Update(0, mParent.ByteSize() - 1);
|
||||
}
|
||||
ResizeToParentSize();
|
||||
}
|
||||
|
||||
T GlobalMaximum() const {
|
||||
MOZ_ASSERT(!mInvalidated);
|
||||
return mTreeData[1];
|
||||
}
|
||||
|
||||
@ -231,13 +242,14 @@ public:
|
||||
}
|
||||
|
||||
static size_t NextMultipleOfElementsPerLeaf(size_t numElements) {
|
||||
MOZ_ASSERT(numElements >= 1);
|
||||
return ((numElements - 1) | sElementsPerLeafMask) + 1;
|
||||
}
|
||||
|
||||
bool Validate(T maxAllowed, size_t firstLeaf, size_t lastLeaf,
|
||||
uint32_t* out_upperBound)
|
||||
{
|
||||
MOZ_ASSERT(!mInvalidated);
|
||||
|
||||
size_t firstTreeIndex = TreeIndexForLeaf(firstLeaf);
|
||||
size_t lastTreeIndex = TreeIndexForLeaf(lastLeaf);
|
||||
|
||||
@ -298,7 +310,28 @@ public:
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Update(size_t firstByte, size_t lastByte);
|
||||
bool ResizeToParentSize()
|
||||
{
|
||||
size_t numberOfElements = mParent.ByteSize() / sizeof(T);
|
||||
size_t requiredNumLeaves = (numberOfElements + sElementsPerLeaf - 1) / sElementsPerLeaf;
|
||||
|
||||
size_t oldNumLeaves = mNumLeaves;
|
||||
mNumLeaves = NextPowerOfTwo(requiredNumLeaves);
|
||||
Invalidate(0, mParent.ByteSize() - 1);
|
||||
|
||||
// see class comment for why we the tree storage size is 2 * mNumLeaves
|
||||
if (!mTreeData.SetLength(2 * mNumLeaves)) {
|
||||
return false;
|
||||
}
|
||||
if (mNumLeaves != oldNumLeaves) {
|
||||
memset(mTreeData.Elements(), 0, mTreeData.Length() * sizeof(mTreeData[0]));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Invalidate(size_t firstByte, size_t lastByte);
|
||||
|
||||
void Update();
|
||||
|
||||
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
|
||||
{
|
||||
@ -329,48 +362,44 @@ struct TreeForType<uint32_t>
|
||||
static WebGLElementArrayCacheTree<uint32_t>*& Run(WebGLElementArrayCache *b) { return b->mUint32Tree; }
|
||||
};
|
||||
|
||||
// Calling this method will 1) update the leaves in this interval
|
||||
// from the raw buffer data, and 2) propagate this update up the tree
|
||||
// When the buffer gets updated from firstByte to lastByte,
|
||||
// calling this method will notify the tree accordingly
|
||||
template<typename T>
|
||||
bool WebGLElementArrayCacheTree<T>::Update(size_t firstByte, size_t lastByte)
|
||||
void WebGLElementArrayCacheTree<T>::Invalidate(size_t firstByte, size_t lastByte)
|
||||
{
|
||||
MOZ_ASSERT(firstByte <= lastByte);
|
||||
MOZ_ASSERT(lastByte < mParent.ByteSize());
|
||||
|
||||
// Step #0: if needed, resize our tree data storage.
|
||||
if (mParentByteSize != mParent.ByteSize())
|
||||
{
|
||||
mParentByteSize = mParent.ByteSize();
|
||||
|
||||
size_t numberOfElements = mParent.ByteSize() / sizeof(T);
|
||||
if (numberOfElements == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t requiredNumLeaves = (numberOfElements + sElementsPerLeaf - 1) / sElementsPerLeaf;
|
||||
size_t oldNumLeaves = mNumLeaves;
|
||||
mNumLeaves = NextPowerOfTwo(requiredNumLeaves);
|
||||
if (mNumLeaves != oldNumLeaves) {
|
||||
// see class comment for why we the tree storage size is 2 * mNumLeaves
|
||||
if (!mTreeData.SetLength(2 * mNumLeaves)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
lastByte = std::min(lastByte, mNumLeaves * sElementsPerLeaf * sizeof(T) - 1);
|
||||
if (firstByte > lastByte) {
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
|
||||
size_t firstLeaf = LeafForByte(firstByte);
|
||||
size_t lastLeaf = LeafForByte(lastByte);
|
||||
|
||||
MOZ_ASSERT(firstLeaf <= lastLeaf && lastLeaf < mNumLeaves);
|
||||
if (mInvalidated) {
|
||||
mFirstInvalidatedLeaf = std::min(firstLeaf, mFirstInvalidatedLeaf);
|
||||
mLastInvalidatedLeaf = std::max(lastLeaf, mLastInvalidatedLeaf);
|
||||
} else {
|
||||
mInvalidated = true;
|
||||
mFirstInvalidatedLeaf = firstLeaf;
|
||||
mLastInvalidatedLeaf = lastLeaf;
|
||||
}
|
||||
}
|
||||
|
||||
size_t firstTreeIndex = TreeIndexForLeaf(firstLeaf);
|
||||
size_t lastTreeIndex = TreeIndexForLeaf(lastLeaf);
|
||||
|
||||
// When tree has been partially invalidated, from mFirstInvalidatedLeaf to
|
||||
// mLastInvalidatedLeaf, calling this method will 1) update the leaves in this interval
|
||||
// from the raw buffer data, and 2) propagate this update up the tree
|
||||
template<typename T>
|
||||
void WebGLElementArrayCacheTree<T>::Update()
|
||||
{
|
||||
if (!mInvalidated) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mLastInvalidatedLeaf < mNumLeaves);
|
||||
|
||||
size_t firstTreeIndex = TreeIndexForLeaf(mFirstInvalidatedLeaf);
|
||||
size_t lastTreeIndex = TreeIndexForLeaf(mLastInvalidatedLeaf);
|
||||
|
||||
// Step #1: initialize the tree leaves from plain buffer data.
|
||||
// That is, each tree leaf must be set to the max of the |sElementsPerLeaf| corresponding
|
||||
@ -380,8 +409,8 @@ bool WebGLElementArrayCacheTree<T>::Update(size_t firstByte, size_t lastByte)
|
||||
// treeIndex is the index of the tree leaf we're writing, i.e. the destination index
|
||||
size_t treeIndex = firstTreeIndex;
|
||||
// srcIndex is the index in the source buffer
|
||||
size_t srcIndex = firstLeaf * sElementsPerLeaf;
|
||||
size_t numberOfElements = mParentByteSize / sizeof(T);
|
||||
size_t srcIndex = mFirstInvalidatedLeaf * sElementsPerLeaf;
|
||||
size_t numberOfElements = mParent.ByteSize() / sizeof(T);
|
||||
while (treeIndex <= lastTreeIndex) {
|
||||
T m = 0;
|
||||
size_t a = srcIndex;
|
||||
@ -402,7 +431,7 @@ bool WebGLElementArrayCacheTree<T>::Update(size_t firstByte, size_t lastByte)
|
||||
firstTreeIndex = ParentNode(firstTreeIndex);
|
||||
lastTreeIndex = ParentNode(lastTreeIndex);
|
||||
|
||||
// fast-exit case where only one node is updated at the current level
|
||||
// fast-exit case where only one node is invalidated at the current level
|
||||
if (firstTreeIndex == lastTreeIndex) {
|
||||
mTreeData[firstTreeIndex] = std::max(mTreeData[LeftChildNode(firstTreeIndex)], mTreeData[RightChildNode(firstTreeIndex)]);
|
||||
continue;
|
||||
@ -439,7 +468,7 @@ bool WebGLElementArrayCacheTree<T>::Update(size_t firstByte, size_t lastByte)
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
mInvalidated = false;
|
||||
}
|
||||
|
||||
WebGLElementArrayCache::~WebGLElementArrayCache() {
|
||||
@ -450,35 +479,40 @@ WebGLElementArrayCache::~WebGLElementArrayCache() {
|
||||
}
|
||||
|
||||
bool WebGLElementArrayCache::BufferData(const void* ptr, size_t byteSize) {
|
||||
void* newUntypedData = realloc(mUntypedData, byteSize);
|
||||
if (!newUntypedData)
|
||||
return false;
|
||||
mByteSize = byteSize;
|
||||
mUntypedData = newUntypedData;
|
||||
|
||||
if (mUint8Tree)
|
||||
if (!mUint8Tree->ResizeToParentSize())
|
||||
return false;
|
||||
if (mUint16Tree)
|
||||
if (!mUint16Tree->ResizeToParentSize())
|
||||
return false;
|
||||
if (mUint32Tree)
|
||||
if (!mUint32Tree->ResizeToParentSize())
|
||||
return false;
|
||||
mUntypedData = realloc(mUntypedData, byteSize);
|
||||
if (!mUntypedData)
|
||||
return false;
|
||||
BufferSubData(0, ptr, byteSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WebGLElementArrayCache::BufferSubData(size_t pos, const void* ptr, size_t updateByteSize) {
|
||||
if (!updateByteSize) return true;
|
||||
void WebGLElementArrayCache::BufferSubData(size_t pos, const void* ptr, size_t updateByteSize) {
|
||||
if (!updateByteSize) return;
|
||||
if (ptr)
|
||||
memcpy(static_cast<uint8_t*>(mUntypedData) + pos, ptr, updateByteSize);
|
||||
else
|
||||
memset(static_cast<uint8_t*>(mUntypedData) + pos, 0, updateByteSize);
|
||||
return UpdateTrees(pos, pos + updateByteSize - 1);
|
||||
InvalidateTrees(pos, pos + updateByteSize - 1);
|
||||
}
|
||||
|
||||
bool WebGLElementArrayCache::UpdateTrees(size_t firstByte, size_t lastByte)
|
||||
void WebGLElementArrayCache::InvalidateTrees(size_t firstByte, size_t lastByte)
|
||||
{
|
||||
bool result = true;
|
||||
if (mUint8Tree)
|
||||
result &= mUint8Tree->Update(firstByte, lastByte);
|
||||
mUint8Tree->Invalidate(firstByte, lastByte);
|
||||
if (mUint16Tree)
|
||||
result &= mUint16Tree->Update(firstByte, lastByte);
|
||||
mUint16Tree->Invalidate(firstByte, lastByte);
|
||||
if (mUint32Tree)
|
||||
result &= mUint32Tree->Update(firstByte, lastByte);
|
||||
return result;
|
||||
mUint32Tree->Invalidate(firstByte, lastByte);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
@ -511,6 +545,8 @@ WebGLElementArrayCache::Validate(uint32_t maxAllowed, size_t firstElement,
|
||||
|
||||
size_t lastElement = firstElement + countElements - 1;
|
||||
|
||||
tree->Update();
|
||||
|
||||
// fast exit path when the global maximum for the whole element array buffer
|
||||
// falls in the allowed range
|
||||
T globalMax = tree->GlobalMaximum();
|
||||
|
@ -31,7 +31,7 @@ class WebGLElementArrayCache {
|
||||
|
||||
public:
|
||||
bool BufferData(const void* ptr, size_t byteSize);
|
||||
bool BufferSubData(size_t pos, const void* ptr, size_t updateByteSize);
|
||||
void BufferSubData(size_t pos, const void* ptr, size_t updateByteSize);
|
||||
|
||||
bool Validate(GLenum type, uint32_t maxAllowed, size_t first, size_t count,
|
||||
uint32_t* out_upperBound = nullptr);
|
||||
@ -66,7 +66,7 @@ private:
|
||||
template<typename T>
|
||||
T* Elements() { return static_cast<T*>(mUntypedData); }
|
||||
|
||||
bool UpdateTrees(size_t firstByte, size_t lastByte);
|
||||
void InvalidateTrees(size_t firstByte, size_t lastByte);
|
||||
|
||||
template<typename T>
|
||||
friend struct WebGLElementArrayCacheTree;
|
||||
|
Loading…
Reference in New Issue
Block a user