Ejemplo n.º 1
0
void SkOpContour::joinCoincidence(const SkTArray<SkCoincidence, true>& coincidences, bool partial) {
    int count = coincidences.count();
#if DEBUG_CONCIDENT
    if (count > 0) {
        SkDebugf("%s count=%d\n", __FUNCTION__, count);
    }
#endif
    // look for a lineup where the partial implies another adjoining coincidence
    for (int index = 0; index < count; ++index) {
        const SkCoincidence& coincidence = coincidences[index];
        int thisIndex = coincidence.fSegments[0];
        SkOpSegment& thisOne = fSegments[thisIndex];
        if (thisOne.done()) {
            continue;
        }
        SkOpContour* otherContour = coincidence.fOther;
        int otherIndex = coincidence.fSegments[1];
        SkOpSegment& other = otherContour->fSegments[otherIndex];
        if (other.done()) {
            continue;
        }
        double startT = coincidence.fTs[0][0];
        double endT = coincidence.fTs[0][1];
        if (startT == endT) {  // this can happen in very large compares
            continue;
        }
        double oStartT = coincidence.fTs[1][0];
        double oEndT = coincidence.fTs[1][1];
        if (oStartT == oEndT) {
            continue;
        }
        bool swapStart = startT > endT;
        bool swapOther = oStartT > oEndT;
        const SkPoint* startPt = &coincidence.fPts[0][0];
        const SkPoint* endPt = &coincidence.fPts[0][1];
        if (swapStart) {
            SkTSwap(startT, endT);
            SkTSwap(oStartT, oEndT);
            SkTSwap(startPt, endPt);
        }
        bool cancel = swapOther != swapStart;
        int step = swapStart ? -1 : 1;
        int oStep = swapOther ? -1 : 1;
        double oMatchStart = cancel ? oEndT : oStartT;
        if (partial ? startT != 0 || oMatchStart != 0 : (startT == 0) != (oMatchStart == 0)) {
            bool added = false;
            if (oMatchStart != 0) {
                const SkPoint& oMatchStartPt = cancel ? *endPt : *startPt;
                added = thisOne.joinCoincidence(&other, oMatchStart, oMatchStartPt, oStep, cancel);
            }
            if (!cancel && startT != 0 && !added) {
                (void) other.joinCoincidence(&thisOne, startT, *startPt, step, cancel);
            }
        }
        double oMatchEnd = cancel ? oStartT : oEndT;
        if (partial ? endT != 1 || oMatchEnd != 1 : (endT == 1) != (oMatchEnd == 1)) {
            bool added = false;
            if (cancel && endT != 1 && !added) {
                (void) other.joinCoincidence(&thisOne, endT, *endPt, -step, cancel);
            }
        }
    }
}
Ejemplo n.º 2
0
void GrDrawTarget::drawBatch(const GrPipelineBuilder& pipelineBuilder,
                             GrDrawContext* drawContext,
                             const GrClip& clip,
                             GrDrawBatch* batch) {
    // Setup clip
    GrAppliedClip appliedClip;
    if (!clip.apply(fContext, pipelineBuilder, drawContext, &batch->bounds(), &appliedClip)) {
        return;
    }

    GrPipelineBuilder::AutoRestoreFragmentProcessorState arfps;
    if (appliedClip.clipCoverageFragmentProcessor()) {
        arfps.set(&pipelineBuilder);
        arfps.addCoverageFragmentProcessor(appliedClip.clipCoverageFragmentProcessor());
    }

    GrPipeline::CreateArgs args;
    args.fPipelineBuilder = &pipelineBuilder;
    args.fCaps = this->caps();
    args.fScissor = &appliedClip.scissorState();
    args.fHasStencilClip = appliedClip.hasStencilClip();
    if (pipelineBuilder.hasUserStencilSettings() || appliedClip.hasStencilClip()) {
        if (!fResourceProvider->attachStencilAttachment(pipelineBuilder.getRenderTarget())) {
            SkDebugf("ERROR creating stencil attachment. Draw skipped.\n");
            return;
        }
    }
    batch->getPipelineOptimizations(&args.fOpts);
    GrScissorState finalScissor;
    if (args.fOpts.fOverrides.fUsePLSDstRead || fClipBatchToBounds) {
        GrRenderTarget* rt = pipelineBuilder.getRenderTarget();
        GrGLIRect viewport;
        viewport.fLeft = 0;
        viewport.fBottom = 0;
        viewport.fWidth = rt->width();
        viewport.fHeight = rt->height();
        SkIRect ibounds;
        ibounds.fLeft = SkTPin(SkScalarFloorToInt(batch->bounds().fLeft), viewport.fLeft,
                              viewport.fWidth);
        ibounds.fTop = SkTPin(SkScalarFloorToInt(batch->bounds().fTop), viewport.fBottom,
                             viewport.fHeight);
        ibounds.fRight = SkTPin(SkScalarCeilToInt(batch->bounds().fRight), viewport.fLeft,
                               viewport.fWidth);
        ibounds.fBottom = SkTPin(SkScalarCeilToInt(batch->bounds().fBottom), viewport.fBottom,
                                viewport.fHeight);
        if (appliedClip.scissorState().enabled()) {
            const SkIRect& scissorRect = appliedClip.scissorState().rect();
            if (!ibounds.intersect(scissorRect)) {
                return;
            }
        }
        finalScissor.set(ibounds);
        args.fScissor = &finalScissor;
    }
    args.fOpts.fColorPOI.completeCalculations(pipelineBuilder.fColorFragmentProcessors.begin(),
                                              pipelineBuilder.numColorFragmentProcessors());
    args.fOpts.fCoveragePOI.completeCalculations(
                                               pipelineBuilder.fCoverageFragmentProcessors.begin(),
                                               pipelineBuilder.numCoverageFragmentProcessors());
    if (!this->setupDstReadIfNecessary(pipelineBuilder, clip, args.fOpts, &args.fDstTexture,
                                       batch->bounds())) {
        return;
    }

    if (!batch->installPipeline(args)) {
        return;
    }

#ifdef ENABLE_MDB
    SkASSERT(fRenderTarget);
    batch->pipeline()->addDependenciesTo(fRenderTarget);
#endif

    this->recordBatch(batch);
}
Ejemplo n.º 3
0
void ShowOp(SkPathOp op, const char* pathOne, const char* pathTwo) {
    SkDebugf("    testPathOp(reporter, %s, %s, %s);\n", pathOne, pathTwo, gOpStrs[op]);
    SkDebugf("}\n");
}
Ejemplo n.º 4
0
void TestResult::testOne() {
    SkPicture* pic = nullptr;
    {
        SkString d;
        d.printf("    {%d, \"%s\"},", fDirNo, fFilename);
        SkString path = make_filepath(fDirNo, IN_DIR, fFilename);
        SkFILEStream stream(path.c_str());
        if (!stream.isValid()) {
            SkDebugf("invalid stream %s\n", path.c_str());
            goto finish;
        }
        if (fTestStep == kEncodeFiles) {
            size_t length = stream.getLength();
            SkTArray<char, true> bytes;
            bytes.push_back_n(length);
            stream.read(&bytes[0], length);
            stream.rewind();
            SkString wPath = make_filepath(0, outSkpDir, fFilename);
            SkFILEWStream wStream(wPath.c_str());
            wStream.write(&bytes[0], length);
            wStream.flush();
        }
        pic = SkPicture::CreateFromStream(&stream, &SkImageDecoder::DecodeMemory);
        if (!pic) {
            SkDebugf("unable to decode %s\n", fFilename);
            goto finish;
        }
        int pWidth = pic->width();
        int pHeight = pic->height();
        int pLargerWH = SkTMax(pWidth, pHeight);
        GrContextFactory contextFactory;
#ifdef SK_BUILD_FOR_WIN
        GrContext* context = contextFactory.get(kAngle);
#else
        GrContext* context = contextFactory.get(kNative);
#endif
        if (nullptr == context) {
            SkDebugf("unable to allocate context for %s\n", fFilename);
            goto finish;
        }
        int maxWH = context->getMaxRenderTargetSize();
        int scale = 1;
        while (pLargerWH / scale > maxWH) {
            scale *= 2;
        }
        SkBitmap bitmap;
        SkIPoint dim;
        do {
            dim.fX = (pWidth + scale - 1) / scale;
            dim.fY = (pHeight + scale - 1) / scale;
            bool success = bitmap.allocN32Pixels(dim.fX, dim.fY);
            if (success) {
                break;
            }
            SkDebugf("-%d-", scale);
        } while ((scale *= 2) < 256);
        if (scale >= 256) {
            SkDebugf("unable to allocate bitmap for %s (w=%d h=%d) (sw=%d sh=%d)\n",
                    fFilename, pWidth, pHeight, dim.fX, dim.fY);
            goto finish;
        }
        SkCanvas skCanvas(bitmap);
        drawPict(pic, &skCanvas, fScaleOversized ? scale : 1);
        GrTextureDesc desc;
        desc.fConfig = kSkia8888_GrPixelConfig;
        desc.fFlags = kRenderTarget_GrTextureFlagBit;
        desc.fWidth = dim.fX;
        desc.fHeight = dim.fY;
        desc.fSampleCnt = 0;
        SkAutoTUnref<GrTexture> texture(context->createUncachedTexture(desc, nullptr, 0));
        if (!texture) {
            SkDebugf("unable to allocate texture for %s (w=%d h=%d)\n", fFilename,
                dim.fX, dim.fY);
            goto finish;
        }
        SkGpuDevice grDevice(context, texture.get());
        SkCanvas grCanvas(&grDevice);
        drawPict(pic, &grCanvas, fScaleOversized ? scale : 1);

        SkBitmap grBitmap;
        grBitmap.allocPixels(grCanvas.imageInfo());
        grCanvas.readPixels(&grBitmap, 0, 0);

        if (fTestStep == kCompareBits) {
            fPixelError = similarBits(grBitmap, bitmap);
            int skTime = timePict(pic, &skCanvas);
            int grTime = timePict(pic, &grCanvas);
            fTime = skTime - grTime;
        } else if (fTestStep == kEncodeFiles) {
            SkString pngStr = make_png_name(fFilename);
            const char* pngName = pngStr.c_str();
            writePict(grBitmap, outGrDir, pngName);
            writePict(bitmap, outSkDir, pngName);
        }
    }
finish:
    delete pic;
}
Ejemplo n.º 5
0
DEF_TEST(SkpSkGrThreaded, reporter) {
    if (!initTest()) {
        return;
    }
    SkpSkGrThreadedTestRunner testRunner(reporter);
    for (int dirIndex = 1; dirIndex <= 100; ++dirIndex) {
        SkString pictDir = make_in_dir_name(dirIndex);
        if (pictDir.size() == 0) {
            continue;
        }
        SkOSFile::Iter iter(pictDir.c_str(), "skp");
        SkString filename;
        while (iter.next(&filename)) {
            SkString pngName = make_png_name(filename.c_str());
            SkString oldPng = make_filepath(dirIndex, outSkDir, pngName.c_str());
            SkString newPng = make_filepath(dirIndex, outGrDir, pngName.c_str());
            if (sk_exists(oldPng.c_str()) && sk_exists(newPng.c_str())) {
                bumpCount(reporter, true);
                continue;
            }
            for (size_t index = 0; index < skipOverSkGrCount; ++index) {
                if (skipOverSkGr[index].directory == dirIndex
                        && strcmp(filename.c_str(), skipOverSkGr[index].filename) == 0) {
                    bumpCount(reporter, true);
                    goto skipOver;
                }
            }
            *testRunner.fRunnables.append() = new SkpSkGrThreadedRunnable(
                    &testSkGrMain, dirIndex, filename.c_str(), &testRunner);
    skipOver:
            ;
        }
    }
    testRunner.render();
    SkpSkGrThreadState& max = testRunner.fRunnables[0]->fState;
    for (int dirIndex = 2; dirIndex <= 100; ++dirIndex) {
        SkpSkGrThreadState& state = testRunner.fRunnables[dirIndex - 1]->fState;
        for (int index = 0; index < state.fFoundCount; ++index) {
            int maxIdx = max.fFoundCount;
            if (maxIdx < kMaxFiles) {
                max.fError[maxIdx] = state.fError[index];
                strcpy(max.fFilesFound[maxIdx], state.fFilesFound[index]);
                max.fDirsFound[maxIdx] = state.fDirsFound[index];
                ++max.fFoundCount;
                continue;
            }
            for (maxIdx = 0; maxIdx < max.fFoundCount; ++maxIdx) {
                if (max.fError[maxIdx] < state.fError[index]) {
                    max.fError[maxIdx] = state.fError[index];
                    strcpy(max.fFilesFound[maxIdx], state.fFilesFound[index]);
                    max.fDirsFound[maxIdx] = state.fDirsFound[index];
                    break;
                }
            }
        }
    }
    TestResult encoder;
    encoder.fTestStep = kEncodeFiles;
    for (int index = 0; index < max.fFoundCount; ++index) {
        encoder.fDirNo = max.fDirsFound[index];
        strcpy(encoder.fFilename, max.fFilesFound[index]);
        encoder.testOne();
        SkDebugf("+");
    }
}
Ejemplo n.º 6
0
SkOpSegment* FindChase(SkTDArray<SkOpSpan*>* chase, int* tIndex, int* endIndex) {
    while (chase->count()) {
        SkOpSpan* span;
        chase->pop(&span);
        const SkOpSpan& backPtr = span->fOther->span(span->fOtherIndex);
        SkOpSegment* segment = backPtr.fOther;
        *tIndex = backPtr.fOtherIndex;
        bool sortable = true;
        bool done = true;
        *endIndex = -1;
        if (const SkOpAngle* last = segment->activeAngle(*tIndex, tIndex, endIndex, &done,
                &sortable)) {
            *tIndex = last->start();
            *endIndex = last->end();
    #if TRY_ROTATE
            *chase->insert(0) = span;
    #else
            *chase->append() = span;
    #endif
            return last->segment();
        }
        if (done) {
            continue;
        }
        if (!sortable) {
            continue;
        }
        // find first angle, initialize winding to computed wind sum
        const SkOpAngle* angle = segment->spanToAngle(*tIndex, *endIndex);
        const SkOpAngle* firstAngle;
        SkDEBUGCODE(firstAngle = angle);
        SkDEBUGCODE(bool loop = false);
        int winding;
        do {
            angle = angle->next();
            SkASSERT(angle != firstAngle || !loop);
            SkDEBUGCODE(loop |= angle == firstAngle);
            segment = angle->segment();
            winding = segment->windSum(angle);
        } while (winding == SK_MinS32);
        int spanWinding = segment->spanSign(angle->start(), angle->end());
    #if DEBUG_WINDING
        SkDebugf("%s winding=%d spanWinding=%d\n", __FUNCTION__, winding, spanWinding);
    #endif
        // turn span winding into contour winding
        if (spanWinding * winding < 0) {
            winding += spanWinding;
        }
        // we care about first sign and whether wind sum indicates this
        // edge is inside or outside. Maybe need to pass span winding
        // or first winding or something into this function?
        // advance to first undone angle, then return it and winding
        // (to set whether edges are active or not)
        firstAngle = angle;
        winding -= firstAngle->segment()->spanSign(firstAngle);
        while ((angle = angle->next()) != firstAngle) {
            segment = angle->segment();
            int maxWinding = winding;
            winding -= segment->spanSign(angle);
    #if DEBUG_SORT
            SkDebugf("%s id=%d maxWinding=%d winding=%d sign=%d\n", __FUNCTION__,
                    segment->debugID(), maxWinding, winding, angle->sign());
    #endif
            *tIndex = angle->start();
            *endIndex = angle->end();
            int lesser = SkMin32(*tIndex, *endIndex);
            const SkOpSpan& nextSpan = segment->span(lesser);
            if (!nextSpan.fDone) {
            // FIXME: this be wrong? assign startWinding if edge is in
            // same direction. If the direction is opposite, winding to
            // assign is flipped sign or +/- 1?
                if (SkOpSegment::UseInnerWinding(maxWinding, winding)) {
                    maxWinding = winding;
                }
                // allowed to do nothing
                (void) segment->markAndChaseWinding(angle, maxWinding, 0, NULL);
                break;
            }
        }
        *chase->insert(0) = span;
        return segment;
    }
    return NULL;
}
Ejemplo n.º 7
0
static int contourRangeCheckY(const SkTArray<SkOpContour*, true>& contourList, SkOpSegment** currentPtr,
                              int* indexPtr, int* endIndexPtr, double* bestHit, SkScalar* bestDx,
                              bool* tryAgain, double* midPtr, bool opp) {
    const int index = *indexPtr;
    const int endIndex = *endIndexPtr;
    const double mid = *midPtr;
    const SkOpSegment* current = *currentPtr;
    double tAtMid = current->tAtMid(index, endIndex, mid);
    SkPoint basePt = current->ptAtT(tAtMid);
    int contourCount = contourList.count();
    SkScalar bestY = SK_ScalarMin;
    SkOpSegment* bestSeg = NULL;
    int bestTIndex = 0;
    bool bestOpp;
    bool hitSomething = false;
    for (int cTest = 0; cTest < contourCount; ++cTest) {
        SkOpContour* contour = contourList[cTest];
        bool testOpp = contour->operand() ^ current->operand() ^ opp;
        if (basePt.fY < contour->bounds().fTop) {
            continue;
        }
        if (bestY > contour->bounds().fBottom) {
            continue;
        }
        int segmentCount = contour->segments().count();
        for (int test = 0; test < segmentCount; ++test) {
            SkOpSegment* testSeg = &contour->segments()[test];
            SkScalar testY = bestY;
            double testHit;
            int testTIndex = testSeg->crossedSpanY(basePt, &testY, &testHit, &hitSomething, tAtMid,
                    testOpp, testSeg == current);
            if (testTIndex < 0) {
                if (testTIndex == SK_MinS32) {
                    hitSomething = true;
                    bestSeg = NULL;
                    goto abortContours;  // vertical encountered, return and try different point
                }
                continue;
            }
            if (testSeg == current && current->betweenTs(index, testHit, endIndex)) {
                double baseT = current->t(index);
                double endT = current->t(endIndex);
                double newMid = (testHit - baseT) / (endT - baseT);
#if DEBUG_WINDING
                double midT = current->tAtMid(index, endIndex, mid);
                SkPoint midXY = current->xyAtT(midT);
                double newMidT = current->tAtMid(index, endIndex, newMid);
                SkPoint newXY = current->xyAtT(newMidT);
                SkDebugf("%s [%d] mid=%1.9g->%1.9g s=%1.9g (%1.9g,%1.9g) m=%1.9g (%1.9g,%1.9g)"
                        " n=%1.9g (%1.9g,%1.9g) e=%1.9g (%1.9g,%1.9g)\n", __FUNCTION__,
                        current->debugID(), mid, newMid,
                        baseT, current->xAtT(index), current->yAtT(index),
                        baseT + mid * (endT - baseT), midXY.fX, midXY.fY,
                        baseT + newMid * (endT - baseT), newXY.fX, newXY.fY,
                        endT, current->xAtT(endIndex), current->yAtT(endIndex));
#endif
                *midPtr = newMid * 2;  // calling loop with divide by 2 before continuing
                return SK_MinS32;
            }
            bestSeg = testSeg;
            *bestHit = testHit;
            bestOpp = testOpp;
            bestTIndex = testTIndex;
            bestY = testY;
        }
    }
abortContours:
    int result;
    if (!bestSeg) {
        result = hitSomething ? SK_MinS32 : 0;
    } else {
        if (bestSeg->windSum(bestTIndex) == SK_MinS32) {
            *currentPtr = bestSeg;
            *indexPtr = bestTIndex;
            *endIndexPtr = bestSeg->nextSpan(bestTIndex, 1);
            SkASSERT(*indexPtr != *endIndexPtr && *indexPtr >= 0 && *endIndexPtr >= 0);
            *tryAgain = true;
            return 0;
        }
        result = bestSeg->windingAtT(*bestHit, bestTIndex, bestOpp, bestDx);
        SkASSERT(result == SK_MinS32 || *bestDx);
    }
    double baseT = current->t(index);
    double endT = current->t(endIndex);
    *bestHit = baseT + mid * (endT - baseT);
    return result;
}
Ejemplo n.º 8
0
/**
 *  Test decoding an image in premultiplied mode and unpremultiplied mode and compare
 *  them.
 */
