aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gyp/gpu.gypi2
-rw-r--r--src/gpu/gl/GrGLGpu.cpp4
-rw-r--r--src/gpu/gl/GrGLNameAllocator.cpp370
-rw-r--r--src/gpu/gl/GrGLNameAllocator.h86
-rw-r--r--src/gpu/gl/GrGLPathRendering.cpp97
-rw-r--r--src/gpu/gl/GrGLPathRendering.h3
-rw-r--r--tests/NameAllocatorTest.cpp169
7 files changed, 59 insertions, 672 deletions
diff --git a/gyp/gpu.gypi b/gyp/gpu.gypi
index 44c1d1a7c3..a637e8ee5a 100644
--- a/gyp/gpu.gypi
+++ b/gyp/gpu.gypi
@@ -326,8 +326,6 @@
'<(skia_src_path)/gpu/gl/GrGLIndexBuffer.h',
'<(skia_src_path)/gpu/gl/GrGLInterface.cpp',
'<(skia_src_path)/gpu/gl/GrGLIRect.h',
- '<(skia_src_path)/gpu/gl/GrGLNameAllocator.cpp',
- '<(skia_src_path)/gpu/gl/GrGLNameAllocator.h',
'<(skia_src_path)/gpu/gl/GrGLNoOpInterface.cpp',
'<(skia_src_path)/gpu/gl/GrGLNoOpInterface.h',
'<(skia_src_path)/gpu/gl/GrGLPath.cpp',
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index 972049aa56..9b03a2e23d 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -227,6 +227,10 @@ GrGLGpu::GrGLGpu(GrGLContext* ctx, GrContext* context)
}
GrGLGpu::~GrGLGpu() {
+ // Delete the path rendering explicitly, since it will need working gpu object to release the
+ // resources the object itself holds.
+ fPathRendering.reset();
+
if (0 != fHWProgramID) {
// detach the current program so there is no confusion on OpenGL's part
// that we want it to be deleted
diff --git a/src/gpu/gl/GrGLNameAllocator.cpp b/src/gpu/gl/GrGLNameAllocator.cpp
deleted file mode 100644
index 03123a6d86..0000000000
--- a/src/gpu/gl/GrGLNameAllocator.cpp
+++ /dev/null
@@ -1,370 +0,0 @@
-
-/*
- * Copyright 2014 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "GrGLNameAllocator.h"
-
-/**
- * This is the abstract base class for a nonempty AVL tree that tracks allocated
- * names within the half-open range [fFirst, fEnd). The inner nodes can be
- * sparse (meaning not every name within the range is necessarily allocated),
- * but the bounds are tight, so fFirst *is* guaranteed to be allocated, and so
- * is fEnd - 1.
- */
-class GrGLNameAllocator::SparseNameRange : public SkRefCnt {
-public:
- virtual ~SparseNameRange() {}
-
- /**
- * Return the beginning of the range. first() is guaranteed to be allocated.
- *
- * @return The first name in the range.
- */
- GrGLuint first() const { return fFirst; }
-
- /**
- * Return the end of the range. end() - 1 is guaranteed to be allocated.
- *
- * @return One plus the final name in the range.
- */
- GrGLuint end() const { return fEnd; }
-
- /**
- * Return the height of the tree. This can only be nonzero at an inner node.
- *
- * @return 0 if the implementation is a leaf node,
- * The nonzero height of the tree otherwise.
- */
- GrGLuint height() const { return fHeight; }
-
- /**
- * Allocate a name from strictly inside this range. The call will fail if
- * there is not a free name within.
- *
- * @param outName A pointer that receives the allocated name. outName will
- * be set to zero if there were no free names within the
- * range [fFirst, fEnd).
- * @return The resulting SparseNameRange after the allocation. Note that
- * this call is destructive, so the original SparseNameRange will no
- * longer be valid afterward. The caller must always update its
- * pointer with the new SparseNameRange.
- */
- virtual SparseNameRange* SK_WARN_UNUSED_RESULT internalAllocate(GrGLuint* outName) = 0;
-
- /**
- * Remove the leftmost leaf node from this range (or the entire thing if it
- * *is* a leaf node). This is an internal helper method that is used after
- * an allocation if one contiguous range became adjacent to another. (The
- * range gets removed so the one immediately before can be extended,
- * collapsing the two into one.)
- *
- * @param removedCount A pointer that receives the size of the contiguous
- range that was removed.
- * @return The resulting SparseNameRange after the removal (or nullptr if it
- * became empty). Note that this call is destructive, so the
- * original SparseNameRange will no longer be valid afterward. The
- * caller must always update its pointer with the new
- * SparseNameRange.
- */
- virtual SparseNameRange* SK_WARN_UNUSED_RESULT removeLeftmostContiguousRange(GrGLuint* removedCount) = 0;
-
- /**
- * Append adjacent allocated names to the end of this range. This operation
- * does not affect the structure of the tree. The caller is responsible for
- * ensuring the new names won't overlap sibling ranges, if any.
- *
- * @param count The number of adjacent names to append.
- * @return The first name appended.
- */
- virtual GrGLuint appendNames(GrGLuint count) = 0;
-
- /**
- * Prepend adjacent allocated names behind the beginning of this range. This
- * operation does not affect the structure of the tree. The caller is
- * responsible for ensuring the new names won't overlap sibling ranges, if
- * any.
- *
- * @param count The number of adjacent names to prepend.
- * @return The final name prepended (the one with the lowest value).
- */
- virtual GrGLuint prependNames(GrGLuint count) = 0;
-
- /**
- * Free a name so it is no longer tracked as allocated. If the name is at
- * the very beginning or very end of the range, the boundaries [fFirst, fEnd)
- * will be tightened.
- *
- * @param name The name to free. Not-allocated names are silently ignored
- * the same way they are in the OpenGL spec.
- * @return The resulting SparseNameRange after the free (or nullptr if it
- * became empty). Note that this call is destructive, so the
- * original SparseNameRange will no longer be valid afterward. The
- * caller must always update its pointer with the new
- * SparseNameRange.
- */
- virtual SparseNameRange* SK_WARN_UNUSED_RESULT free(GrGLuint name) = 0;
-
-protected:
- SparseNameRange* takeRef() {
- this->ref();
- return this;
- }
-
- GrGLuint fFirst;
- GrGLuint fEnd;
- GrGLuint fHeight;
-};
-
-/**
- * This class is the SparseNameRange implementation for an inner node. It is an
- * AVL tree with non-null, non-adjacent left and right children.
- */
-class GrGLNameAllocator::SparseNameTree : public SparseNameRange {
-public:
- SparseNameTree(SparseNameRange* left, SparseNameRange* right)
- : fLeft(left),
- fRight(right) {
- SkASSERT(fLeft.get());
- SkASSERT(fRight.get());
- this->updateStats();
- }
-
- SparseNameRange* SK_WARN_UNUSED_RESULT internalAllocate(GrGLuint* outName) override {
- // Try allocating the range inside fLeft's internal gaps.
- fLeft.reset(fLeft->internalAllocate(outName));
- if (0 != *outName) {
- this->updateStats();
- return this->rebalance();
- }
-
- if (fLeft->end() + 1 == fRight->first()) {
- // It closed the gap between fLeft and fRight; merge.
- GrGLuint removedCount;
- fRight.reset(fRight->removeLeftmostContiguousRange(&removedCount));
- *outName = fLeft->appendNames(1 + removedCount);
- if (nullptr == fRight.get()) {
- return fLeft.detach();
- }
- this->updateStats();
- return this->rebalance();
- }
-
- // There is guaranteed to be a gap between fLeft and fRight, and the
- // "size 1" case has already been covered.
- SkASSERT(fLeft->end() + 1 < fRight->first());
- *outName = fLeft->appendNames(1);
- return this->takeRef();
- }
-
- SparseNameRange* SK_WARN_UNUSED_RESULT removeLeftmostContiguousRange(GrGLuint* removedCount) override {
- fLeft.reset(fLeft->removeLeftmostContiguousRange(removedCount));
- if (nullptr == fLeft) {
- return fRight.detach();
- }
- this->updateStats();
- return this->rebalance();
- }
-
- GrGLuint appendNames(GrGLuint count) override {
- SkASSERT(fEnd + count > fEnd); // Check for integer wrap.
- GrGLuint name = fRight->appendNames(count);
- SkASSERT(fRight->end() == fEnd + count);
- this->updateStats();
- return name;
- }
-
- GrGLuint prependNames(GrGLuint count) override {
- SkASSERT(fFirst > count); // We can't allocate at or below 0.
- GrGLuint name = fLeft->prependNames(count);
- SkASSERT(fLeft->first() == fFirst - count);
- this->updateStats();
- return name;
- }
-
- SparseNameRange* SK_WARN_UNUSED_RESULT free(GrGLuint name) override {
- if (name < fLeft->end()) {
- fLeft.reset(fLeft->free(name));
- if (nullptr == fLeft) {
- // fLeft became empty after the free.
- return fRight.detach();
- }
- this->updateStats();
- return this->rebalance();
- } else {
- fRight.reset(fRight->free(name));
- if (nullptr == fRight) {
- // fRight became empty after the free.
- return fLeft.detach();
- }
- this->updateStats();
- return this->rebalance();
- }
- }
-
-private:
- typedef SkAutoTUnref<SparseNameRange> SparseNameTree::* ChildRange;
-
- SparseNameRange* SK_WARN_UNUSED_RESULT rebalance() {
- if (fLeft->height() > fRight->height() + 1) {
- return this->rebalanceImpl<&SparseNameTree::fLeft, &SparseNameTree::fRight>();
- }
- if (fRight->height() > fLeft->height() + 1) {
- return this->rebalanceImpl<&SparseNameTree::fRight, &SparseNameTree::fLeft>();
- }
- return this->takeRef();
- }
-
- /**
- * Rebalance the tree using rotations, as described in the AVL algorithm:
- * http://en.wikipedia.org/wiki/AVL_tree#Insertion
- */
- template<ChildRange Tall, ChildRange Short>
- SparseNameRange* SK_WARN_UNUSED_RESULT rebalanceImpl() {
- // We should be calling rebalance() enough that the tree never gets more
- // than one rotation off balance.
- SkASSERT(2 == (this->*Tall)->height() - (this->*Short)->height());
-
- // Ensure we are in the 'Left Left' or 'Right Right' case:
- // http://en.wikipedia.org/wiki/AVL_tree#Insertion
- SparseNameTree* tallChild = static_cast<SparseNameTree*>((this->*Tall).get());
- if ((tallChild->*Tall)->height() < (tallChild->*Short)->height()) {
- (this->*Tall).reset(tallChild->rotate<Short, Tall>());
- }
-
- // Perform a rotation to balance the tree.
- return this->rotate<Tall, Short>();
- }
-
- /**
- * Perform a node rotation, as described in the AVL algorithm:
- * http://en.wikipedia.org/wiki/AVL_tree#Insertion
- */
- template<ChildRange Tall, ChildRange Short>
- SparseNameRange* SK_WARN_UNUSED_RESULT rotate() {
- SparseNameTree* newRoot = static_cast<SparseNameTree*>((this->*Tall).detach());
-
- (this->*Tall).reset((newRoot->*Short).detach());
- this->updateStats();
-
- (newRoot->*Short).reset(this->takeRef());
- newRoot->updateStats();
-
- return newRoot;
- }
-
- void updateStats() {
- SkASSERT(fLeft->end() < fRight->first()); // There must be a gap between left and right.
- fFirst = fLeft->first();
- fEnd = fRight->end();
- fHeight = 1 + SkMax32(fLeft->height(), fRight->height());
- }
-
- SkAutoTUnref<SparseNameRange> fLeft;
- SkAutoTUnref<SparseNameRange> fRight;
-};
-
-/**
- * This class is the SparseNameRange implementation for a leaf node. It just a
- * contiguous range of allocated names.
- */
-class GrGLNameAllocator::ContiguousNameRange : public SparseNameRange {
-public:
- ContiguousNameRange(GrGLuint first, GrGLuint end) {
- SkASSERT(first < end);
- fFirst = first;
- fEnd = end;
- fHeight = 0;
- }
-
- SparseNameRange* SK_WARN_UNUSED_RESULT internalAllocate(GrGLuint* outName) override {
- *outName = 0; // No internal gaps, we are contiguous.
- return this->takeRef();
- }
-
- SparseNameRange* SK_WARN_UNUSED_RESULT removeLeftmostContiguousRange(GrGLuint* removedCount) override {
- *removedCount = fEnd - fFirst;
- return nullptr;
- }
-
- GrGLuint appendNames(GrGLuint count) override {
- SkASSERT(fEnd + count > fEnd); // Check for integer wrap.
- GrGLuint name = fEnd;
- fEnd += count;
- return name;
- }
-
- GrGLuint prependNames(GrGLuint count) override {
- SkASSERT(fFirst > count); // We can't allocate at or below 0.
- fFirst -= count;
- return fFirst;
- }
-
- SparseNameRange* SK_WARN_UNUSED_RESULT free(GrGLuint name) override {
- if (name < fFirst || name >= fEnd) {
- // Not-allocated names are silently ignored.
- return this->takeRef();
- }
-
- if (fFirst == name) {
- ++fFirst;
- return (fEnd == fFirst) ? nullptr : this->takeRef();
- }
-
- if (fEnd == name + 1) {
- --fEnd;
- return this->takeRef();
- }
-
- SparseNameRange* left = new ContiguousNameRange(fFirst, name);
- SparseNameRange* right = this->takeRef();
- fFirst = name + 1;
- return new SparseNameTree(left, right);
- }
-};
-
-GrGLNameAllocator::GrGLNameAllocator(GrGLuint firstName, GrGLuint endName)
- : fFirstName(firstName),
- fEndName(endName) {
- SkASSERT(firstName > 0);
- SkASSERT(endName > firstName);
-}
-
-GrGLNameAllocator::~GrGLNameAllocator() {
-}
-
-GrGLuint GrGLNameAllocator::allocateName() {
- if (nullptr == fAllocatedNames.get()) {
- fAllocatedNames.reset(new ContiguousNameRange(fFirstName, fFirstName + 1));
- return fFirstName;
- }
-
- if (fAllocatedNames->first() > fFirstName) {
- return fAllocatedNames->prependNames(1);
- }
-
- GrGLuint name;
- fAllocatedNames.reset(fAllocatedNames->internalAllocate(&name));
- if (0 != name) {
- return name;
- }
-
- if (fAllocatedNames->end() < fEndName) {
- return fAllocatedNames->appendNames(1);
- }
-
- // Out of names.
- return 0;
-}
-
-void GrGLNameAllocator::free(GrGLuint name) {
- if (!fAllocatedNames.get()) {
- // Not-allocated names are silently ignored.
- return;
- }
-
- fAllocatedNames.reset(fAllocatedNames->free(name));
-}
diff --git a/src/gpu/gl/GrGLNameAllocator.h b/src/gpu/gl/GrGLNameAllocator.h
deleted file mode 100644
index 8b0b2a244a..0000000000
--- a/src/gpu/gl/GrGLNameAllocator.h
+++ /dev/null
@@ -1,86 +0,0 @@
-
-/*
- * Copyright 2014 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef GrGLNameAllocator_DEFINED
-#define GrGLNameAllocator_DEFINED
-
-#include "SkRefCnt.h"
-#include "gl/GrGLTypes.h"
-
-/**
- * This class assumes ownership of an explicit range of OpenGL object names and
- * manages allocations within that range. This allows the app to generate new
- * objects on the client side without making round trips to the GL server.
- */
-class GrGLNameAllocator {
-public:
- /**
- * Constructs a name allocator that produces names within the explicit
- * half-open range [firstName, end). Note that the caller will most likely
- * need to call glGen* beforehand to reserve a range within the GL driver,
- * and then invoke this constructor with that range.
- *
- * @param firstName The first name in the range owned by this class. Must be
- greater than zero.
- * @param endName The first past-the-end name beyond the range owned by
- this class. Must be >= firstName.
- */
- GrGLNameAllocator(GrGLuint firstName, GrGLuint endName);
-
- /**
- * Destructs the name allocator. The caller is responsible for calling the
- * appropriate glDelete* on the range if necessary.
- */
- ~GrGLNameAllocator();
-
- /**
- * Return the beginning of this class's range.
- *
- * @return The first name in the range owned by this class.
- */
- GrGLuint firstName() const { return fFirstName; }
-
- /**
- * Return the end of this class's range. Note that endName() is not owned by
- * this class.
- *
- * @return One plus the final name in the range owned by this class.
- */
- GrGLuint endName() const { return fEndName; }
-
- /**
- * Allocate an OpenGL object name from within this class's range.
- *
- * @return The name if one was available,
- 0 if all the names in the range were already in use.
- */
- GrGLuint allocateName();
-
- /**
- * Free an OpenGL object name, allowing it to be returned by a future call
- * to allocateName(). Note that the caller should most likely redefine the
- * object as empty to deallocate any underlying GPU memory before calling
- * this method (but not call glDelete*, since that would free up the name
- * within the driver itself).
- *
- * @param name The object name to free. Not-allocated names are silently
- * ignored the same way they are in the OpenGL spec.
- */
- void free(GrGLuint name);
-
-private:
- class SparseNameRange;
- class SparseNameTree;
- class ContiguousNameRange;
-
- const GrGLuint fFirstName;
- const GrGLuint fEndName;
- SkAutoTUnref<SparseNameRange> fAllocatedNames;
-};
-
-#endif
diff --git a/src/gpu/gl/GrGLPathRendering.cpp b/src/gpu/gl/GrGLPathRendering.cpp
index 4c9ef86786..3cfec749ac 100644
--- a/src/gpu/gl/GrGLPathRendering.cpp
+++ b/src/gpu/gl/GrGLPathRendering.cpp
@@ -6,7 +6,6 @@
*/
#include "gl/GrGLPathRendering.h"
-#include "gl/GrGLNameAllocator.h"
#include "gl/GrGLUtil.h"
#include "gl/GrGLGpu.h"
@@ -20,6 +19,9 @@
#define GL_CALL(X) GR_GL_CALL(this->gpu()->glInterface(), X)
#define GL_CALL_RET(RET, X) GR_GL_CALL_RET(this->gpu()->glInterface(), RET, X)
+// Number of paths to allocate per glGenPaths call. The call can be overly slow on command buffer GL
+// implementation. The call has a result value, and thus waiting for the call completion is needed.
+static const GrGLsizei kPathIDPreallocationAmount = 65536;
static const GrGLenum gIndexType2GLType[] = {
GR_GL_UNSIGNED_BYTE,
@@ -60,17 +62,21 @@ static GrGLenum gr_stencil_op_to_gl_path_rendering_fill_mode(GrStencilOp op) {
}
GrGLPathRendering::GrGLPathRendering(GrGLGpu* gpu)
- : GrPathRendering(gpu) {
+ : GrPathRendering(gpu)
+ , fPreallocatedPathCount(0) {
const GrGLInterface* glInterface = gpu->glInterface();
fCaps.bindFragmentInputSupport =
nullptr != glInterface->fFunctions.fBindFragmentInputLocation;
}
GrGLPathRendering::~GrGLPathRendering() {
+ if (fPreallocatedPathCount > 0) {
+ this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount);
+ }
}
void GrGLPathRendering::abandonGpuResources() {
- fPathNameAllocator.reset(nullptr);
+ fPreallocatedPathCount = 0;
}
void GrGLPathRendering::resetContext() {
@@ -230,54 +236,57 @@ void GrGLPathRendering::setProjectionMatrix(const SkMatrix& matrix,
}
GrGLuint GrGLPathRendering::genPaths(GrGLsizei range) {
- if (range > 1) {
- GrGLuint name;
- GL_CALL_RET(name, GenPaths(range));
- return name;
+ SkASSERT(range > 0);
+ GrGLuint firstID;
+ if (fPreallocatedPathCount >= range) {
+ firstID = fFirstPreallocatedPathID;
+ fPreallocatedPathCount -= range;
+ fFirstPreallocatedPathID += range;
+ return firstID;
}
-
- if (nullptr == fPathNameAllocator.get()) {
- static const int range = 65536;
- GrGLuint firstName;
- GL_CALL_RET(firstName, GenPaths(range));
- fPathNameAllocator.reset(new GrGLNameAllocator(firstName, firstName + range));
+ // Allocate range + the amount to fill up preallocation amount. If succeed, either join with
+ // the existing preallocation range or delete the existing and use the new (potentially partial)
+ // preallocation range.
+ GrGLsizei allocAmount = range + (kPathIDPreallocationAmount - fPreallocatedPathCount);
+ if (allocAmount >= range) {
+ GL_CALL_RET(firstID, GenPaths(allocAmount));
+
+ if (firstID != 0) {
+ if (fPreallocatedPathCount > 0 &&
+ firstID == fFirstPreallocatedPathID + fPreallocatedPathCount) {
+ firstID = fFirstPreallocatedPathID;
+ fPreallocatedPathCount += allocAmount - range;
+ fFirstPreallocatedPathID += range;
+ return firstID;
+ }
+
+ if (allocAmount > range) {
+ if (fPreallocatedPathCount > 0) {
+ this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount);
+ }
+ fFirstPreallocatedPathID = firstID + range;
+ fPreallocatedPathCount = allocAmount - range;
+ }
+ // Special case: if allocAmount == range, we have full preallocated range.
+ return firstID;
+ }
}
-
- // When allocating names one at a time, pull from a client-side pool of
- // available names in order to save a round trip to the GL server.
- GrGLuint name = fPathNameAllocator->allocateName();
-
- if (0 == name) {
- // Our reserved path names are all in use. Fall back on GenPaths.
- GL_CALL_RET(name, GenPaths(1));
+ // Failed to allocate with preallocation. Remove existing preallocation and try to allocate just
+ // the range.
+ if (fPreallocatedPathCount > 0) {
+ this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount);
+ fPreallocatedPathCount = 0;
}
- return name;
+ GL_CALL_RET(firstID, GenPaths(range));
+ if (firstID == 0) {
+ SkDebugf("Warning: Failed to allocate path\n");
+ }
+ return firstID;
}
void GrGLPathRendering::deletePaths(GrGLuint path, GrGLsizei range) {
- if (range > 1) {
- // It is not supported to delete names in ranges that were allocated
- // individually using GrGLPathNameAllocator.
- SkASSERT(nullptr == fPathNameAllocator.get() ||
- path + range <= fPathNameAllocator->firstName() ||
- path >= fPathNameAllocator->endName());
- GL_CALL(DeletePaths(path, range));
- return;
- }
-
- if (nullptr == fPathNameAllocator.get() ||
- path < fPathNameAllocator->firstName() ||
- path >= fPathNameAllocator->endName()) {
- // If we aren't inside fPathNameAllocator's range then this name was
- // generated by the GenPaths fallback (or else was never allocated).
- GL_CALL(DeletePaths(path, 1));
- return;
- }
-
- // Make the path empty to save memory, but don't free the name in the driver.
- GL_CALL(PathCommands(path, 0, nullptr, 0, GR_GL_FLOAT, nullptr));
- fPathNameAllocator->free(path);
+ GL_CALL(DeletePaths(path, range));
}
void GrGLPathRendering::flushPathStencilSettings(const GrStencilSettings& stencilSettings) {
diff --git a/src/gpu/gl/GrGLPathRendering.h b/src/gpu/gl/GrGLPathRendering.h
index 57209fddc1..c3e5317808 100644
--- a/src/gpu/gl/GrGLPathRendering.h
+++ b/src/gpu/gl/GrGLPathRendering.h
@@ -111,7 +111,8 @@ private:
};
GrGLGpu* gpu();
- SkAutoTDelete<GrGLNameAllocator> fPathNameAllocator;
+ GrGLuint fFirstPreallocatedPathID;
+ GrGLsizei fPreallocatedPathCount;
MatrixState fHWProjectionMatrixState;
GrStencilSettings fHWPathStencilSettings;
Caps fCaps;
diff --git a/tests/NameAllocatorTest.cpp b/tests/NameAllocatorTest.cpp
deleted file mode 100644
index 86efdb2f72..0000000000
--- a/tests/NameAllocatorTest.cpp
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright 2014 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#if SK_SUPPORT_GPU
-
-#include "gl/GrGLNameAllocator.h"
-#include "Test.h"
-
-////////////////////////////////////////////////////////////////////////////////
-
-class NameLeakTest {
- static const GrGLuint kFirstName = 101;
- static const GrGLuint kRange = 1013;
-
-public:
- NameLeakTest(skiatest::Reporter* reporter)
- : fReporter(reporter),
- fAllocator(kFirstName, kFirstName + kRange),
- fAllocatedCount(0),
- fRandomName(kFirstName + 4 * kRange / 7) {
- memset(fAllocatedNames, 0, sizeof(fAllocatedNames));
- }
-
- bool run() {
- if (!this->allocateAllRemaining()) {
- return false;
- }
-
- for (GrGLuint freeCount = 1; freeCount <= kRange; ++freeCount) {
- if (!this->freeRandomNames(freeCount)) {
- return false;
- }
- if (!this->allocateAllRemaining()) {
- return false;
- }
- }
-
- return true;
- }
-
-private:
- bool isAllocated(GrGLuint name) const {
- return fAllocatedNames[name - kFirstName];
- }
-
- void setAllocated(GrGLuint name, bool allocated) {
- fAllocatedNames[name - kFirstName] = allocated;
- }
-
- bool allocateAllRemaining() {
- for (; fAllocatedCount < kRange; ++fAllocatedCount) {
- GrGLuint name = fAllocator.allocateName();
- if (0 == name) {
- ERRORF(fReporter,
- "Name allocate failed, but there should still be %u free names",
- kRange - fAllocatedCount);
- return false;
- }
- if (name < kFirstName || name >= kFirstName + kRange) {
- ERRORF(fReporter,
- "Name allocate returned name %u outside its bounds [%u, %u)",
- name, kFirstName, kFirstName + kRange);
- return false;
- }
- if (this->isAllocated(name)) {
- ERRORF(fReporter, "Name allocate returned name that is already allocated");
- return false;
- }
-
- this->setAllocated(name, true);
- }
-
- // Ensure it returns 0 once all the names are allocated.
- GrGLuint name = fAllocator.allocateName();
- if (0 != name) {
- ERRORF(fReporter,
- "Name allocate did not fail when all names were already in use");
- return false;
- }
-
- // Ensure every unique name is allocated.
- for (GrGLuint i = 0; i < kRange; ++i) {
- if (!this->isAllocated(kFirstName + i)) {
- ERRORF(fReporter, "Not all unique names are allocated after allocateAllRemaining()");
- return false;
- }
- }
-
- return true;
- }
-
- bool freeRandomNames(GrGLuint count) {
- // The values a and c make up an LCG (pseudo-random generator). These
- // values must satisfy the Hull-Dobell Theorem (with m=kRange):
- // http://en.wikipedia.org/wiki/Linear_congruential_generator
- // We use our own generator to guarantee it hits each unique value
- // within kRange exactly once before repeating.
- const GrGLuint seed = (count + fRandomName) / 2;
- const GrGLuint a = seed * kRange + 1;
- const GrGLuint c = (seed * 743) % kRange;
-
- for (GrGLuint i = 0; i < count; ++i) {
- fRandomName = (a * fRandomName + c) % kRange;
- const GrGLuint name = kFirstName + fRandomName;
- if (!this->isAllocated(name)) {
- ERRORF(fReporter, "Test bug: Should not free a not-allocated name at this point (%u)", i);
- return false;
- }
-
- fAllocator.free(name);
- this->setAllocated(name, false);
- --fAllocatedCount;
- }
-
- return true;
- }
-
- skiatest::Reporter* fReporter;
- GrGLNameAllocator fAllocator;
- bool fAllocatedNames[kRange];
- GrGLuint fAllocatedCount;
- GrGLuint fRandomName;
-};
-
-DEF_GPUTEST(NameAllocator, reporter, factory) {
- // Ensure no names are leaked or double-allocated during heavy usage.
- {
- NameLeakTest nameLeakTest(reporter);
- nameLeakTest.run();
- }
-
- static const GrGLuint range = 32;
- GrGLNameAllocator allocator(1, 1 + range);
- for (GrGLuint i = 1; i <= range; ++i) {
- allocator.allocateName();
- }
- REPORTER_ASSERT(reporter, 0 == allocator.allocateName());
-
- // Test freeing names out of range.
- allocator.free(allocator.firstName() - 1);
- allocator.free(allocator.endName());
- REPORTER_ASSERT(reporter, 0 == allocator.allocateName());
-
- // Test freeing not-allocated names.
- for (GrGLuint i = 1; i <= range/2; i += 2) {
- allocator.free(i);
- }
- for (GrGLuint i = 1; i <= range/2; i += 2) {
- // None of these names will be allocated.
- allocator.free(i);
- }
- for (GrGLuint i = 1; i <= range/2; ++i) {
- // Every other name will not be be allocated.
- allocator.free(i);
- }
- for (GrGLuint i = 1; i <= range/2; ++i) {
- if (0 == allocator.allocateName()) {
- ERRORF(reporter, "Name allocate failed when there should be free names");
- break;
- }
- }
- REPORTER_ASSERT(reporter, 0 == allocator.allocateName());
-}
-
-#endif