static IntersectionType intersection(const SkPoint& p1, const SkPoint& p2, const SkPoint& p3, const SkPoint& p4, SkPoint& res) { // Store the values for fast access and easy // equations-to-code conversion SkScalar x1 = p1.x(), x2 = p2.x(), x3 = p3.x(), x4 = p4.x(); SkScalar y1 = p1.y(), y2 = p2.y(), y3 = p3.y(), y4 = p4.y(); SkScalar d = SkScalarMul(x1 - x2, y3 - y4) - SkScalarMul(y1 - y2, x3 - x4); // If d is zero, there is no intersection if (SkScalarNearlyZero(d)) { return kNone_IntersectionType; } // Get the x and y SkScalar pre = SkScalarMul(x1, y2) - SkScalarMul(y1, x2), post = SkScalarMul(x3, y4) - SkScalarMul(y3, x4); // Compute the point of intersection res.set(SkScalarDiv(SkScalarMul(pre, x3 - x4) - SkScalarMul(x1 - x2, post), d), SkScalarDiv(SkScalarMul(pre, y3 - y4) - SkScalarMul(y1 - y2, post), d)); // Check if the x and y coordinates are within both lines return (res.x() < GrMin(x1, x2) || res.x() > GrMax(x1, x2) || res.x() < GrMin(x3, x4) || res.x() > GrMax(x3, x4) || res.y() < GrMin(y1, y2) || res.y() > GrMax(y1, y2) || res.y() < GrMin(y3, y4) || res.y() > GrMax(y3, y4)) ? kOut_IntersectionType : kIn_IntersectionType; }
GrBufferAllocPool::GrBufferAllocPool(GrGpu* gpu, BufferType bufferType, bool frequentResetHint, size_t blockSize, int preallocBufferCnt) : fBlocks(GrMax(8, 2*preallocBufferCnt)) { GrAssert(NULL != gpu); fGpu = gpu; fGpu->ref(); fGpuIsReffed = true; fBufferType = bufferType; fFrequentResetHint = frequentResetHint; fBufferPtr = NULL; fMinBlockSize = GrMax(GrBufferAllocPool_MIN_BLOCK_SIZE, blockSize); fBytesInUse = 0; fPreallocBuffersInUse = 0; fFirstPreallocBuffer = 0; for (int i = 0; i < preallocBufferCnt; ++i) { GrGeometryBuffer* buffer = this->createBuffer(fMinBlockSize); if (NULL != buffer) { *fPreallocBuffers.append() = buffer; buffer->ref(); } } }
uint32_t GrPathUtils::cubicPointCount(const GrPoint points[], GrScalar tol) { if (tol < gMinCurveTol) { tol == gMinCurveTol; } GrAssert(tol > 0); GrScalar d = GrMax( points[1].distanceToLineSegmentBetweenSqd(points[0], points[3]), points[2].distanceToLineSegmentBetweenSqd(points[0], points[3])); d = SkScalarSqrt(d); if (d <= tol) { return 1; } else { int temp = SkScalarCeil(SkScalarSqrt(SkScalarDiv(d, tol))); int pow2 = GrNextPow2(temp); // Because of NaNs & INFs we can wind up with a degenerate temp // such that pow2 comes out negative. Also, our point generator // will always output at least one pt. if (pow2 < 1) { pow2 = 1; } return GrMin(pow2, MAX_POINTS_PER_CURVE); } }
void* GrAllocPool::alloc(size_t size) { this->validate(); if (!fBlock || !fBlock->canAlloc(size)) { size_t blockSize = GrMax(fMinBlockSize, size); fBlock = Block::Create(blockSize, fBlock); GR_DEBUGCODE(fBlocksAllocated += 1;) }
bool GrBufferAllocPool::createBlock(size_t requestSize) { size_t size = GrMax(requestSize, fMinBlockSize); GrAssert(size >= GrBufferAllocPool_MIN_BLOCK_SIZE); VALIDATE(); BufferBlock& block = fBlocks.push_back(); if (size == fMinBlockSize && fPreallocBuffersInUse < fPreallocBuffers.count()) { uint32_t nextBuffer = (fPreallocBuffersInUse + fPreallocBufferStartIdx) % fPreallocBuffers.count(); block.fBuffer = fPreallocBuffers[nextBuffer]; block.fBuffer->ref(); ++fPreallocBuffersInUse; } else { block.fBuffer = this->createBuffer(size); if (NULL == block.fBuffer) { fBlocks.pop_back(); return false; } } block.fBytesFree = size; if (NULL != fBufferPtr) { GrAssert(fBlocks.count() > 1); BufferBlock& prev = fBlocks.fromBack(1); if (prev.fBuffer->isLocked()) { prev.fBuffer->unlock(); } else { flushCpuData(prev.fBuffer, prev.fBuffer->sizeInBytes() - prev.fBytesFree); } fBufferPtr = NULL; } GrAssert(NULL == fBufferPtr); if (fGpu->getCaps().fBufferLockSupport && size > GR_GEOM_BUFFER_LOCK_THRESHOLD && (!fFrequentResetHint || requestSize > GR_GEOM_BUFFER_LOCK_THRESHOLD)) { fBufferPtr = block.fBuffer->lock(); } if (NULL == fBufferPtr) { fBufferPtr = fCpuData.reset(size); } VALIDATE(true); return true; }
static uint32_t cubic_point_count(const GrPoint points[], GrScalar tol) { GrScalar d = GrMax(points[1].distanceToLineSegmentBetweenSqd(points[0], points[3]), points[2].distanceToLineSegmentBetweenSqd(points[0], points[3])); d = sqrtf(d); if (d < tol) { return 1; } else { d = ceilf(sqrtf(d/tol)); return GrMin(GrNextPow2((uint32_t)d), MAX_POINTS_PER_CURVE); } }
int GrInOrderDrawBuffer::concatInstancedDraw(const DrawInfo& info) { GrAssert(info.isInstanced()); const GeometrySrcState& geomSrc = this->getGeomSrc(); const GrDrawState& drawState = this->getDrawState(); // we only attempt to concat the case when reserved verts are used with a client-specified index // buffer. To make this work with client-specified VBs we'd need to know if the VB was updated // between draws. if (kReserved_GeometrySrcType != geomSrc.fVertexSrc || kBuffer_GeometrySrcType != geomSrc.fIndexSrc) { return 0; } // Check if there is a draw info that is compatible that uses the same VB from the pool and // the same IB if (kDraw_Cmd != fCmds.back()) { return 0; } DrawRecord* draw = &fDraws.back(); GeometryPoolState& poolState = fGeoPoolStateStack.back(); const GrVertexBuffer* vertexBuffer = poolState.fPoolVertexBuffer; if (!draw->isInstanced() || draw->verticesPerInstance() != info.verticesPerInstance() || draw->indicesPerInstance() != info.indicesPerInstance() || draw->fVertexBuffer != vertexBuffer || draw->fIndexBuffer != geomSrc.fIndexBuffer) { return 0; } // info does not yet account for the offset from the start of the pool's VB while the previous // draw record does. int adjustedStartVertex = poolState.fPoolStartVertex + info.startVertex(); if (draw->startVertex() + draw->vertexCount() != adjustedStartVertex) { return 0; } GrAssert(poolState.fPoolStartVertex == draw->startVertex() + draw->vertexCount()); // how many instances can be concat'ed onto draw given the size of the index buffer int instancesToConcat = this->indexCountInCurrentSource() / info.indicesPerInstance(); instancesToConcat -= draw->instanceCount(); instancesToConcat = GrMin(instancesToConcat, info.instanceCount()); // update the amount of reserved vertex data actually referenced in draws size_t vertexBytes = instancesToConcat * info.verticesPerInstance() * drawState.getVertexSize(); poolState.fUsedPoolVertexBytes = GrMax(poolState.fUsedPoolVertexBytes, vertexBytes); draw->adjustInstanceCount(instancesToConcat); return instancesToConcat; }
size_t GrRenderTarget::sizeInBytes() const { int colorBits; if (kUnknown_GrPixelConfig == fConfig) { colorBits = 32; // don't know, make a guess } else { colorBits = GrBytesPerPixel(fConfig); } uint64_t size = fWidth; size *= fHeight; size *= colorBits; size *= GrMax(1,fSampleCnt); return (size_t)(size / 8); }
GrMemoryPool::GrMemoryPool(size_t preallocSize, size_t minAllocSize) { GR_DEBUGCODE(fAllocationCnt = 0); minAllocSize = GrMax<size_t>(minAllocSize, 1 << 10); fMinAllocSize = GrSizeAlignUp(minAllocSize + kPerAllocPad, kAlignment), fPreallocSize = GrSizeAlignUp(preallocSize + kPerAllocPad, kAlignment); fPreallocSize = GrMax(fPreallocSize, fMinAllocSize); fHead = CreateBlock(fPreallocSize); fTail = fHead; fHead->fNext = NULL; fHead->fPrev = NULL; VALIDATE; };
void GrInOrderDrawBuffer::onDrawNonIndexed(GrPrimitiveType primitiveType, int startVertex, int vertexCount) { if (!vertexCount) { return; } fCurrQuad = 0; GeometryPoolState& poolState = fGeoPoolStateStack.back(); Draw& draw = fDraws.push_back(); draw.fPrimitiveType = primitiveType; draw.fStartVertex = startVertex; draw.fStartIndex = 0; draw.fVertexCount = vertexCount; draw.fIndexCount = 0; draw.fClipChanged = this->needsNewClip(); if (draw.fClipChanged) { this->pushClip(); } draw.fStateChanged = this->needsNewState(); if (draw.fStateChanged) { this->pushState(); } draw.fVertexLayout = this->getGeomSrc().fVertexLayout; switch (this->getGeomSrc().fVertexSrc) { case kBuffer_GeometrySrcType: draw.fVertexBuffer = this->getGeomSrc().fVertexBuffer; break; case kReserved_GeometrySrcType: // fallthrough case kArray_GeometrySrcType: { size_t vertexBytes = (vertexCount + startVertex) * VertexSize(this->getGeomSrc().fVertexLayout); poolState.fUsedPoolVertexBytes = GrMax(poolState.fUsedPoolVertexBytes, vertexBytes); draw.fVertexBuffer = poolState.fPoolVertexBuffer; draw.fStartVertex += poolState.fPoolStartVertex; break; } default: GrCrash("unknown geom src type"); } draw.fVertexBuffer->ref(); draw.fIndexBuffer = NULL; }
void GrInOrderDrawBuffer::onDrawNonIndexed(GrPrimitiveType primitiveType, int startVertex, int vertexCount) { if (!vertexCount) { return; } this->resetDrawTracking(); GeometryPoolState& poolState = fGeoPoolStateStack.back(); if (this->needsNewClip()) { this->recordClip(); } if (this->needsNewState()) { this->recordState(); } Draw* draw = this->recordDraw(); draw->fPrimitiveType = primitiveType; draw->fStartVertex = startVertex; draw->fStartIndex = 0; draw->fVertexCount = vertexCount; draw->fIndexCount = 0; draw->fVertexLayout = this->getVertexLayout(); switch (this->getGeomSrc().fVertexSrc) { case kBuffer_GeometrySrcType: draw->fVertexBuffer = this->getGeomSrc().fVertexBuffer; break; case kReserved_GeometrySrcType: // fallthrough case kArray_GeometrySrcType: { size_t vertexBytes = (vertexCount + startVertex) * GrDrawState::VertexSize(draw->fVertexLayout); poolState.fUsedPoolVertexBytes = GrMax(poolState.fUsedPoolVertexBytes, vertexBytes); draw->fVertexBuffer = poolState.fPoolVertexBuffer; draw->fStartVertex += poolState.fPoolStartVertex; break; } default: GrCrash("unknown geom src type"); } draw->fVertexBuffer->ref(); draw->fIndexBuffer = NULL; }
bool GrBufferAllocPool::createBlock(size_t requestSize) { size_t size = GrMax(requestSize, fMinBlockSize); GrAssert(size >= GrBufferAllocPool_MIN_BLOCK_SIZE); VALIDATE(); BufferBlock& block = fBlocks.push_back(); if (size == fMinBlockSize && fPreallocBuffersInUse < fPreallocBuffers.count()) { uint32_t nextBuffer = (fPreallocBuffersInUse + fPreallocBufferStartIdx) % fPreallocBuffers.count(); block.fBuffer = fPreallocBuffers[nextBuffer]; block.fBuffer->ref(); ++fPreallocBuffersInUse; } else { block.fBuffer = this->createBuffer(size); if (NULL == block.fBuffer) { fBlocks.pop_back(); return false; } } block.fBytesFree = size; if (NULL != fBufferPtr) { GrAssert(fBlocks.count() > 1); BufferBlock& prev = fBlocks.fromBack(1); if (prev.fBuffer->isLocked()) { prev.fBuffer->unlock(); } else { flushCpuData(prev.fBuffer, prev.fBuffer->sizeInBytes() - prev.fBytesFree); } fBufferPtr = NULL; } GrAssert(NULL == fBufferPtr); // If the buffer is CPU-backed we lock it because it is free to do so and saves a copy. // Otherwise when buffer locking is supported: // a) If the frequently reset hint is set we only lock when the requested size meets a // threshold (since we don't expect it is likely that we will see more vertex data) // b) If the hint is not set we lock if the buffer size is greater than the threshold. bool attemptLock = block.fBuffer->isCPUBacked(); if (!attemptLock && fGpu->caps()->bufferLockSupport()) { if (fFrequentResetHint) { attemptLock = requestSize > GR_GEOM_BUFFER_LOCK_THRESHOLD; } else { attemptLock = size > GR_GEOM_BUFFER_LOCK_THRESHOLD; } } if (attemptLock) { fBufferPtr = block.fBuffer->lock(); } if (NULL == fBufferPtr) { fBufferPtr = fCpuData.reset(size); } VALIDATE(true); return true; }
void GrInOrderDrawBuffer::onDraw(const DrawInfo& info) { GeometryPoolState& poolState = fGeoPoolStateStack.back(); const GrDrawState& drawState = this->getDrawState(); AutoClipReenable acr; if (drawState.isClipState() && NULL != info.getDevBounds() && this->quickInsideClip(*info.getDevBounds())) { acr.set(this->drawState()); } if (this->needsNewClip()) { this->recordClip(); } if (this->needsNewState()) { this->recordState(); } DrawRecord* draw; if (info.isInstanced()) { int instancesConcated = this->concatInstancedDraw(info); if (info.instanceCount() > instancesConcated) { draw = this->recordDraw(info); draw->adjustInstanceCount(-instancesConcated); } else { return; } } else { draw = this->recordDraw(info); } switch (this->getGeomSrc().fVertexSrc) { case kBuffer_GeometrySrcType: draw->fVertexBuffer = this->getGeomSrc().fVertexBuffer; break; case kReserved_GeometrySrcType: // fallthrough case kArray_GeometrySrcType: { size_t vertexBytes = (info.vertexCount() + info.startVertex()) * drawState.getVertexSize(); poolState.fUsedPoolVertexBytes = GrMax(poolState.fUsedPoolVertexBytes, vertexBytes); draw->fVertexBuffer = poolState.fPoolVertexBuffer; draw->adjustStartVertex(poolState.fPoolStartVertex); break; } default: GrCrash("unknown geom src type"); } draw->fVertexBuffer->ref(); if (info.isIndexed()) { switch (this->getGeomSrc().fIndexSrc) { case kBuffer_GeometrySrcType: draw->fIndexBuffer = this->getGeomSrc().fIndexBuffer; break; case kReserved_GeometrySrcType: // fallthrough case kArray_GeometrySrcType: { size_t indexBytes = (info.indexCount() + info.startIndex()) * sizeof(uint16_t); poolState.fUsedPoolIndexBytes = GrMax(poolState.fUsedPoolIndexBytes, indexBytes); draw->fIndexBuffer = poolState.fPoolIndexBuffer; draw->adjustStartIndex(poolState.fPoolStartIndex); break; } default: GrCrash("unknown geom src type"); } draw->fIndexBuffer->ref(); } else { draw->fIndexBuffer = NULL; } }
void GrInOrderDrawBuffer::drawIndexedInstances(GrPrimitiveType type, int instanceCount, int verticesPerInstance, int indicesPerInstance) { if (!verticesPerInstance || !indicesPerInstance) { return; } const GeometrySrcState& geomSrc = this->getGeomSrc(); // we only attempt to concat the case when reserved verts are used with // an index buffer. if (kReserved_GeometrySrcType == geomSrc.fVertexSrc && kBuffer_GeometrySrcType == geomSrc.fIndexSrc) { Draw* draw = NULL; // if the last draw used the same indices/vertices per shape then we // may be able to append to it. if (verticesPerInstance == fInstancedDrawTracker.fVerticesPerInstance && indicesPerInstance == fInstancedDrawTracker.fIndicesPerInstance) { GrAssert(fDraws.count()); draw = &fDraws.back(); } bool clipChanged = this->needsNewClip(); bool stateChanged = this->needsNewState(); if (clipChanged) { this->pushClip(); } if (stateChanged) { this->pushState(); } GeometryPoolState& poolState = fGeoPoolStateStack.back(); const GrVertexBuffer* vertexBuffer = poolState.fPoolVertexBuffer; // Check whether the draw is compatible with this draw in order to // append if (NULL == draw || clipChanged || stateChanged || draw->fIndexBuffer != geomSrc.fIndexBuffer || draw->fPrimitiveType != type || draw->fVertexBuffer != vertexBuffer) { draw = &fDraws.push_back(); draw->fClipChanged = clipChanged; draw->fStateChanged = stateChanged; draw->fIndexBuffer = geomSrc.fIndexBuffer; geomSrc.fIndexBuffer->ref(); draw->fVertexBuffer = vertexBuffer; vertexBuffer->ref(); draw->fPrimitiveType = type; draw->fStartIndex = 0; draw->fIndexCount = 0; draw->fStartVertex = poolState.fPoolStartVertex; draw->fVertexCount = 0; draw->fVertexLayout = geomSrc.fVertexLayout; } else { GrAssert(!(draw->fIndexCount % indicesPerInstance)); GrAssert(!(draw->fVertexCount % verticesPerInstance)); GrAssert(poolState.fPoolStartVertex == draw->fStartVertex + draw->fVertexCount); } // how many instances can be in a single draw int maxInstancesPerDraw = this->indexCountInCurrentSource() / indicesPerInstance; if (!maxInstancesPerDraw) { return; } // how many instances should be concat'ed onto draw int instancesToConcat = maxInstancesPerDraw - draw->fVertexCount / verticesPerInstance; if (maxInstancesPerDraw > instanceCount) { maxInstancesPerDraw = instanceCount; if (instancesToConcat > instanceCount) { instancesToConcat = instanceCount; } } // update the amount of reserved data actually referenced in draws size_t vertexBytes = instanceCount * verticesPerInstance * VertexSize(draw->fVertexLayout); poolState.fUsedPoolVertexBytes = GrMax(poolState.fUsedPoolVertexBytes, vertexBytes); while (instanceCount) { if (!instancesToConcat) { int startVertex = draw->fStartVertex + draw->fVertexCount; draw = &fDraws.push_back(); draw->fClipChanged = false; draw->fStateChanged = false; draw->fIndexBuffer = geomSrc.fIndexBuffer; geomSrc.fIndexBuffer->ref(); draw->fVertexBuffer = vertexBuffer; vertexBuffer->ref(); draw->fPrimitiveType = type; draw->fStartIndex = 0; draw->fStartVertex = startVertex; draw->fVertexCount = 0; draw->fVertexLayout = geomSrc.fVertexLayout; instancesToConcat = maxInstancesPerDraw; } draw->fVertexCount += instancesToConcat * verticesPerInstance; draw->fIndexCount += instancesToConcat * indicesPerInstance; instanceCount -= instancesToConcat; instancesToConcat = 0; } // update draw tracking for next draw fCurrQuad = 0; fInstancedDrawTracker.fVerticesPerInstance = verticesPerInstance; fInstancedDrawTracker.fIndicesPerInstance = indicesPerInstance; } else { this->INHERITED::drawIndexedInstances(type, instanceCount, verticesPerInstance, indicesPerInstance); } }
GrAllocPool::GrAllocPool(size_t blockSize) { fBlock = NULL; fMinBlockSize = GrMax(blockSize, GrAllocPool_MIN_BLOCK_SIZE); GR_DEBUGCODE(fBlocksAllocated = 0;) }