static void compare_unpremul(skiatest::Reporter* reporter, const SkString& filename) {
    // Decode a resource:
    SkBitmap bm8888;
    SkBitmap bm8888Unpremul;

    SkFILEStream stream(filename.c_str());

    SkImageDecoder::Format format = SkImageDecoder::GetStreamFormat(&stream);
    if (skip_image_format(format)) {
        return;
    }

    SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(&stream));
    if (NULL == decoder.get()) {
        SkDebugf("couldn't decode %s\n", filename.c_str());
        return;
    }

    bool success = decoder->decode(&stream, &bm8888, kN32_SkColorType,
                                   SkImageDecoder::kDecodePixels_Mode) != SkImageDecoder::kFailure;
    if (!success) {
        return;
    }

    success = stream.rewind();
    REPORTER_ASSERT(reporter, success);
    if (!success) {
        return;
    }

    decoder->setRequireUnpremultipliedColors(true);
    success = decoder->decode(&stream, &bm8888Unpremul, kN32_SkColorType,
                              SkImageDecoder::kDecodePixels_Mode) != SkImageDecoder::kFailure;
    if (!success) {
        return;
    }

    bool dimensionsMatch = bm8888.width() == bm8888Unpremul.width()
                           && bm8888.height() == bm8888Unpremul.height();
    REPORTER_ASSERT(reporter, dimensionsMatch);
    if (!dimensionsMatch) {
        return;
    }

    // Only do the comparison if the two bitmaps are both 8888.
    if (bm8888.colorType() != kN32_SkColorType || bm8888Unpremul.colorType() != kN32_SkColorType) {
        return;
    }

    // Now compare the two bitmaps.
    for (int i = 0; i < bm8888.width(); ++i) {
        for (int j = 0; j < bm8888.height(); ++j) {
            // "c0" is the color of the premultiplied bitmap at (i, j).
            const SkPMColor c0 = *bm8888.getAddr32(i, j);
            // "c1" is the result of premultiplying the color of the unpremultiplied
            // bitmap at (i, j).
            const SkPMColor c1 = premultiply_unpmcolor(*bm8888Unpremul.getAddr32(i, j));
            // Compute the difference for each component.
            int da = SkAbs32(SkGetPackedA32(c0) - SkGetPackedA32(c1));
            int dr = SkAbs32(SkGetPackedR32(c0) - SkGetPackedR32(c1));
            int dg = SkAbs32(SkGetPackedG32(c0) - SkGetPackedG32(c1));
            int db = SkAbs32(SkGetPackedB32(c0) - SkGetPackedB32(c1));

            // Alpha component must be exactly the same.
            REPORTER_ASSERT(reporter, 0 == da);

            // Color components may not match exactly due to rounding error.
            REPORTER_ASSERT(reporter, dr <= 1);
            REPORTER_ASSERT(reporter, dg <= 1);
            REPORTER_ASSERT(reporter, db <= 1);
        }
    }
}
 ~MyObserver() {
     if (fCount != 0) {
         SkDebugf("--- pvjpeg left %d allocations\n", fCount);
     }
 }
