| Index: src/gpu/gl/GrGLPathRendering.cpp
|
| diff --git a/src/gpu/gl/GrGLPathRendering.cpp b/src/gpu/gl/GrGLPathRendering.cpp
|
| index 4c9ef86786744b8d4df4fbc276e01e90bfd6178c..3cfec749acbdfb92b79be253c4dd59da15fe7131 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) {
|
|
|