void GrResourceCache2::insertResource(GrGpuResource* resource) { SkASSERT(resource); SkASSERT(!resource->wasDestroyed()); SkASSERT(!this->isInCache(resource)); SkASSERT(!fPurging); fResources.addToHead(resource); size_t size = resource->gpuMemorySize(); ++fCount; fBytes += size; #if GR_CACHE_STATS fHighWaterCount = SkTMax(fCount, fHighWaterCount); fHighWaterBytes = SkTMax(fBytes, fHighWaterBytes); #endif if (resource->cacheAccess().isBudgeted()) { ++fBudgetedCount; fBudgetedBytes += size; #if GR_CACHE_STATS fBudgetedHighWaterCount = SkTMax(fBudgetedCount, fBudgetedHighWaterCount); fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes); #endif } if (!resource->cacheAccess().getScratchKey().isNullScratch()) { SkASSERT(!resource->cacheAccess().isWrapped()); fScratchMap.insert(resource->cacheAccess().getScratchKey(), resource); } this->purgeAsNeeded(); }
/* It is necessary to average the color component of transparent pixels with their surrounding neighbors since the PDF renderer may separately re-sample the alpha and color channels when the image is not displayed at its native resolution. Since an alpha of zero gives no information about the color component, the pathological case is a white image with sharp transparency bounds - the color channel goes to black, and the should-be-transparent pixels are rendered as grey because of the separate soft mask and color resizing. e.g.: gm/bitmappremul.cpp */ static void get_neighbor_avg_color(const SkBitmap& bm, int xOrig, int yOrig, uint8_t rgb[3], SkColorType ct) { unsigned a = 0, r = 0, g = 0, b = 0; // Clamp the range to the edge of the bitmap. int ymin = SkTMax(0, yOrig - 1); int ymax = SkTMin(yOrig + 1, bm.height() - 1); int xmin = SkTMax(0, xOrig - 1); int xmax = SkTMin(xOrig + 1, bm.width() - 1); for (int y = ymin; y <= ymax; ++y) { uint32_t* scanline = bm.getAddr32(0, y); for (int x = xmin; x <= xmax; ++x) { uint32_t color = scanline[x]; a += SkGetA32Component(color, ct); r += SkGetR32Component(color, ct); g += SkGetG32Component(color, ct); b += SkGetB32Component(color, ct); } } if (a > 0) { rgb[0] = SkToU8(255 * r / a); rgb[1] = SkToU8(255 * g / a); rgb[2] = SkToU8(255 * b / a); } else { rgb[0] = rgb[1] = rgb[2] = 0; } }
/* It is necessary to average the color component of transparent pixels with their surrounding neighbors since the PDF renderer may separately re-sample the alpha and color channels when the image is not displayed at its native resolution. Since an alpha of zero gives no information about the color component, the pathological case is a white image with sharp transparency bounds - the color channel goes to black, and the should-be-transparent pixels are rendered as grey because of the separate soft mask and color resizing. e.g.: gm/bitmappremul.cpp */ static void get_neighbor_avg_color(const SkBitmap& bm, int xOrig, int yOrig, uint8_t rgb[3]) { SkASSERT(kN32_SkColorType == bm.colorType()); unsigned a = 0, r = 0, g = 0, b = 0; // Clamp the range to the edge of the bitmap. int ymin = SkTMax(0, yOrig - 1); int ymax = SkTMin(yOrig + 1, bm.height() - 1); int xmin = SkTMax(0, xOrig - 1); int xmax = SkTMin(xOrig + 1, bm.width() - 1); for (int y = ymin; y <= ymax; ++y) { SkPMColor* scanline = bm.getAddr32(0, y); for (int x = xmin; x <= xmax; ++x) { SkPMColor pmColor = scanline[x]; a += SkGetPackedA32(pmColor); r += SkGetPackedR32(pmColor); g += SkGetPackedG32(pmColor); b += SkGetPackedB32(pmColor); } } if (a > 0) { rgb[0] = SkToU8(255 * r / a); rgb[1] = SkToU8(255 * g / a); rgb[2] = SkToU8(255 * b / a); } else { rgb[0] = rgb[1] = rgb[2] = 0; } }
void GrInOrderDrawBuffer::onDraw(const DrawInfo& info) { GeometryPoolState& poolState = fGeoPoolStateStack.back(); const GrDrawState& drawState = this->getDrawState(); AutoClipReenable acr; if (drawState.isClipState() && info.getDevBounds() && this->quickInsideClip(*info.getDevBounds())) { acr.set(this->drawState()); } this->recordClipIfNecessary(); this->recordStateIfNecessary(); const GrVertexBuffer* vb; if (kBuffer_GeometrySrcType == this->getGeomSrc().fVertexSrc) { vb = this->getGeomSrc().fVertexBuffer; } else { vb = poolState.fPoolVertexBuffer; } const GrIndexBuffer* ib = NULL; if (info.isIndexed()) { if (kBuffer_GeometrySrcType == this->getGeomSrc().fIndexSrc) { ib = this->getGeomSrc().fIndexBuffer; } else { ib = poolState.fPoolIndexBuffer; } } Draw* draw; if (info.isInstanced()) { int instancesConcated = this->concatInstancedDraw(info); if (info.instanceCount() > instancesConcated) { draw = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, Draw, (info, vb, ib)); draw->fInfo.adjustInstanceCount(-instancesConcated); } else { return; } } else { draw = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, Draw, (info, vb, ib)); } this->recordTraceMarkersIfNecessary(); // Adjust the starting vertex and index when we are using reserved or array sources to // compensate for the fact that the data was inserted into a larger vb/ib owned by the pool. if (kBuffer_GeometrySrcType != this->getGeomSrc().fVertexSrc) { size_t bytes = (info.vertexCount() + info.startVertex()) * drawState.getVertexStride(); poolState.fUsedPoolVertexBytes = SkTMax(poolState.fUsedPoolVertexBytes, bytes); draw->fInfo.adjustStartVertex(poolState.fPoolStartVertex); } if (info.isIndexed() && kBuffer_GeometrySrcType != this->getGeomSrc().fIndexSrc) { size_t bytes = (info.indexCount() + info.startIndex()) * sizeof(uint16_t); poolState.fUsedPoolIndexBytes = SkTMax(poolState.fUsedPoolIndexBytes, bytes); draw->fInfo.adjustStartIndex(poolState.fPoolStartIndex); } }
static uint16_t packTriple(U8CPU r, U8CPU g, U8CPU b) { #ifdef SK_SHOW_TEXT_BLIT_COVERAGE r = SkTMax(r, (U8CPU)0x40); g = SkTMax(g, (U8CPU)0x40); b = SkTMax(b, (U8CPU)0x40); #endif return SkPack888ToRGB16(r, g, b); }
static double maxQuad(const SkDQuad& quad) { double max = 0; for (int index = 0; index < 2; ++index) { max = SkTMax(max, fabs(quad[index].fX)); max = SkTMax(max, fabs(quad[index].fY)); } return max; }
static void join(SkRect* out, const SkRect& a, const SkRect& b) { SkASSERT(a.fLeft <= a.fRight && a.fTop <= a.fBottom); SkASSERT(b.fLeft <= b.fRight && b.fTop <= b.fBottom); out->fLeft = SkTMin(a.fLeft, b.fLeft); out->fTop = SkTMin(a.fTop, b.fTop); out->fRight = SkTMax(a.fRight, b.fRight); out->fBottom = SkTMax(a.fBottom, b.fBottom); }
static bool cubic_in_bounds(const SkScalar* pts, const SkScalar bounds[2]) { SkScalar min = SkTMin(SkTMin(SkTMin(pts[0], pts[2]), pts[4]), pts[6]); if (bounds[1] < min) { return false; } SkScalar max = SkTMax(SkTMax(SkTMax(pts[0], pts[2]), pts[4]), pts[6]); return bounds[0] < max; }
// reduce to a quadratic or smaller // look for identical points // look for all four points in a line // note that three points in a line doesn't simplify a cubic // look for approximation with single quadratic // save approximation with multiple quadratics for later int reduceOrder(const Cubic& cubic, Cubic& reduction, ReduceOrder_Quadratics allowQuadratics, ReduceOrder_Styles reduceStyle) { int index, minX, maxX, minY, maxY; int minXSet, minYSet; minX = maxX = minY = maxY = 0; minXSet = minYSet = 0; for (index = 1; index < 4; ++index) { if (cubic[minX].x > cubic[index].x) { minX = index; } if (cubic[minY].y > cubic[index].y) { minY = index; } if (cubic[maxX].x < cubic[index].x) { maxX = index; } if (cubic[maxY].y < cubic[index].y) { maxY = index; } } for (index = 0; index < 4; ++index) { double cx = cubic[index].x; double cy = cubic[index].y; double denom = SkTMax(fabs(cx), SkTMax(fabs(cy), SkTMax(fabs(cubic[minX].x), fabs(cubic[minY].y)))); if (denom == 0) { minXSet |= 1 << index; minYSet |= 1 << index; continue; } double inv = 1 / denom; if (approximately_equal_half(cx * inv, cubic[minX].x * inv)) { minXSet |= 1 << index; } if (approximately_equal_half(cy * inv, cubic[minY].y * inv)) { minYSet |= 1 << index; } } if (minXSet == 0xF) { // test for vertical line if (minYSet == 0xF) { // return 1 if all four are coincident return coincident_line(cubic, reduction); } return vertical_line(cubic, reduceStyle, reduction); } if (minYSet == 0xF) { // test for horizontal line return horizontal_line(cubic, reduceStyle, reduction); } int result = check_linear(cubic, reduceStyle, minX, maxX, minY, maxY, reduction); if (result) { return result; } if (allowQuadratics == kReduceOrder_QuadraticsAllowed && (result = check_quadratic(cubic, reduction))) { return result; } memcpy(reduction, cubic, sizeof(Cubic)); return 4; }
void GLEllipticalRRectEffect::onSetData(const GrGLSLProgramDataManager& pdman, const GrFragmentProcessor& effect) { const EllipticalRRectEffect& erre = effect.cast<EllipticalRRectEffect>(); const SkRRect& rrect = erre.getRRect(); // If we're using a scale factor to work around precision issues, choose the largest radius // as the scale factor. The inv radii need to be pre-adjusted by the scale factor. if (rrect != fPrevRRect) { SkRect rect = rrect.getBounds(); const SkVector& r0 = rrect.radii(SkRRect::kUpperLeft_Corner); SkASSERT(r0.fX >= kRadiusMin); SkASSERT(r0.fY >= kRadiusMin); switch (erre.getRRect().getType()) { case SkRRect::kSimple_Type: rect.inset(r0.fX, r0.fY); if (fScaleUniform.isValid()) { if (r0.fX > r0.fY) { pdman.set2f(fInvRadiiSqdUniform, 1.f, (r0.fX * r0.fX) / (r0.fY * r0.fY)); pdman.set2f(fScaleUniform, r0.fX, 1.f / r0.fX); } else { pdman.set2f(fInvRadiiSqdUniform, (r0.fY * r0.fY) / (r0.fX * r0.fX), 1.f); pdman.set2f(fScaleUniform, r0.fY, 1.f / r0.fY); } } else { pdman.set2f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX), 1.f / (r0.fY * r0.fY)); } break; case SkRRect::kNinePatch_Type: { const SkVector& r1 = rrect.radii(SkRRect::kLowerRight_Corner); SkASSERT(r1.fX >= kRadiusMin); SkASSERT(r1.fY >= kRadiusMin); rect.fLeft += r0.fX; rect.fTop += r0.fY; rect.fRight -= r1.fX; rect.fBottom -= r1.fY; if (fScaleUniform.isValid()) { float scale = SkTMax(SkTMax(r0.fX, r0.fY), SkTMax(r1.fX, r1.fY)); float scaleSqd = scale * scale; pdman.set4f(fInvRadiiSqdUniform, scaleSqd / (r0.fX * r0.fX), scaleSqd / (r0.fY * r0.fY), scaleSqd / (r1.fX * r1.fX), scaleSqd / (r1.fY * r1.fY)); pdman.set2f(fScaleUniform, scale, 1.f / scale); } else { pdman.set4f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX), 1.f / (r0.fY * r0.fY), 1.f / (r1.fX * r1.fX), 1.f / (r1.fY * r1.fY)); } break; } default: SK_ABORT("RRect should always be simple or nine-patch."); } pdman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom); fPrevRRect = rrect; } }
static inline bool intersect(SkRect* out, const SkRect& a, const SkRect& b) { SkASSERT(a.fLeft <= a.fRight && a.fTop <= a.fBottom); SkASSERT(b.fLeft <= b.fRight && b.fTop <= b.fBottom); out->fLeft = SkTMax(a.fLeft, b.fLeft); out->fTop = SkTMax(a.fTop, b.fTop); out->fRight = SkTMin(a.fRight, b.fRight); out->fBottom = SkTMin(a.fBottom, b.fBottom); return (out->fLeft <= out->fRight && out->fTop <= out->fBottom); }
// reduce to a quadratic or smaller // look for identical points // look for all four points in a line // note that three points in a line doesn't simplify a cubic // look for approximation with single quadratic // save approximation with multiple quadratics for later int SkReduceOrder::reduce(const SkDCubic& cubic, Quadratics allowQuadratics) { int index, minX, maxX, minY, maxY; int minXSet, minYSet; minX = maxX = minY = maxY = 0; minXSet = minYSet = 0; for (index = 1; index < 4; ++index) { if (cubic[minX].fX > cubic[index].fX) { minX = index; } if (cubic[minY].fY > cubic[index].fY) { minY = index; } if (cubic[maxX].fX < cubic[index].fX) { maxX = index; } if (cubic[maxY].fY < cubic[index].fY) { maxY = index; } } for (index = 0; index < 4; ++index) { double cx = cubic[index].fX; double cy = cubic[index].fY; double denom = SkTMax(fabs(cx), SkTMax(fabs(cy), SkTMax(fabs(cubic[minX].fX), fabs(cubic[minY].fY)))); if (denom == 0) { minXSet |= 1 << index; minYSet |= 1 << index; continue; } double inv = 1 / denom; if (approximately_equal_half(cx * inv, cubic[minX].fX * inv)) { minXSet |= 1 << index; } if (approximately_equal_half(cy * inv, cubic[minY].fY * inv)) { minYSet |= 1 << index; } } if (minXSet == 0xF) { // test for vertical line if (minYSet == 0xF) { // return 1 if all four are coincident return coincident_line(cubic, fCubic); } return vertical_line(cubic, fCubic); } if (minYSet == 0xF) { // test for horizontal line return horizontal_line(cubic, fCubic); } int result = check_linear(cubic, minX, maxX, minY, maxY, fCubic); if (result) { return result; } if (allowQuadratics == SkReduceOrder::kAllow_Quadratics && (result = check_quadratic(cubic, fCubic))) { return result; } fCubic = cubic; return 4; }
GrCCPRAtlas::GrCCPRAtlas(const GrCaps& caps, int minWidth, int minHeight) : fMaxAtlasSize(caps.maxRenderTargetSize()) , fDrawBounds{0, 0} { SkASSERT(fMaxAtlasSize <= caps.maxTextureSize()); SkASSERT(SkTMax(minWidth, minHeight) <= fMaxAtlasSize); int initialSize = GrNextPow2(SkTMax(minWidth, minHeight)); initialSize = SkTMax(int(kMinSize), initialSize); initialSize = SkTMin(initialSize, fMaxAtlasSize); fHeight = fWidth = initialSize; fTopNode = skstd::make_unique<Node>(nullptr, 0, 0, initialSize, initialSize); }
bool GrCCPRAtlas::addRect(int w, int h, SkIPoint16* loc) { // This can't be called anymore once finalize() has been called. SkASSERT(!fTextureProxy); if (!this->internalPlaceRect(w, h, loc)) { return false; } fDrawBounds.fWidth = SkTMax(fDrawBounds.width(), loc->x() + w); fDrawBounds.fHeight = SkTMax(fDrawBounds.height(), loc->y() + h); return true; }
void PathText::Glyph::reset(SkRandom& rand, int w, int h) { int screensize = SkTMax(w, h); const SkRect& bounds = fPath.getBounds(); SkScalar t; fPosition = {rand.nextF() * w, rand.nextF() * h}; t = pow(rand.nextF(), 100); fZoom = ((1 - t) * screensize / 50 + t * screensize / 3) / SkTMax(bounds.width(), bounds.height()); fSpin = rand.nextF() * 360; fMidpt = {bounds.centerX(), bounds.centerY()}; }
// The tallest inset rect SkRect compute_tallest_occluder(const SkRRect& rr) { const SkRect& r = rr.getBounds(); const SkVector& ul = rr.radii(SkRRect::kUpperLeft_Corner); const SkVector& ur = rr.radii(SkRRect::kUpperRight_Corner); const SkVector& lr = rr.radii(SkRRect::kLowerRight_Corner); const SkVector& ll = rr.radii(SkRRect::kLowerLeft_Corner); SkScalar maxL = SkTMax(ul.fX, ll.fX); SkScalar maxR = SkTMax(ur.fX, lr.fX); return SkRect::MakeLTRB(r.fLeft + maxL, r.fTop, r.fRight - maxR, r.fBottom); }
// OPTIMIZATION: can this be done better in after when angles are sorted? void SkOpAngle::markStops() { SkOpAngle* angle = this; int lastEnd = SkTMax(fSectorStart, fSectorEnd); do { angle = angle->fNext; int angleStart = SkTMin(angle->fSectorStart, angle->fSectorEnd); // angles that are smaller by one aren't necessary better, since the larger may be a line // and the smaller may be a curve that curls to the other side of the line. if (lastEnd + 1 < angleStart) { angle->fStop = true; } lastEnd = SkTMax(angle->fSectorStart, angle->fSectorEnd); } while (angle != this); }
// The widest inset rect SkRect compute_widest_occluder(const SkRRect& rr) { const SkRect& r = rr.getBounds(); const SkVector& ul = rr.radii(SkRRect::kUpperLeft_Corner); const SkVector& ur = rr.radii(SkRRect::kUpperRight_Corner); const SkVector& lr = rr.radii(SkRRect::kLowerRight_Corner); const SkVector& ll = rr.radii(SkRRect::kLowerLeft_Corner); SkScalar maxT = SkTMax(ul.fY, ur.fY); SkScalar maxB = SkTMax(ll.fY, lr.fY); return SkRect::MakeLTRB(r.fLeft, r.fTop + maxT, r.fRight, r.fBottom - maxB); }
bool SkRect::setBoundsCheck(const SkPoint pts[], int count) { SkASSERT((pts && count > 0) || count == 0); bool isFinite = true; if (count <= 0) { sk_bzero(this, sizeof(SkRect)); } else { Sk4s min, max, accum; if (count & 1) { min = Sk4s(pts[0].fX, pts[0].fY, pts[0].fX, pts[0].fY); pts += 1; count -= 1; } else { min = Sk4s::Load(&pts[0].fX); pts += 2; count -= 2; } accum = max = min; accum *= Sk4s(0); count >>= 1; for (int i = 0; i < count; ++i) { Sk4s xy = Sk4s::Load(&pts->fX); accum *= xy; min = Sk4s::Min(min, xy); max = Sk4s::Max(max, xy); pts += 2; } /** * With some trickery, we may be able to use Min/Max to also propogate non-finites, * in which case we could eliminate accum entirely, and just check min and max for * "is_finite". */ if (is_finite(accum)) { float minArray[4], maxArray[4]; min.store(minArray); max.store(maxArray); this->set(SkTMin(minArray[0], minArray[2]), SkTMin(minArray[1], minArray[3]), SkTMax(maxArray[0], maxArray[2]), SkTMax(maxArray[1], maxArray[3])); } else { // we hit a non-finite value, so zero everything and return false this->setEmpty(); isFinite = false; } } return isFinite; }
bool SkDLine::nearRay(const SkDPoint& xy) const { // project a perpendicular ray from the point to the line; find the T on the line SkDVector len = fPts[1] - fPts[0]; // the x/y magnitudes of the line double denom = len.fX * len.fX + len.fY * len.fY; // see DLine intersectRay SkDVector ab0 = xy - fPts[0]; double numer = len.fX * ab0.fX + ab0.fY * len.fY; double t = numer / denom; SkDPoint realPt = ptAtT(t); double dist = realPt.distance(xy); // OPTIMIZATION: can we compare against distSq instead ? // find the ordinal in the original line with the largest unsigned exponent double tiniest = SkTMin(SkTMin(SkTMin(fPts[0].fX, fPts[0].fY), fPts[1].fX), fPts[1].fY); double largest = SkTMax(SkTMax(SkTMax(fPts[0].fX, fPts[0].fY), fPts[1].fX), fPts[1].fY); largest = SkTMax(largest, -tiniest); return RoughlyEqualUlps(largest, largest + dist); // is the dist within ULPS tolerance? }
int SkMipMap::ComputeLevelCount(int baseWidth, int baseHeight) { if (baseWidth < 1 || baseHeight < 1) { return 0; } // OpenGL's spec requires that each mipmap level have height/width equal to // max(1, floor(original_height / 2^i) // (or original_width) where i is the mipmap level. // Continue scaling down until both axes are size 1. const int largestAxis = SkTMax(baseWidth, baseHeight); if (largestAxis < 2) { // SkMipMap::Build requires a minimum size of 2. return 0; } const int leadingZeros = SkCLZ(static_cast<uint32_t>(largestAxis)); // If the value 00011010 has 3 leading 0s then it has 5 significant bits // (the bits which are not leading zeros) const int significantBits = (sizeof(uint32_t) * 8) - leadingZeros; // This is making the assumption that the size of a byte is 8 bits // and that sizeof(uint32_t)'s implementation-defined behavior is 4. int mipLevelCount = significantBits; // SkMipMap does not include the base mip level. // For example, it contains levels 1-x instead of 0-x. // This is because the image used to create SkMipMap is the base level. // So subtract 1 from the mip level count. if (mipLevelCount > 0) { --mipLevelCount; } return mipLevelCount; }
void draw_fill(SkCanvas* canvas, const SkRect& rect, SkScalar width) { if (rect.isEmpty()) { return; } SkPaint paint; paint.setColor(0x1f1f0f0f); paint.setStyle(SkPaint::kStroke_Style); paint.setStrokeWidth(width); SkPath path; SkScalar maxSide = SkTMax(rect.width(), rect.height()) / 2; SkPoint center = { rect.fLeft + maxSide, rect.fTop + maxSide }; path.addCircle(center.fX, center.fY, maxSide); canvas->drawPath(path, paint); paint.setStyle(SkPaint::kFill_Style); path.reset(); path.addCircle(center.fX, center.fY, maxSide - width / 2); paint.setColor(0x3f0f1f3f); canvas->drawPath(path, paint); path.reset(); path.setFillType(SkPath::kEvenOdd_FillType); path.addCircle(center.fX, center.fY, maxSide + width / 2); SkRect outside = SkRect::MakeXYWH(center.fX - maxSide - width, center.fY - maxSide - width, (maxSide + width) * 2, (maxSide + width) * 2); path.addRect(outside); canvas->drawPath(path, paint); }
// Note: if the newSize == kReadToEnd (0), this function will read to the end of stream. bool bufferMoreData(size_t newSize) { if (newSize == kReadToEnd) { if (fWholeStreamRead) { // already read-to-end. return true; } // TODO: optimize for the special case when the input is SkMemoryStream. return SkStreamCopy(&fStreamBuffer, fStream.get()); } if (newSize <= fStreamBuffer.bytesWritten()) { // already buffered to newSize return true; } if (fWholeStreamRead) { // newSize is larger than the whole stream. return false; } // Try to read at least 8192 bytes to avoid to many small reads. const size_t kMinSizeToRead = 8192; const size_t sizeRequested = newSize - fStreamBuffer.bytesWritten(); const size_t sizeToRead = SkTMax(kMinSizeToRead, sizeRequested); SkAutoSTMalloc<kMinSizeToRead, uint8> tempBuffer(sizeToRead); const size_t bytesRead = fStream->read(tempBuffer.get(), sizeToRead); if (bytesRead < sizeRequested) { return false; } return fStreamBuffer.write(tempBuffer.get(), bytesRead); }
void GrGLRenderTarget::init(const GrSurfaceDesc& desc, const IDDesc& idDesc) { fRTFBOID = idDesc.fRTFBOID; fTexFBOID = idDesc.fTexFBOID; fMSColorRenderbufferID = idDesc.fMSColorRenderbufferID; fIsWrapped = kWrapped_LifeCycle == idDesc.fLifeCycle; fViewport.fLeft = 0; fViewport.fBottom = 0; fViewport.fWidth = desc.fWidth; fViewport.fHeight = desc.fHeight; // We own one color value for each MSAA sample. int colorValuesPerPixel = SkTMax(1, fDesc.fSampleCnt); if (fTexFBOID != fRTFBOID) { // If we own the resolve buffer then that is one more sample per pixel. colorValuesPerPixel += 1; } else if (fTexFBOID != 0) { // For auto-resolving FBOs, the MSAA buffer is free. colorValuesPerPixel = 1; } SkASSERT(kUnknown_GrPixelConfig != fDesc.fConfig); SkASSERT(!GrPixelConfigIsCompressed(fDesc.fConfig)); size_t colorBytes = GrBytesPerPixel(fDesc.fConfig); SkASSERT(colorBytes > 0); fGpuMemorySize = colorValuesPerPixel * fDesc.fWidth * fDesc.fHeight * colorBytes; }
bool onQuery(SkEvent* evt) override { if (SampleCode::TitleQ(*evt)) { SampleCode::TitleR(evt, "QuadStroker"); return true; } SkUnichar uni; if (fTextButton.fEnabled && SampleCode::CharQ(*evt, &uni)) { switch (uni) { case ' ': fText = ""; break; case '-': fTextSize = SkTMax(1.0f, fTextSize - 1); break; case '+': case '=': fTextSize += 1; break; default: fText.appendUnichar(uni); } this->inval(NULL); return true; } return this->INHERITED::onQuery(evt); }
size_t GrVkStencilAttachment::onGpuMemorySize() const { uint64_t size = this->width(); size *= this->height(); size *= fFormat.fTotalBits; size *= SkTMax(1,this->numSamples()); return static_cast<size_t>(size / 8); }
template <int N, typename T> static double test_parse_fixed_r(skiatest::Reporter* reporter, double low, double high, double inc) { double SK_FixedMax_double = nextafter(1 << (sizeof(T) * CHAR_BIT - N - 1), 0.0); double SK_FixedEpsilon_double = (1.0 / (1 << N)); double maxError = 0; char buffer[64]; for (double f = low; f < high; f += inc) { SkString s; // 'sprintf' formatting as expected depends on the current locale being "C". // We currently expect tests and tools to run in the "C" locale. sprintf(buffer, "%.20f", f); T fix; bool b = parse_fixed<N>(buffer, &fix); if (b) { double f2 = fix * SK_FixedEpsilon_double; double error = fabs(f - f2); REPORTER_ASSERT(reporter, error <= SK_FixedEpsilon_double); maxError = SkTMax(maxError, error); } else { REPORTER_ASSERT(reporter, f < -SK_FixedMax_double || SK_FixedMax_double < f); } } //SkDebugf("maxError: %.20f\n", maxError); return maxError; }
uint32_t GrPathUtils::cubicPointCount(const SkPoint points[], SkScalar tol) { if (tol < gMinCurveTol) { tol = gMinCurveTol; } SkASSERT(tol > 0); SkScalar d = SkTMax( points[1].distanceToLineSegmentBetweenSqd(points[0], points[3]), points[2].distanceToLineSegmentBetweenSqd(points[0], points[3])); d = SkScalarSqrt(d); if (!SkScalarIsFinite(d)) { return MAX_POINTS_PER_CURVE; } else if (d <= tol) { return 1; } else { SkScalar divSqrt = SkScalarSqrt(d / tol); if (((SkScalar)SK_MaxS32) <= divSqrt) { return MAX_POINTS_PER_CURVE; } else { int temp = SkScalarCeilToInt(SkScalarSqrt(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 SkTMin(pow2, MAX_POINTS_PER_CURVE); } } }
// we subdivide the quads to avoid huge overfill // if it returns -1 then should be drawn as lines static int num_quad_subdivs(const SkPoint p[3]) { SkScalar dsqd; if (is_degen_quad_or_conic(p, &dsqd)) { return -1; } // tolerance of triangle height in pixels // tuned on windows Quadro FX 380 / Z600 // trade off of fill vs cpu time on verts // maybe different when do this using gpu (geo or tess shaders) static const SkScalar gSubdivTol = 175 * SK_Scalar1; if (dsqd <= SkScalarMul(gSubdivTol, gSubdivTol)) { return 0; } else { static const int kMaxSub = 4; // subdividing the quad reduces d by 4. so we want x = log4(d/tol) // = log4(d*d/tol*tol)/2 // = log2(d*d/tol*tol) // +1 since we're ignoring the mantissa contribution. int log = get_float_exp(dsqd/(gSubdivTol*gSubdivTol)) + 1; log = SkTMin(SkTMax(0, log), kMaxSub); return log; } }
bool GrAADistanceFieldPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const { // TODO: Support inverse fill if (!args.fShaderCaps->shaderDerivativeSupport() || !args.fAntiAlias || SkStrokeRec::kHairline_Style == args.fStroke->getStyle() || args.fPath->isInverseFillType() || args.fPath->isVolatile() || // We don't currently apply the dash or factor it into the DF key. (skbug.com/5082) args.fStroke->isDashed()) { return false; } // currently don't support perspective if (args.fViewMatrix->hasPerspective()) { return false; } // only support paths with bounds within kMediumMIP by kMediumMIP, // scaled to have bounds within 2.0f*kLargeMIP by 2.0f*kLargeMIP // the goal is to accelerate rendering of lots of small paths that may be scaling SkScalar maxScale = args.fViewMatrix->getMaxScale(); const SkRect& bounds = args.fPath->getBounds(); SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height()); // Approximate stroked size by adding the maximum of the stroke width or 2x the miter limit if (!args.fStroke->isFillStyle()) { SkScalar extraWidth = args.fStroke->getWidth(); if (SkPaint::kMiter_Join == args.fStroke->getJoin()) { extraWidth = SkTMax(extraWidth, 2.0f*args.fStroke->getMiter()); } maxDim += extraWidth; } return maxDim <= kMediumMIP && maxDim * maxScale <= 2.0f*kLargeMIP; }