Ejemplo n.º 10
0
void draw(SkCanvas* canvas) {
    SkIPoint pt1 = {45, 66};
    SkIPoint pt2 = SkIPoint::Make(45, 66);
    SkDebugf("pt1 %c= pt2\n", pt1 == pt2 ? '=' : '!');
}
Ejemplo n.º 11
0
// Using known images, test that decoding into unpremul and premul behave as expected.
DEF_TEST(ImageDecoding_unpremul, reporter) {
    SkString resourcePath = GetResourcePath();
    if (resourcePath.isEmpty()) {
        SkDebugf("Could not run unpremul test because resourcePath not specified.");
        return;
    }
    const char* root = "half-transparent-white-pixel";
    const char* suffixes[] = { ".png", ".webp" };

    for (size_t i = 0; i < SK_ARRAY_COUNT(suffixes); ++i) {
        SkString basename = SkStringPrintf("%s%s", root, suffixes[i]);
        SkString fullName = SkOSPath::Join(resourcePath.c_str(), basename.c_str());

        SkBitmap bm;
        SkFILEStream stream(fullName.c_str());

        if (!stream.isValid()) {
            SkDebugf("file %s missing from resource directoy %s\n",
                     basename.c_str(), resourcePath.c_str());
            continue;
        }

        // This should never fail since we know the images we're decoding.
        SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(&stream));
        REPORTER_ASSERT(reporter, decoder.get());
        if (NULL == decoder.get()) {
            continue;
        }

        // Test unpremultiplied. We know what color this should result in.
        decoder->setRequireUnpremultipliedColors(true);
        bool success = decoder->decode(&stream, &bm, kN32_SkColorType,
                                       SkImageDecoder::kDecodePixels_Mode);
        REPORTER_ASSERT(reporter, success);
        if (!success) {
            continue;
        }

        REPORTER_ASSERT(reporter, bm.width() == 1 && bm.height() == 1);
        {
            SkAutoLockPixels alp(bm);
            REPORTER_ASSERT(reporter, bm.getAddr32(0, 0)[0] == 0x7fffffff);
        }

        success = stream.rewind();
        REPORTER_ASSERT(reporter, success);
        if (!success) {
            continue;
        }

        // Test premultiplied. Once again, we know which color this should
        // result in.
        decoder->setRequireUnpremultipliedColors(false);
        success = decoder->decode(&stream, &bm, kN32_SkColorType,
                                  SkImageDecoder::kDecodePixels_Mode);
        REPORTER_ASSERT(reporter, success);
        if (!success) {
            continue;
        }

        REPORTER_ASSERT(reporter, bm.width() == 1 && bm.height() == 1);
        {
            SkAutoLockPixels alp(bm);
            REPORTER_ASSERT(reporter, bm.getAddr32(0, 0)[0] == 0x7f7f7f7f);
        }
    }
}
Ejemplo n.º 12
0
static void TestPathMeasure(skiatest::Reporter* reporter) {
    SkPath  path;

    path.moveTo(0, 0);
    path.lineTo(SK_Scalar1, 0);
    path.lineTo(SK_Scalar1, SK_Scalar1);
    path.lineTo(0, SK_Scalar1);

    SkPathMeasure   meas(path, true);
    SkScalar        length = meas.getLength();
    SkASSERT(length == SK_Scalar1*4);

    path.reset();
    path.moveTo(0, 0);
    path.lineTo(SK_Scalar1*3, SK_Scalar1*4);
    meas.setPath(&path, false);
    length = meas.getLength();
    REPORTER_ASSERT(reporter, length == SK_Scalar1*5);

    path.reset();
    path.addCircle(0, 0, SK_Scalar1);
    meas.setPath(&path, true);
    length = meas.getLength();
//    SkDebugf("circle arc-length = %g\n", length);

    for (int i = 0; i < 8; i++) {
        SkScalar    d = length * i / 8;
        SkPoint     p;
        SkVector    v;
        meas.getPosTan(d, &p, &v);
#if 0
        SkDebugf("circle arc-length=%g, pos[%g %g] tan[%g %g]\n",
                 d, p.fX, p.fY, v.fX, v.fY);
#endif
    }

    // Test the behavior following a close not followed by a move.
    path.reset();
    path.lineTo(SK_Scalar1, 0);
    path.lineTo(SK_Scalar1, SK_Scalar1);
    path.lineTo(0, SK_Scalar1);
    path.close();
    path.lineTo(-SK_Scalar1, 0);
    meas.setPath(&path, false);
    length = meas.getLength();
    REPORTER_ASSERT(reporter, length == SK_Scalar1 * 4);
    meas.nextContour();
    length = meas.getLength();
    REPORTER_ASSERT(reporter, length == SK_Scalar1);
    SkPoint position;
    SkVector tangent;
    REPORTER_ASSERT(reporter, meas.getPosTan(SK_ScalarHalf, &position, &tangent));
    REPORTER_ASSERT(reporter,
        SkScalarNearlyEqual(position.fX, -SK_ScalarHalf, SK_Scalar1 * 0.0001));
    REPORTER_ASSERT(reporter, position.fY == 0);
    REPORTER_ASSERT(reporter, tangent.fX == -SK_Scalar1);
    REPORTER_ASSERT(reporter, tangent.fY == 0);

    // Test degenerate paths
    path.reset();
    path.moveTo(0, 0);
    path.lineTo(0, 0);
    path.lineTo(SK_Scalar1, 0);
    path.quadTo(SK_Scalar1, 0, SK_Scalar1, 0);
    path.quadTo(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1 * 2);
    path.cubicTo(SK_Scalar1, SK_Scalar1 * 2,
                 SK_Scalar1, SK_Scalar1 * 2,
                 SK_Scalar1, SK_Scalar1 * 2);
    path.cubicTo(SK_Scalar1*2, SK_Scalar1 * 2,
                 SK_Scalar1*3, SK_Scalar1 * 2,
                 SK_Scalar1*4, SK_Scalar1 * 2);
    meas.setPath(&path, false);
    length = meas.getLength();
    REPORTER_ASSERT(reporter, length == SK_Scalar1 * 6);
    REPORTER_ASSERT(reporter, meas.getPosTan(SK_ScalarHalf, &position, &tangent));
    REPORTER_ASSERT(reporter,
        SkScalarNearlyEqual(position.fX, SK_ScalarHalf, SK_Scalar1 * 0.0001));
    REPORTER_ASSERT(reporter, position.fY == 0);
    REPORTER_ASSERT(reporter, tangent.fX == SK_Scalar1);
    REPORTER_ASSERT(reporter, tangent.fY == 0);
    REPORTER_ASSERT(reporter, meas.getPosTan(SK_Scalar1 * 2.5f, &position, &tangent));
    REPORTER_ASSERT(reporter,
        SkScalarNearlyEqual(position.fX, SK_Scalar1, SK_Scalar1 * 0.0001));
    REPORTER_ASSERT(reporter,
        SkScalarNearlyEqual(position.fY, SK_Scalar1 * 1.5f));
    REPORTER_ASSERT(reporter, tangent.fX == 0);
    REPORTER_ASSERT(reporter, tangent.fY == SK_Scalar1);
    REPORTER_ASSERT(reporter, meas.getPosTan(SK_Scalar1 * 4.5f, &position, &tangent));
    REPORTER_ASSERT(reporter,
        SkScalarNearlyEqual(position.fX, SK_Scalar1 * 2.5f, SK_Scalar1 * 0.0001));
    REPORTER_ASSERT(reporter,
        SkScalarNearlyEqual(position.fY, SK_Scalar1 * 2.0f, SK_Scalar1 * 0.0001));
    REPORTER_ASSERT(reporter, tangent.fX == SK_Scalar1);
    REPORTER_ASSERT(reporter, tangent.fY == 0);

    path.reset();
    path.moveTo(0, 0);
    path.lineTo(SK_Scalar1, 0);
    path.moveTo(SK_Scalar1, SK_Scalar1);
    path.moveTo(SK_Scalar1 * 2, SK_Scalar1 * 2);
    path.lineTo(SK_Scalar1, SK_Scalar1 * 2);
    meas.setPath(&path, false);
    length = meas.getLength();
    REPORTER_ASSERT(reporter, length == SK_Scalar1);
    REPORTER_ASSERT(reporter, meas.getPosTan(SK_ScalarHalf, &position, &tangent));
    REPORTER_ASSERT(reporter,
        SkScalarNearlyEqual(position.fX, SK_ScalarHalf, SK_Scalar1 * 0.0001));
    REPORTER_ASSERT(reporter, position.fY == 0);
    REPORTER_ASSERT(reporter, tangent.fX == SK_Scalar1);
    REPORTER_ASSERT(reporter, tangent.fY == 0);
    meas.nextContour();
    length = meas.getLength();
    REPORTER_ASSERT(reporter, length == SK_Scalar1);
    REPORTER_ASSERT(reporter, meas.getPosTan(SK_ScalarHalf, &position, &tangent));
    REPORTER_ASSERT(reporter,
        SkScalarNearlyEqual(position.fX, SK_Scalar1 * 1.5f, SK_Scalar1 * 0.0001));
    REPORTER_ASSERT(reporter,
        SkScalarNearlyEqual(position.fY, SK_Scalar1 * 2.0f, SK_Scalar1 * 0.0001));
    REPORTER_ASSERT(reporter, tangent.fX == -SK_Scalar1);
    REPORTER_ASSERT(reporter, tangent.fY == 0);
}
SkPixelRef* SkCreateRLEPixelRef(const SkBitmap& src) {
    
    if (SkBitmap::kIndex8_Config != src.config() &&
            SkBitmap::kA8_Config != src.config()) {
        return NULL;
    }
    
    size_t maxPacked = SkPackBits::ComputeMaxSize8(src.width());

    // estimate the rle size based on the original size
    size_t size = src.getSize() >> 3;
    if (size < maxPacked) {
        size = maxPacked;
    }

    ChunkRLEPixels* rlePixels = SkNEW_ARGS(ChunkRLEPixels,
                                           (src.width(), src.height(), size));

    uint8_t* dstRow = NULL;
    size_t free = 0;
    size_t totalPacked = 0;

    for (int y = 0; y < src.height(); y++) {
        const uint8_t* srcRow = src.getAddr8(0, y);
        
        if (free < maxPacked) {
            dstRow = (uint8_t*)rlePixels->fStorage.allocThrow(size);
            free = size;
        }
        size_t packedSize = SkPackBits::Pack8(srcRow, src.width(), dstRow);
        SkASSERT(packedSize <= free);
        rlePixels->setPackedAtY(y, dstRow);
        
        dstRow += packedSize;
        free -= packedSize;
        
        totalPacked += packedSize;
    }
    
//#ifdef SK_DEBUG
#if 0
    // test
    uint8_t* buffer = new uint8_t[src.width()];
    for (int y = 0; y < src.height(); y++) {
        const uint8_t* srcRow = src.getAddr8(0, y);
        SkPackBits::Unpack8(buffer, 0, src.width(), rlePixels->packedAtY(y));
        int n = memcmp(buffer, srcRow, src.width());
        if (n) {
            SkDebugf("----- memcmp returned %d on line %d\n", n, y);
        }
        SkASSERT(n == 0);
    }
    delete[] buffer;

    size_t totalAlloc = src.height() * sizeof(uint8_t*) + totalPacked;
    
    SkDebugf("--- RLE: orig [%d %d] %d, rle %d %d savings %g\n",
             src.width(), src.height(), src.getSize(),
             src.height() * sizeof(uint8_t*), totalPacked,
             (float)totalAlloc / src.getSize());

#endif

    // transfer ownership of rlePixels to our pixelref
    return SkNEW_ARGS(RLEPixelRef, (rlePixels, src.getColorTable()));
}
Ejemplo n.º 14
0
static void intersectionFinder(int index0, int index1, double t1Seed, double t2Seed,
        double t1Step, double t2Step) {
    const SkDCubic& cubic1 = newTestSet[index0];
    const SkDCubic& cubic2 = newTestSet[index1];
    SkDPoint t1[3], t2[3];
    bool toggle = true;
    do {
        t1[0] = cubic1.ptAtT(t1Seed - t1Step);
        t1[1] = cubic1.ptAtT(t1Seed);
        t1[2] = cubic1.ptAtT(t1Seed + t1Step);
        t2[0] = cubic2.ptAtT(t2Seed - t2Step);
        t2[1] = cubic2.ptAtT(t2Seed);
        t2[2] = cubic2.ptAtT(t2Seed + t2Step);
        double dist[3][3];
        dist[1][1] = t1[1].distance(t2[1]);
        int best_i = 1, best_j = 1;
        for (int i = 0; i < 3; ++i) {
            for (int j = 0; j < 3; ++j) {
                if (i == 1 && j == 1) {
                    continue;
                }
                dist[i][j] = t1[i].distance(t2[j]);
                if (dist[best_i][best_j] > dist[i][j]) {
                    best_i = i;
                    best_j = j;
                }
            }
        }
        if (best_i == 0) {
            t1Seed -= t1Step;
        } else if (best_i == 2) {
            t1Seed += t1Step;
        }
        if (best_j == 0) {
            t2Seed -= t2Step;
        } else if (best_j == 2) {
            t2Seed += t2Step;
        }
        if (best_i == 1 && best_j == 1) {
            if ((toggle ^= true)) {
                t1Step /= 2;
            } else {
                t2Step /= 2;
            }
        }
    } while (!t1[1].approximatelyEqual(t2[1]));
    t1Step = t2Step = 0.1;
    double t10 = t1Seed - t1Step * 2;
    double t12 = t1Seed + t1Step * 2;
    double t20 = t2Seed - t2Step * 2;
    double t22 = t2Seed + t2Step * 2;
    SkDPoint test;
    while (!approximately_zero(t1Step)) {
        test = cubic1.ptAtT(t10);
        t10 += t1[1].approximatelyEqual(test) ? -t1Step : t1Step;
        t1Step /= 2;
    }
    t1Step = 0.1;
    while (!approximately_zero(t1Step)) {
        test = cubic1.ptAtT(t12);
        t12 -= t1[1].approximatelyEqual(test) ? -t1Step : t1Step;
        t1Step /= 2;
    }
    while (!approximately_zero(t2Step)) {
        test = cubic2.ptAtT(t20);
        t20 += t2[1].approximatelyEqual(test) ? -t2Step : t2Step;
        t2Step /= 2;
    }
    t2Step = 0.1;
    while (!approximately_zero(t2Step)) {
        test = cubic2.ptAtT(t22);
        t22 -= t2[1].approximatelyEqual(test) ? -t2Step : t2Step;
        t2Step /= 2;
    }
#if ONE_OFF_DEBUG
    SkDebugf("%s t1=(%1.9g<%1.9g<%1.9g) t2=(%1.9g<%1.9g<%1.9g)\n", __FUNCTION__,
        t10, t1Seed, t12, t20, t2Seed, t22);
    SkDPoint p10 = cubic1.ptAtT(t10);
    SkDPoint p1Seed = cubic1.ptAtT(t1Seed);
    SkDPoint p12 = cubic1.ptAtT(t12);
    SkDebugf("%s p1=(%1.9g,%1.9g)<(%1.9g,%1.9g)<(%1.9g,%1.9g)\n", __FUNCTION__,
        p10.fX, p10.fY, p1Seed.fX, p1Seed.fY, p12.fX, p12.fY);
    SkDPoint p20 = cubic2.ptAtT(t20);
    SkDPoint p2Seed = cubic2.ptAtT(t2Seed);
    SkDPoint p22 = cubic2.ptAtT(t22);
    SkDebugf("%s p2=(%1.9g,%1.9g)<(%1.9g,%1.9g)<(%1.9g,%1.9g)\n", __FUNCTION__,
        p20.fX, p20.fY, p2Seed.fX, p2Seed.fY, p22.fX, p22.fY);
#endif
}
Ejemplo n.º 15
0
static int filter_picture(const SkString& inFile, const SkString& outFile) {
    SkAutoTDelete<SkPicture> inPicture;

    SkFILEStream inStream(inFile.c_str());
    if (inStream.isValid()) {
        inPicture.reset(SkPicture::CreateFromStream(&inStream));
    }

    if (NULL == inPicture.get()) {
        SkDebugf("Could not read file %s\n", inFile.c_str());
        return -1;
    }

    int localCount[SK_ARRAY_COUNT(gOptTable)];

    memset(localCount, 0, sizeof(localCount));

    SkDebugCanvas debugCanvas(inPicture->width(), inPicture->height());
    debugCanvas.setBounds(inPicture->width(), inPicture->height());
    inPicture->draw(&debugCanvas);

    // delete the initial save and restore since replaying the commands will
    // re-add them
    if (debugCanvas.getSize() > 1) {
        debugCanvas.deleteDrawCommandAt(0);
        debugCanvas.deleteDrawCommandAt(debugCanvas.getSize()-1);
    }

    bool changed = true;
    int numBefore = debugCanvas.getSize();

    while (changed) {
        changed = false;
        for (int i = 0; i < debugCanvas.getSize(); ++i) {
            for (size_t opt = 0; opt < SK_ARRAY_COUNT(gOptTable); ++opt) {
                if ((*gOptTable[opt].fCheck)(&debugCanvas, i)) {
                    (*gOptTable[opt].fApply)(&debugCanvas, i);

                    ++gOptTable[opt].fNumTimesApplied;
                    ++localCount[opt];

                    if (debugCanvas.getSize() == i) {
                        // the optimization removed all the remaining operations
                        break;
                    }

                    opt = 0;          // try all the opts all over again
                    changed = true;
                }
            }
        }
    }

    int numAfter = debugCanvas.getSize();

    if (!outFile.isEmpty()) {
        SkPictureRecorder recorder;
        SkCanvas* canvas = recorder.beginRecording(inPicture->width(), inPicture->height(), NULL, 0);
        debugCanvas.draw(canvas);
        SkAutoTUnref<SkPicture> outPicture(recorder.endRecording());

        SkFILEWStream outStream(outFile.c_str());

        outPicture->serialize(&outStream);
    }

    bool someOptFired = false;
    for (size_t opt = 0; opt < SK_ARRAY_COUNT(gOptTable); ++opt) {
        if (0 != localCount[opt]) {
            SkDebugf("%d: %d ", opt, localCount[opt]);
            someOptFired = true;
        }
    }

    if (!someOptFired) {
        SkDebugf("No opts fired\n");
    } else {
        SkDebugf("\t before: %d after: %d delta: %d\n",
                 numBefore, numAfter, numBefore-numAfter);
    }

    return 0;
}
	virtual void allocateBuffer(uint8* &buffer, int32 buffersize) {
        ++fCount;
        // we double the allocation to work around bug when height is odd
        buffer = (uint8*)sk_malloc_throw(buffersize << 1);
        SkDebugf("---  pvjpeg alloc [%d] %d addr=%p\n", fCount, buffersize, buffer);
    }
Ejemplo n.º 17
0
int tool_main(int argc, char** argv) {
#if SK_ENABLE_INST_COUNT
    gPrintInstCount = true;
#endif

    SkGraphics::Init();

    if (argc < 3) {
        usage();
        return -1;
    }

    SkString inFile, outFile, inDir, outDir;

    char* const* stop = argv + argc;
    for (++argv; argv < stop; ++argv) {
        if (strcmp(*argv, "-i") == 0) {
            argv++;
            if (argv < stop && **argv) {
                inFile.set(*argv);
            } else {
                SkDebugf("missing arg for -i\n");
                usage();
                return -1;
            }
        } else if (strcmp(*argv, "--input-dir") == 0) {
            argv++;
            if (argv < stop && **argv) {
                inDir.set(*argv);
            } else {
                SkDebugf("missing arg for --input-dir\n");
                usage();
                return -1;
            }
        } else if (strcmp(*argv, "--output-dir") == 0) {
            argv++;
            if (argv < stop && **argv) {
                outDir.set(*argv);
            } else {
                SkDebugf("missing arg for --output-dir\n");
                usage();
                return -1;
            }
        } else if (strcmp(*argv, "-o") == 0) {
            argv++;
            if (argv < stop && **argv) {
                outFile.set(*argv);
            } else {
                SkDebugf("missing arg for -o\n");
                usage();
                return -1;
            }
        } else if (strcmp(*argv, "--help") == 0 || strcmp(*argv, "-h") == 0) {
            usage();
            return 0;
        } else {
            SkDebugf("unknown arg %s\n", *argv);
            usage();
            return -1;
        }
    }

    SkOSFile::Iter iter(inDir.c_str(), "skp");

    SkString inputFilename, outputFilename;
    if (iter.next(&inputFilename)) {

        do {
            inFile = SkOSPath::SkPathJoin(inDir.c_str(), inputFilename.c_str());
            if (!outDir.isEmpty()) {
                outFile = SkOSPath::SkPathJoin(outDir.c_str(), inputFilename.c_str());
            }
            SkDebugf("Executing %s\n", inputFilename.c_str());
            filter_picture(inFile, outFile);
        } while(iter.next(&inputFilename));

    } else if (!inFile.isEmpty()) {
        filter_picture(inFile, outFile);
    } else {
        usage();
        return -1;
    }

    for (size_t opt = 0; opt < SK_ARRAY_COUNT(gOptTable); ++opt) {
        SkDebugf("opt %d: %d\n", opt, gOptTable[opt].fNumTimesApplied);
    }

    SkGraphics::Term();
    return 0;
}
	virtual void deallocateBuffer(uint8 *buffer) {
        SkDebugf("--- pvjpeg free [%d] addr=%p\n", fCount, buffer);
        --fCount;
        sk_free(buffer);
    }
Ejemplo n.º 19
0
SkOpSegment* FindSortableTop(const SkTArray<SkOpContour*, true>& contourList,
        SkOpAngle::IncludeType angleIncludeType, bool* firstContour, int* indexPtr,
        int* endIndexPtr, SkPoint* topLeft, bool* unsortable, bool* done, bool* onlyVertical,
        bool firstPass) {
    SkOpSegment* current = findTopSegment(contourList, indexPtr, endIndexPtr, topLeft, unsortable,
            done, firstPass);
    if (!current) {
        return NULL;
    }
    const int startIndex = *indexPtr;
    const int endIndex = *endIndexPtr;
    if (*firstContour) {
        current->initWinding(startIndex, endIndex, angleIncludeType);
        *firstContour = false;
        return current;
    }
    int minIndex = SkMin32(startIndex, endIndex);
    int sumWinding = current->windSum(minIndex);
    if (sumWinding == SK_MinS32) {
        int index = endIndex;
        int oIndex = startIndex;
        do { 
            const SkOpSpan& span = current->span(index);
            if ((oIndex < index ? span.fFromAngle : span.fToAngle) == NULL) {
                current->addSimpleAngle(index);
            }
            sumWinding = current->computeSum(oIndex, index, angleIncludeType);
            SkTSwap(index, oIndex);
        } while (sumWinding == SK_MinS32 && index == startIndex);
    }
    if (sumWinding != SK_MinS32 && sumWinding != SK_NaN32) {
        return current;
    }
    int contourWinding;
    int oppContourWinding = 0;
    // the simple upward projection of the unresolved points hit unsortable angles
    // shoot rays at right angles to the segment to find its winding, ignoring angle cases
    bool tryAgain;
    double tHit;
    SkScalar hitDx = 0;
    SkScalar hitOppDx = 0;
    // keep track of subsequent returns to detect infinite loops
    SkTDArray<SortableTop> sortableTops;
    do {
        // if current is vertical, find another candidate which is not
        // if only remaining candidates are vertical, then they can be marked done
        SkASSERT(*indexPtr != *endIndexPtr && *indexPtr >= 0 && *endIndexPtr >= 0);
        skipVertical(contourList, &current, indexPtr, endIndexPtr);
        SkASSERT(current);  // FIXME: if null, all remaining are vertical
        SkASSERT(*indexPtr != *endIndexPtr && *indexPtr >= 0 && *endIndexPtr >= 0);
        tryAgain = false;
        contourWinding = rightAngleWinding(contourList, &current, indexPtr, endIndexPtr, &tHit,
                &hitDx, &tryAgain, onlyVertical, false);
        if (tryAgain) {
            bool giveUp = false;
            int count = sortableTops.count();
            for (int index = 0; index < count; ++index) {
                const SortableTop& prev = sortableTops[index];
                if (giveUp) {
                    prev.fSegment->markDoneFinal(prev.fIndex);
                } else if (prev.fSegment == current
                        && (prev.fIndex == *indexPtr || prev.fEndIndex == *endIndexPtr)) {
                    // remaining edges are non-vertical and cannot have their winding computed
                    // mark them as done and return, and hope that assembly can fill the holes
                    giveUp = true;
                    index = -1;
                }
            }
            if (giveUp) {
                *done = true;
                return NULL;
            }
        }
        SortableTop* sortableTop = sortableTops.append();
        sortableTop->fSegment = current;
        sortableTop->fIndex = *indexPtr;
        sortableTop->fEndIndex = *endIndexPtr;
#if DEBUG_SORT
        SkDebugf("%s current=%d index=%d endIndex=%d tHit=%1.9g hitDx=%1.9g try=%d vert=%d\n",
                __FUNCTION__, current->debugID(), *indexPtr, *endIndexPtr, tHit, hitDx, tryAgain,
                *onlyVertical);
#endif
        if (*onlyVertical) {
            return current;
        }
        if (tryAgain) {
            continue;
        }
        if (angleIncludeType < SkOpAngle::kBinarySingle) {
            break;
        }
        oppContourWinding = rightAngleWinding(contourList, &current, indexPtr, endIndexPtr, &tHit,
                &hitOppDx, &tryAgain, NULL, true);
    } while (tryAgain);
    bool success = current->initWinding(*indexPtr, *endIndexPtr, tHit, contourWinding, hitDx,
            oppContourWinding, hitOppDx);
    if (current->done()) {
        return NULL;
    } else if (!success) {  // check if the span has a valid winding
        int min = SkTMin(*indexPtr, *endIndexPtr);
        const SkOpSpan& span = current->span(min);
        if (span.fWindSum == SK_MinS32) {
            return NULL;
        }
    }
    return current;
}
Ejemplo n.º 20
0
	static void assert_no_attr(const SkDOM& dom, const SkDOM::Node* node, const char attr[])
	{
		const char* value = dom.findAttr(node, attr);
		if (value)
			SkDebugf("unknown attribute %s=\"%s\"\n", attr, value);
	}
Ejemplo n.º 21
0
    /*
        check start and end of each contour
        if not the same, record them
        match them up
        connect closest
        reassemble contour pieces into new path
    */
void Assemble(const SkPathWriter& path, SkPathWriter* simple) {
#if DEBUG_PATH_CONSTRUCTION
    SkDebugf("%s\n", __FUNCTION__);
#endif
    SkTArray<SkOpContour> contours;
    SkOpEdgeBuilder builder(path, contours);
    builder.finish();
    int count = contours.count();
    int outer;
    SkTArray<int, true> runs(count);  // indices of partial contours
    for (outer = 0; outer < count; ++outer) {
        const SkOpContour& eContour = contours[outer];
        const SkPoint& eStart = eContour.start();
        const SkPoint& eEnd = eContour.end();
#if DEBUG_ASSEMBLE
        SkDebugf("%s contour", __FUNCTION__);
        if (!SkDPoint::ApproximatelyEqual(eStart, eEnd)) {
            SkDebugf("[%d]", runs.count());
        } else {
            SkDebugf("   ");
        }
        SkDebugf(" start=(%1.9g,%1.9g) end=(%1.9g,%1.9g)\n",
                eStart.fX, eStart.fY, eEnd.fX, eEnd.fY);
#endif
        if (SkDPoint::ApproximatelyEqual(eStart, eEnd)) {
            eContour.toPath(simple);
            continue;
        }
        runs.push_back(outer);
    }
    count = runs.count();
    if (count == 0) {
        return;
    }
    SkTArray<int, true> sLink, eLink;
    sLink.push_back_n(count);
    eLink.push_back_n(count);
    int rIndex, iIndex;
    for (rIndex = 0; rIndex < count; ++rIndex) {
        sLink[rIndex] = eLink[rIndex] = SK_MaxS32;
    }
    const int ends = count * 2;  // all starts and ends
    const int entries = (ends - 1) * count;  // folded triangle : n * (n - 1) / 2
    SkTArray<double, true> distances;
    distances.push_back_n(entries);
    for (rIndex = 0; rIndex < ends - 1; ++rIndex) {
        outer = runs[rIndex >> 1];
        const SkOpContour& oContour = contours[outer];
        const SkPoint& oPt = rIndex & 1 ? oContour.end() : oContour.start();
        const int row = rIndex < count - 1 ? rIndex * ends : (ends - rIndex - 2)
                * ends - rIndex - 1;
        for (iIndex = rIndex + 1; iIndex < ends; ++iIndex) {
            int inner = runs[iIndex >> 1];
            const SkOpContour& iContour = contours[inner];
            const SkPoint& iPt = iIndex & 1 ? iContour.end() : iContour.start();
            double dx = iPt.fX - oPt.fX;
            double dy = iPt.fY - oPt.fY;
            double dist = dx * dx + dy * dy;
            distances[row + iIndex] = dist;  // oStart distance from iStart
        }
    }
    SkTArray<int, true> sortedDist;
    sortedDist.push_back_n(entries);
    for (rIndex = 0; rIndex < entries; ++rIndex) {
        sortedDist[rIndex] = rIndex;
    }
    SkTQSort<int>(sortedDist.begin(), sortedDist.end() - 1, DistanceLessThan(distances.begin()));
    int remaining = count;  // number of start/end pairs
    for (rIndex = 0; rIndex < entries; ++rIndex) {
        int pair = sortedDist[rIndex];
        int row = pair / ends;
        int col = pair - row * ends;
        int thingOne = row < col ? row : ends - row - 2;
        int ndxOne = thingOne >> 1;
        bool endOne = thingOne & 1;
        int* linkOne = endOne ? eLink.begin() : sLink.begin();
        if (linkOne[ndxOne] != SK_MaxS32) {
            continue;
        }
        int thingTwo = row < col ? col : ends - row + col - 1;
        int ndxTwo = thingTwo >> 1;
        bool endTwo = thingTwo & 1;
        int* linkTwo = endTwo ? eLink.begin() : sLink.begin();
        if (linkTwo[ndxTwo] != SK_MaxS32) {
            continue;
        }
        SkASSERT(&linkOne[ndxOne] != &linkTwo[ndxTwo]);
        bool flip = endOne == endTwo;
        linkOne[ndxOne] = flip ? ~ndxTwo : ndxTwo;
        linkTwo[ndxTwo] = flip ? ~ndxOne : ndxOne;
        if (!--remaining) {
            break;
        }
    }
    SkASSERT(!remaining);
#if DEBUG_ASSEMBLE
    for (rIndex = 0; rIndex < count; ++rIndex) {
        int s = sLink[rIndex];
        int e = eLink[rIndex];
        SkDebugf("%s %c%d <- s%d - e%d -> %c%d\n", __FUNCTION__, s < 0 ? 's' : 'e',
                s < 0 ? ~s : s, rIndex, rIndex, e < 0 ? 'e' : 's', e < 0 ? ~e : e);
    }
#endif
    rIndex = 0;
    do {
        bool forward = true;
        bool first = true;
        int sIndex = sLink[rIndex];
        SkASSERT(sIndex != SK_MaxS32);
        sLink[rIndex] = SK_MaxS32;
        int eIndex;
        if (sIndex < 0) {
            eIndex = sLink[~sIndex];
            sLink[~sIndex] = SK_MaxS32;
        } else {
            eIndex = eLink[sIndex];
            eLink[sIndex] = SK_MaxS32;
        }
        SkASSERT(eIndex != SK_MaxS32);
#if DEBUG_ASSEMBLE
        SkDebugf("%s sIndex=%c%d eIndex=%c%d\n", __FUNCTION__, sIndex < 0 ? 's' : 'e',
                    sIndex < 0 ? ~sIndex : sIndex, eIndex < 0 ? 's' : 'e',
                    eIndex < 0 ? ~eIndex : eIndex);
#endif
        do {
            outer = runs[rIndex];
            const SkOpContour& contour = contours[outer];
            if (first) {
                first = false;
                const SkPoint* startPtr = &contour.start();
                simple->deferredMove(startPtr[0]);
            }
            if (forward) {
                contour.toPartialForward(simple);
            } else {
                contour.toPartialBackward(simple);
            }
#if DEBUG_ASSEMBLE
            SkDebugf("%s rIndex=%d eIndex=%s%d close=%d\n", __FUNCTION__, rIndex,
                eIndex < 0 ? "~" : "", eIndex < 0 ? ~eIndex : eIndex,
                sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex));
#endif
            if (sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)) {
                simple->close();
                break;
            }
            if (forward) {
                eIndex = eLink[rIndex];
                SkASSERT(eIndex != SK_MaxS32);
                eLink[rIndex] = SK_MaxS32;
                if (eIndex >= 0) {
                    SkASSERT(sLink[eIndex] == rIndex);
                    sLink[eIndex] = SK_MaxS32;
                } else {
                    SkASSERT(eLink[~eIndex] == ~rIndex);
                    eLink[~eIndex] = SK_MaxS32;
                }
            } else {
                eIndex = sLink[rIndex];
                SkASSERT(eIndex != SK_MaxS32);
                sLink[rIndex] = SK_MaxS32;
                if (eIndex >= 0) {
                    SkASSERT(eLink[eIndex] == rIndex);
                    eLink[eIndex] = SK_MaxS32;
                } else {
                    SkASSERT(sLink[~eIndex] == ~rIndex);
                    sLink[~eIndex] = SK_MaxS32;
                }
            }
            rIndex = eIndex;
            if (rIndex < 0) {
                forward ^= 1;
                rIndex = ~rIndex;
            }
        } while (true);
        for (rIndex = 0; rIndex < count; ++rIndex) {
            if (sLink[rIndex] != SK_MaxS32) {
                break;
            }
        }
    } while (rIndex < count);
#if DEBUG_ASSEMBLE
    for (rIndex = 0; rIndex < count; ++rIndex) {
       SkASSERT(sLink[rIndex] == SK_MaxS32);
       SkASSERT(eLink[rIndex] == SK_MaxS32);
    }
#endif
}
void SkScriptEngine2::decompile(const unsigned char* start, size_t length) {
    SkASSERT(length > 0);
    const unsigned char* opCode = start;
    do {
        SkASSERT((size_t)(opCode - start) < length);
        SkScriptEngine2::TypeOp op = (SkScriptEngine2::TypeOp) *opCode++;
        SkASSERT((size_t)op < gOpNamesSize);
        SkDebugf("%d: %s", opCode - start - 1, gOpNames[op].fName);
        switch (op) {
        case SkScriptEngine2::kCallback: {
            int index;
            memcpy(&index, opCode, sizeof(index));
            opCode += sizeof(index);
            SkDebugf(" index: %d", index);
            } break;
        case SkScriptEngine2::kFunctionCall: 
        case SkScriptEngine2::kMemberOp:
        case SkScriptEngine2::kPropertyOp: {
            size_t ref;
            memcpy(&ref, opCode, sizeof(ref));
            opCode += sizeof(ref);
            SkDebugf(" ref: %d", ref);
            } break;
        case SkScriptEngine2::kIntegerAccumulator:
        case SkScriptEngine2::kIntegerOperand: {
            int32_t integer;
            memcpy(&integer, opCode, sizeof(integer));
            opCode += sizeof(int32_t);
            SkDebugf(" integer: %d", integer);
            } break;
        case SkScriptEngine2::kScalarAccumulator:
        case SkScriptEngine2::kScalarOperand: {
            SkScalar scalar;
            memcpy(&scalar, opCode, sizeof(scalar));
            opCode += sizeof(SkScalar);
#ifdef SK_CAN_USE_FLOAT
            SkDebugf(" scalar: %g", SkScalarToFloat(scalar));
#else
            SkDebugf(" scalar: %x", scalar);
#endif
            } break;
        case SkScriptEngine2::kStringAccumulator:
        case SkScriptEngine2::kStringOperand: {
            int size;
            SkString* strPtr = new SkString();
            memcpy(&size, opCode, sizeof(size));
            opCode += sizeof(size);
            strPtr->set((char*) opCode, size);
            opCode += size;
            SkDebugf(" string: %s", strPtr->c_str());
            delete strPtr;
            } break;
        case SkScriptEngine2::kBoxToken: {
            SkOperand2::OpType type;
            memcpy(&type, opCode, sizeof(type));
            opCode += sizeof(type);
            size_t index = 0;
            if (type == 0)
                SkDebugf(" type: %s", gOperandNames[index].fName);
            else {
                while (type != 0) {
                    SkASSERT(index + 1 < gOperandNamesSize);
                    if (type & (1 << index)) {
                        type = (SkOperand2::OpType) (type & ~(1 << index));
                        SkDebugf(" type: %s", gOperandNames[index + 1].fName);
                    }
                    index++;
                }
            }
            } break;
        case SkScriptEngine2::kIfOp:
        case SkScriptEngine2::kLogicalAndInt:
        case SkScriptEngine2::kElseOp:
        case SkScriptEngine2::kLogicalOrInt: {
            int size;
            memcpy(&size, opCode, sizeof(size));
            opCode += sizeof(size);
            SkDebugf(" offset (address): %d (%d)", size, opCode - start + size);
            } break;
        case SkScriptEngine2::kEnd:
            goto done;
        case SkScriptEngine2::kNop:
                SkASSERT(0);
        default:
            break;
    }
    SkDebugf("\n");
    } while (true);
done:
    SkDebugf("\n");
}
Ejemplo n.º 23
0
DEF_TEST(SkpSkGr, reporter) {
    SkTArray<TestResult, true> errors;
    if (!initTest()) {
        return;
    }
    SkpSkGrThreadState state;
    state.init(0);
    int smallCount = 0;
    for (int dirNo = 1; dirNo <= 100; ++dirNo) {
        SkString pictDir = make_in_dir_name(dirNo);
        SkASSERT(pictDir.size());
        if (reporter->verbose()) {
            SkDebugf("dirNo=%d\n", dirNo);
        }
        SkOSFile::Iter iter(pictDir.c_str(), "skp");
        SkString filename;
        int testCount = 0;
        PreParser preParser(dirNo);
        SkFILEWStream statusStream(makeStatusString(dirNo).c_str());
        while (iter.next(&filename)) {
            for (size_t index = 0; index < skipOverSkGrCount; ++index) {
                if (skipOverSkGr[index].directory == dirNo
                        && strcmp(filename.c_str(), skipOverSkGr[index].filename) == 0) {
                    goto skipOver;
                }
            }
            if (preParser.match(filename, &statusStream, &state.fResult)) {
                addError(&state);
                ++testCount;
                goto checkEarlyExit;
            }
            if (state.fSmallestError > 5000000) {
                goto breakOut;
            }
            {
                TestResult& result = state.fResult;
                result.test(dirNo, filename);
                SkString outStr(result.status());
                statusStream.write(outStr.c_str(), outStr.size());
                statusStream.flush();
                if (1) {
                    SkDebugf("%s", outStr.c_str());
                }
                bool noMatch = addError(&state);
                if (noMatch) {
                    smallCount = 0;
                } else if (++smallCount > 10000) {
                    goto breakOut;
                }
            }
            ++testCount;
            if (reporter->verbose()) {
                if (testCount % 100 == 0) {
                    SkDebugf("#%d\n", testCount);
                }
            }
     skipOver:
             reporter->bumpTestCount();
    checkEarlyExit:
            if (1 && testCount == 20) {
                break;
            }
        }
    }
breakOut:
    if (reporter->verbose()) {
        for (int index = 0; index < state.fFoundCount; ++index) {
            SkDebugf("%d %s %d\n", state.fDirsFound[index], state.fFilesFound[index],
                     state.fError[index]);
        }
    }
    for (int index = 0; index < state.fFoundCount; ++index) {
        TestResult::Test(state.fDirsFound[index], state.fFilesFound[index], kEncodeFiles,
                reporter->verbose());
        if (reporter->verbose()) SkDebugf("+");
    }
}
Ejemplo n.º 24
0
// A function used to determine at runtime if the target CPU supports
// the ARM NEON instruction set. This implementation is Linux-specific.
static bool sk_cpu_arm_check_neon(void) {
    bool result = false;

#if NEON_DEBUG
    // Allow forcing the mode through the environment during debugging.
#  ifdef SK_BUILD_FOR_ANDROID
    // On Android, we use a system property
#   define PROP_NAME  "debug.skia.arm_neon_mode"
    char prop[PROP_VALUE_MAX];
    if (__system_property_get(PROP_NAME, prop) > 0) {
#  else
#   define PROP_NAME   "SKIA_ARM_NEON_MODE"
    // On ARM Linux, we use an environment variable
    const char* prop = getenv(PROP_NAME);
    if (prop != NULL) {
#  endif
        SkDebugf("%s: %s", PROP_NAME, prop);
        if (!strcmp(prop, "1")) {
            SkDebugf("Forcing ARM Neon mode to full!\n");
            return true;
        }
        if (!strcmp(prop, "0")) {
            SkDebugf("Disabling ARM NEON mode\n");
            return false;
        }
    }
    SkDebugf("Running dynamic CPU feature detection\n");
#endif

    // There is no user-accessible CPUID instruction on ARM that we can use.
    // Instead, we must parse /proc/cpuinfo and look for the 'neon' feature.
    // For example, here's a typical output (Nexus S running ICS 4.0.3):
    /*
    Processor       : ARMv7 Processor rev 2 (v7l)
    BogoMIPS        : 994.65
    Features        : swp half thumb fastmult vfp edsp thumbee neon vfpv3
    CPU implementer : 0x41
    CPU architecture: 7
    CPU variant     : 0x2
    CPU part        : 0xc08
    CPU revision    : 2

    Hardware        : herring
    Revision        : 000b
    Serial          : 3833c77d6dc000ec
    */
    char   buffer[4096];

    // If we fail any of the following, assume we don't have NEON instructions
    // This allows us to return immediately in case of error.
    result = false;

    do {
        // open /proc/cpuinfo
        int fd = TEMP_FAILURE_RETRY(open("/proc/cpuinfo", O_RDONLY));
        if (fd < 0) {
            SkDebugf("Could not open /proc/cpuinfo: %s\n", strerror(errno));
            break;
        }

        // Read the file. To simplify our search, we're going to place two
        // sentinel '\n' characters: one at the start of the buffer, and one at
        // the end. This means we reserve the first and last buffer bytes.
        buffer[0] = '\n';
        int size = TEMP_FAILURE_RETRY(read(fd, buffer+1, sizeof(buffer)-2));
        close(fd);

        if (size < 0) {  // should not happen
            SkDebugf("Could not read /proc/cpuinfo: %s\n", strerror(errno));
            break;
        }

        SkDebugf("START /proc/cpuinfo:\n%.*s\nEND /proc/cpuinfo\n",
                 size, buffer+1);

        // Compute buffer limit, and place final sentinel
        char* buffer_end = buffer + 1 + size;
        buffer_end[0] = '\n';

        // Now, find a line that starts with "Features", i.e. look for
        // '\nFeatures ' in our buffer.
        const char features[] = "\nFeatures\t";
        const size_t features_len = sizeof(features)-1;

        char*  line = (char*) memmem(buffer, buffer_end - buffer,
                                     features, features_len);
        if (line == NULL) {  // Weird, no Features line, bad kernel?
            SkDebugf("Could not find a line starting with 'Features'"
              "in /proc/cpuinfo ?\n");
            break;
        }

        line += features_len;  // Skip the "\nFeatures\t" prefix

        // Find the end of the current line
        char* line_end = (char*) memchr(line, '\n', buffer_end - line);
        if (line_end == NULL)
            line_end = buffer_end;

        // Now find an instance of 'neon' in the flags list. We want to
        // ensure it's only 'neon' and not something fancy like 'noneon'
        // so check that it follows a space.
        const char neon[] = " neon";
        const size_t neon_len = sizeof(neon)-1;
        const char* flag = (const char*) memmem(line, line_end - line,
                                                neon, neon_len);
        if (flag == NULL)
            break;

        // Ensure it is followed by a space or a newline.
        if (flag[neon_len] != ' ' && flag[neon_len] != '\n')
            break;

        // Fine, we support Arm NEON !
        result = true;

    } while (0);

    if (result) {
        SkDebugf("Device supports ARM NEON instructions!\n");
    } else {
        SkDebugf("Device does NOT support ARM NEON instructions!\n");
    }
    return result;
}

static pthread_once_t  sOnce;
static bool            sHasArmNeon;

// called through pthread_once()
void sk_cpu_arm_probe_features(void) {
    sHasArmNeon = sk_cpu_arm_check_neon();
}

bool sk_cpu_arm_has_neon(void) {
    pthread_once(&sOnce, sk_cpu_arm_probe_features);
    return sHasArmNeon;
}
Ejemplo n.º 25
0
bool GrDrawTarget::setupDstReadIfNecessary(const GrPipelineBuilder& pipelineBuilder,
                                           const GrClip& clip,
                                           const GrPipelineOptimizations& optimizations,
                                           GrXferProcessor::DstTexture* dstTexture,
                                           const SkRect& batchBounds) {
    SkRect bounds = batchBounds;
    bounds.outset(0.5f, 0.5f);

    if (!pipelineBuilder.willXPNeedDstTexture(*this->caps(), optimizations)) {
        return true;
    }

    GrRenderTarget* rt = pipelineBuilder.getRenderTarget();

    if (this->caps()->textureBarrierSupport()) {
        if (GrTexture* rtTex = rt->asTexture()) {
            // The render target is a texture, so we can read from it directly in the shader. The XP
            // will be responsible to detect this situation and request a texture barrier.
            dstTexture->setTexture(rtTex);
            dstTexture->setOffset(0, 0);
            return true;
        }
    }

    SkIRect copyRect;
    clip.getConservativeBounds(rt->width(), rt->height(), &copyRect);

    SkIRect drawIBounds;
    bounds.roundOut(&drawIBounds);
    if (!copyRect.intersect(drawIBounds)) {
#ifdef SK_DEBUG
        GrCapsDebugf(this->caps(), "Missed an early reject. "
                                   "Bailing on draw from setupDstReadIfNecessary.\n");
#endif
        return false;
    }

    // MSAA consideration: When there is support for reading MSAA samples in the shader we could
    // have per-sample dst values by making the copy multisampled.
    GrSurfaceDesc desc;
    if (!fGpu->initCopySurfaceDstDesc(rt, &desc)) {
        desc.fOrigin = kDefault_GrSurfaceOrigin;
        desc.fFlags = kRenderTarget_GrSurfaceFlag;
        desc.fConfig = rt->config();
    }

    desc.fWidth = copyRect.width();
    desc.fHeight = copyRect.height();

    static const uint32_t kFlags = 0;
    SkAutoTUnref<GrTexture> copy(fResourceProvider->createApproxTexture(desc, kFlags));

    if (!copy) {
        SkDebugf("Failed to create temporary copy of destination texture.\n");
        return false;
    }
    SkIPoint dstPoint = {0, 0};
    this->copySurface(copy, rt, copyRect, dstPoint);
    dstTexture->setTexture(copy);
    dstTexture->setOffset(copyRect.fLeft, copyRect.fTop);
    return true;
}
Ejemplo n.º 26
0
static void setup_benchmark(sk_tools::PictureBenchmark* benchmark) {
    sk_tools::PictureRenderer::DrawFilterFlags drawFilters[SkDrawFilter::kTypeCount];
    sk_bzero(drawFilters, sizeof(drawFilters));

    if (FLAGS_filter.count() > 0) {
        const char* filters = FLAGS_filter[0];
        const char* colon = strchr(filters, ':');
        if (colon) {
            int32_t type = -1;
            size_t typeLen = colon - filters;
            for (size_t tIndex = 0; tIndex < kFilterTypesCount; ++tIndex) {
                if (typeLen == strlen(gFilterTypes[tIndex])
                        && !strncmp(filters, gFilterTypes[tIndex], typeLen)) {
                    type = SkToS32(tIndex);
                    break;
                }
            }
            if (type < 0) {
                SkString err;
                err.printf("Unknown type for --filter %s\n", filters);
                gLogger.logError(err);
                exit(-1);
            }
            int flag = -1;
            size_t flagLen = strlen(filters) - typeLen - 1;
            for (size_t fIndex = 0; fIndex < kFilterFlagsCount; ++fIndex) {
                if (flagLen == strlen(gFilterFlags[fIndex])
                        && !strncmp(colon + 1, gFilterFlags[fIndex], flagLen)) {
                    flag = 1 << fIndex;
                    break;
                }
            }
            if (flag < 0) {
                SkString err;
                err.printf("Unknown flag for --filter %s\n", filters);
                gLogger.logError(err);
                exit(-1);
            }
            for (int index = 0; index < SkDrawFilter::kTypeCount; ++index) {
                if (type != SkDrawFilter::kTypeCount && index != type) {
                    continue;
                }
                drawFilters[index] = (sk_tools::PictureRenderer::DrawFilterFlags)
                        (drawFilters[index] | flag);
            }
        } else {
            SkString err;
            err.printf("Unknown arg for --filter %s : missing colon\n", filters);
            gLogger.logError(err);
            exit(-1);
        }
    }

    if (FLAGS_timers.count() > 0) {
        size_t index = 0;
        bool timerWall = false;
        bool truncatedTimerWall = false;
        bool timerCpu = false;
        bool truncatedTimerCpu = false;
        bool timerGpu = false;
        while (index < strlen(FLAGS_timers[0])) {
            switch (FLAGS_timers[0][index]) {
                case 'w':
                    timerWall = true;
                    break;
                case 'c':
                    timerCpu = true;
                    break;
                case 'W':
                    truncatedTimerWall = true;
                    break;
                case 'C':
                    truncatedTimerCpu = true;
                    break;
                case 'g':
                    timerGpu = true;
                    break;
                default:
                    SkDebugf("mystery character\n");
                    break;
            }
            index++;
        }
        benchmark->setTimersToShow(timerWall, truncatedTimerWall, timerCpu, truncatedTimerCpu,
                                  timerGpu);
    }

    SkString errorString;
    SkAutoTUnref<sk_tools::PictureRenderer> renderer(parseRenderer(errorString,
                                                                   kBench_PictureTool));

    if (errorString.size() > 0) {
        gLogger.logError(errorString);
    }

    if (NULL == renderer.get()) {
        exit(-1);
    }

    if (FLAGS_timeIndividualTiles) {
        if (FLAGS_multi > 1) {
            gLogger.logError("Cannot time individual tiles with more than one thread.\n");
            exit(-1);
        }
        sk_tools::TiledPictureRenderer* tiledRenderer = renderer->getTiledRenderer();
        if (NULL == tiledRenderer) {
            gLogger.logError("--timeIndividualTiles requires tiled rendering.\n");
            exit(-1);
        }
        if (!tiledRenderer->supportsTimingIndividualTiles()) {
            gLogger.logError("This renderer does not support --timeIndividualTiles.\n");
            exit(-1);
        }
        benchmark->setTimeIndividualTiles(true);
    }

    if (FLAGS_readPath.count() < 1) {
        gLogger.logError(".skp files or directories are required.\n");
        exit(-1);
    }

    renderer->setDrawFilters(drawFilters, filtersName(drawFilters));
    benchmark->setPrintMin(FLAGS_min);
    benchmark->setLogPerIter(FLAGS_logPerIter);
    benchmark->setRenderer(renderer);
    benchmark->setRepeats(FLAGS_repeat);
    benchmark->setLogger(&gLogger);
}
Ejemplo n.º 27
0
void ShowFunctionHeader() {
    SkDebugf("\nstatic void test#(skiatest::Reporter* reporter) {\n");
}
Ejemplo n.º 28
0
bool GrVkCopyManager::copySurfaceAsDraw(GrVkGpu* gpu,
                                        GrSurface* dst, GrSurfaceOrigin dstOrigin,
                                        GrSurface* src, GrSurfaceOrigin srcOrigin,
                                        const SkIRect& srcRect, const SkIPoint& dstPoint,
                                        bool canDiscardOutsideDstRect) {
    // None of our copy methods can handle a swizzle. TODO: Make copySurfaceAsDraw handle the
    // swizzle.
    if (gpu->caps()->shaderCaps()->configOutputSwizzle(src->config()) !=
        gpu->caps()->shaderCaps()->configOutputSwizzle(dst->config())) {
        return false;
    }

    GrVkRenderTarget* rt = static_cast<GrVkRenderTarget*>(dst->asRenderTarget());
    if (!rt) {
        return false;
    }

    GrVkTexture* srcTex = static_cast<GrVkTexture*>(src->asTexture());
    if (!srcTex) {
        return false;
    }

    if (VK_NULL_HANDLE == fVertShaderModule) {
        SkASSERT(VK_NULL_HANDLE == fFragShaderModule &&
                 nullptr == fPipelineLayout &&
                 nullptr == fVertexBuffer.get() &&
                 nullptr == fUniformBuffer.get());
        if (!this->createCopyProgram(gpu)) {
            SkDebugf("Failed to create copy program.\n");
            return false;
        }
    }
    SkASSERT(fPipelineLayout);

    GrVkResourceProvider& resourceProv = gpu->resourceProvider();

    GrVkCopyPipeline* pipeline = resourceProv.findOrCreateCopyPipeline(rt,
                                                                       fShaderStageInfo,
                                                                       fPipelineLayout->layout());
    if (!pipeline) {
        return false;
    }

    // UPDATE UNIFORM DESCRIPTOR SET
    int w = srcRect.width();
    int h = srcRect.height();

    // dst rect edges in NDC (-1 to 1)
    int dw = dst->width();
    int dh = dst->height();
    float dx0 = 2.f * dstPoint.fX / dw - 1.f;
    float dx1 = 2.f * (dstPoint.fX + w) / dw - 1.f;
    float dy0 = 2.f * dstPoint.fY / dh - 1.f;
    float dy1 = 2.f * (dstPoint.fY + h) / dh - 1.f;
    if (kBottomLeft_GrSurfaceOrigin == dstOrigin) {
        dy0 = -dy0;
        dy1 = -dy1;
    }


    float sx0 = (float)srcRect.fLeft;
    float sx1 = (float)(srcRect.fLeft + w);
    float sy0 = (float)srcRect.fTop;
    float sy1 = (float)(srcRect.fTop + h);
    int sh = src->height();
    if (kBottomLeft_GrSurfaceOrigin == srcOrigin) {
        sy0 = sh - sy0;
        sy1 = sh - sy1;
    }
    // src rect edges in normalized texture space (0 to 1).
    int sw = src->width();
    sx0 /= sw;
    sx1 /= sw;
    sy0 /= sh;
    sy1 /= sh;

    float uniData[] = { dx1 - dx0, dy1 - dy0, dx0, dy0,    // posXform
                        sx1 - sx0, sy1 - sy0, sx0, sy0 };  // texCoordXform

    fUniformBuffer->updateData(gpu, uniData, sizeof(uniData), nullptr);

    const GrVkDescriptorSet* uniformDS = resourceProv.getUniformDescriptorSet();
    SkASSERT(uniformDS);

    VkDescriptorBufferInfo uniBufferInfo;
    uniBufferInfo.buffer = fUniformBuffer->buffer();
    uniBufferInfo.offset = fUniformBuffer->offset();
    uniBufferInfo.range = fUniformBuffer->size();

    VkWriteDescriptorSet descriptorWrites;
    descriptorWrites.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
    descriptorWrites.pNext = nullptr;
    descriptorWrites.dstSet = uniformDS->descriptorSet();
    descriptorWrites.dstBinding = GrVkUniformHandler::kGeometryBinding;
    descriptorWrites.dstArrayElement = 0;
    descriptorWrites.descriptorCount = 1;
    descriptorWrites.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
    descriptorWrites.pImageInfo = nullptr;
    descriptorWrites.pBufferInfo = &uniBufferInfo;
    descriptorWrites.pTexelBufferView = nullptr;

    GR_VK_CALL(gpu->vkInterface(), UpdateDescriptorSets(gpu->device(),
                                                        1,
                                                        &descriptorWrites,
                                                        0, nullptr));

    // UPDATE SAMPLER DESCRIPTOR SET
    const GrVkDescriptorSet* samplerDS =
        gpu->resourceProvider().getSamplerDescriptorSet(fSamplerDSHandle);

    GrSamplerState samplerState = GrSamplerState::ClampNearest();

    GrVkSampler* sampler = resourceProv.findOrCreateCompatibleSampler(
            samplerState, GrVkYcbcrConversionInfo());

    VkDescriptorImageInfo imageInfo;
    memset(&imageInfo, 0, sizeof(VkDescriptorImageInfo));
    imageInfo.sampler = sampler->sampler();
    imageInfo.imageView = srcTex->textureView()->imageView();
    imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;

    VkWriteDescriptorSet writeInfo;
    memset(&writeInfo, 0, sizeof(VkWriteDescriptorSet));
    writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
    writeInfo.pNext = nullptr;
    writeInfo.dstSet = samplerDS->descriptorSet();
    writeInfo.dstBinding = 0;
    writeInfo.dstArrayElement = 0;
    writeInfo.descriptorCount = 1;
    writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
    writeInfo.pImageInfo = &imageInfo;
    writeInfo.pBufferInfo = nullptr;
    writeInfo.pTexelBufferView = nullptr;

    GR_VK_CALL(gpu->vkInterface(), UpdateDescriptorSets(gpu->device(),
                                                        1,
                                                        &writeInfo,
                                                        0, nullptr));

    VkDescriptorSet vkDescSets[] = { uniformDS->descriptorSet(), samplerDS->descriptorSet() };

    GrVkRenderTarget* texRT = static_cast<GrVkRenderTarget*>(srcTex->asRenderTarget());
    if (texRT) {
        gpu->resolveRenderTargetNoFlush(texRT);
    }

    // TODO: Make tighter bounds and then adjust bounds for origin and granularity if we see
    //       any perf issues with using the whole bounds
    SkIRect bounds = SkIRect::MakeWH(rt->width(), rt->height());

    // Change layouts of rt and texture. We aren't blending so we don't need color attachment read
    // access for blending.
    GrVkImage* targetImage = rt->msaaImage() ? rt->msaaImage() : rt;
    VkAccessFlags dstAccessFlags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
    if (!canDiscardOutsideDstRect) {
        // We need to load the color attachment so need to be able to read it.
        dstAccessFlags |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
    }
    targetImage->setImageLayout(gpu,
                                VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
                                dstAccessFlags,
                                VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
                                false);

    srcTex->setImageLayout(gpu,
                           VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
                           VK_ACCESS_SHADER_READ_BIT,
                           VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
                           false);

    GrStencilAttachment* stencil = rt->renderTargetPriv().getStencilAttachment();
    if (stencil) {
        GrVkStencilAttachment* vkStencil = (GrVkStencilAttachment*)stencil;
        // We aren't actually using the stencil but we still load and store it so we need
        // appropriate barriers.
        // TODO: Once we refactor surface and how we conntect stencil to RTs, we should not even
        // have the stencil on this render pass if possible.
        vkStencil->setImageLayout(gpu,
                                  VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
                                  VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
                                  VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
                                  VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
                                  false);
    }

    VkAttachmentLoadOp loadOp = canDiscardOutsideDstRect ? VK_ATTACHMENT_LOAD_OP_DONT_CARE
                                                         : VK_ATTACHMENT_LOAD_OP_LOAD;
    GrVkRenderPass::LoadStoreOps vkColorOps(loadOp, VK_ATTACHMENT_STORE_OP_STORE);
    GrVkRenderPass::LoadStoreOps vkStencilOps(VK_ATTACHMENT_LOAD_OP_LOAD,
                                              VK_ATTACHMENT_STORE_OP_STORE);
    const GrVkRenderPass* renderPass;
    const GrVkResourceProvider::CompatibleRPHandle& rpHandle = rt->compatibleRenderPassHandle();
    if (rpHandle.isValid()) {
        renderPass = gpu->resourceProvider().findRenderPass(rpHandle,
                                                            vkColorOps,
                                                            vkStencilOps);
    } else {
        renderPass = gpu->resourceProvider().findRenderPass(*rt,
                                                            vkColorOps,
                                                            vkStencilOps);
    }

    SkASSERT(renderPass->isCompatible(*rt->simpleRenderPass()));

    GrVkPrimaryCommandBuffer* cmdBuffer = gpu->currentCommandBuffer();
    cmdBuffer->beginRenderPass(gpu, renderPass, nullptr, *rt, bounds, true);

    GrVkSecondaryCommandBuffer* secondary = gpu->cmdPool()->findOrCreateSecondaryCommandBuffer(gpu);
    if (!secondary) {
        return false;
    }
    secondary->begin(gpu, rt->framebuffer(), renderPass);

    secondary->bindPipeline(gpu, pipeline);

    // Uniform DescriptorSet, Sampler DescriptorSet, and vertex shader uniformBuffer
    SkSTArray<3, const GrVkRecycledResource*> descriptorRecycledResources;
    descriptorRecycledResources.push_back(uniformDS);
    descriptorRecycledResources.push_back(samplerDS);
    descriptorRecycledResources.push_back(fUniformBuffer->resource());

    // One sampler, texture view, and texture
    SkSTArray<3, const GrVkResource*> descriptorResources;
    descriptorResources.push_back(sampler);
    descriptorResources.push_back(srcTex->textureView());
    descriptorResources.push_back(srcTex->resource());

    secondary->bindDescriptorSets(gpu,
                                  descriptorRecycledResources,
                                  descriptorResources,
                                  fPipelineLayout,
                                  0,
                                  2,
                                  vkDescSets,
                                  0,
                                  nullptr);

    // Set Dynamic viewport and stencil
    // We always use one viewport the size of the RT
    VkViewport viewport;
    viewport.x = 0.0f;
    viewport.y = 0.0f;
    viewport.width = SkIntToScalar(rt->width());
    viewport.height = SkIntToScalar(rt->height());
    viewport.minDepth = 0.0f;
    viewport.maxDepth = 1.0f;
    secondary->setViewport(gpu, 0, 1, &viewport);

    // We assume the scissor is not enabled so just set it to the whole RT
    VkRect2D scissor;
    scissor.extent.width = rt->width();
    scissor.extent.height = rt->height();
    scissor.offset.x = 0;
    scissor.offset.y = 0;
    secondary->setScissor(gpu, 0, 1, &scissor);

    secondary->bindInputBuffer(gpu, 0, fVertexBuffer.get());
    secondary->draw(gpu, 4, 1, 0, 0);
    secondary->end(gpu);
    cmdBuffer->executeCommands(gpu, secondary);
    cmdBuffer->endRenderPass(gpu);
    secondary->unref(gpu);

    // Release all temp resources which should now be reffed by the cmd buffer
    pipeline->unref(gpu);
    uniformDS->unref(gpu);
    samplerDS->unref(gpu);
    sampler->unref(gpu);
    renderPass->unref(gpu);

    return true;
}
Ejemplo n.º 29
0
void SkApply::dump(SkAnimateMaker* maker) {
    dumpBase(maker);
    if (dynamicScope.isEmpty() == false)
        SkDebugf("dynamicScope=\"%s\" ", dynamicScope.c_str());
    if (dontDraw)
        SkDebugf("dontDraw=\"true\" ");
    if (begin != 0) //perhaps we want this no matter what?
        SkDebugf("begin=\"%g\" ", (float) begin/1000.0f);   //is this correct?
    if (interval != (SkMSec) -1)
        SkDebugf("interval=\"%g\" ", (float) interval/1000.0f);
    if (steps != -1)
        SkDebugf("steps=\"%d\" ", steps);
    if (restore)
        SkDebugf("restore=\"true\" ");
    if (transition == kTransition_reverse)
        SkDebugf("transition=\"reverse\" ");
    if (mode == kMode_immediate) {
        SkDebugf("mode=\"immediate\" ");
    }
    else if (mode == kMode_create) {
        SkDebugf("mode=\"create\" ");
    }
    bool closedYet = false;
    SkDisplayList::fIndent += 4;
    int save = SkDisplayList::fDumpIndex;
    if (scope) {
        if (closedYet == false) {
            SkDebugf(">\n");
            closedYet = true;
        }
        scope->dump(maker);
    }
    int index;
//  if (fActive) {
        for (index = 0; index < fAnimators.count(); index++) {
            if (closedYet == false) {
                SkDebugf(">\n");
                closedYet = true;
            }
            SkAnimateBase* animator = fAnimators[index];
            animator->dump(maker);
//      }
    }
    SkDisplayList::fIndent -= 4;
    SkDisplayList::fDumpIndex = save;
    if (closedYet)
        dumpEnd(maker);
    else
        SkDebugf("/>\n");
}
Ejemplo n.º 30
0
bool GrDrawingManager::ProgramUnitTest(GrContext* context, int maxStages, int maxLevels) {
    GrDrawingManager* drawingManager = context->contextPriv().drawingManager();

    sk_sp<GrTextureProxy> proxies[2];

    // setup dummy textures
    GrSurfaceDesc dummyDesc;
    dummyDesc.fFlags = kRenderTarget_GrSurfaceFlag;
    dummyDesc.fOrigin = kBottomLeft_GrSurfaceOrigin;
    dummyDesc.fConfig = kRGBA_8888_GrPixelConfig;
    dummyDesc.fWidth = 34;
    dummyDesc.fHeight = 18;
    proxies[0] = GrSurfaceProxy::MakeDeferred(context->resourceProvider(),
                                              dummyDesc, SkBudgeted::kNo, nullptr, 0);
    dummyDesc.fFlags = kNone_GrSurfaceFlags;
    dummyDesc.fOrigin = kTopLeft_GrSurfaceOrigin;
    dummyDesc.fConfig = kAlpha_8_GrPixelConfig;
    dummyDesc.fWidth = 16;
    dummyDesc.fHeight = 22;
    proxies[1] = GrSurfaceProxy::MakeDeferred(context->resourceProvider(),
                                              dummyDesc, SkBudgeted::kNo, nullptr, 0);

    if (!proxies[0] || !proxies[1]) {
        SkDebugf("Could not allocate dummy textures");
        return false;
    }

    // dummy scissor state
    GrScissorState scissor;

    SkRandom random;
    static const int NUM_TESTS = 1024;
    for (int t = 0; t < NUM_TESTS; t++) {
        // setup random render target(can fail)
        sk_sp<GrRenderTargetContext> renderTargetContext(random_render_target_context(
            context, &random, context->caps()));
        if (!renderTargetContext) {
            SkDebugf("Could not allocate renderTargetContext");
            return false;
        }

        GrPaint paint;
        GrProcessorTestData ptd(&random, context, renderTargetContext.get(), proxies);
        set_random_color_coverage_stages(&paint, &ptd, maxStages, maxLevels);
        set_random_xpf(&paint, &ptd);
        set_random_state(&paint, &random);
        GrDrawRandomOp(&random, renderTargetContext.get(), std::move(paint));
    }
    // Flush everything, test passes if flush is successful(ie, no asserts are hit, no crashes)
    drawingManager->flush(nullptr);

    // Validate that GrFPs work correctly without an input.
    sk_sp<GrRenderTargetContext> renderTargetContext(context->makeDeferredRenderTargetContext(
                                                                           SkBackingFit::kExact,
                                                                           kRenderTargetWidth,
                                                                           kRenderTargetHeight,
                                                                           kRGBA_8888_GrPixelConfig,
                                                                           nullptr));
    if (!renderTargetContext) {
        SkDebugf("Could not allocate a renderTargetContext");
        return false;
    }

    int fpFactoryCnt = GrProcessorTestFactory<GrFragmentProcessor>::Count();
    for (int i = 0; i < fpFactoryCnt; ++i) {
        // Since FP factories internally randomize, call each 10 times.
        for (int j = 0; j < 10; ++j) {
            GrProcessorTestData ptd(&random, context, renderTargetContext.get(), proxies);

            GrPaint paint;
            paint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
            sk_sp<GrFragmentProcessor> fp(
                GrProcessorTestFactory<GrFragmentProcessor>::MakeIdx(i, &ptd));
            sk_sp<GrFragmentProcessor> blockFP(
                BlockInputFragmentProcessor::Make(std::move(fp)));
            paint.addColorFragmentProcessor(std::move(blockFP));
            GrDrawRandomOp(&random, renderTargetContext.get(), std::move(paint));
            drawingManager->flush(nullptr);
        }
    }

    return true;
}