Example #1
0
    virtual void onDrawContent(SkCanvas* canvas) {
        SkIRect srcRect;
        SkRect dstRect;
        SkPaint paint;
        paint.setFilterBitmap(true);

        // Test that bitmap draws from malloc-backed bitmaps respect
        // the constrained texture domain.
        srcRect.setXYWH(1, 1, 3, 3);
        dstRect.setXYWH(5.0f, 5.0f, 305.0f, 305.0f);
        canvas->drawBitmapRect(fBM, &srcRect, dstRect, &paint);

        // Test that bitmap draws across separate devices also respect
        // the constrainted texture domain.
        // Note:  GPU-backed bitmaps follow a different rendering path
        // when copying from one GPU device to another.
        SkAutoTUnref<SkDevice> secondDevice(canvas->createCompatibleDevice(
                SkBitmap::kARGB_8888_Config, 5, 5, true));
        SkCanvas secondCanvas(secondDevice.get());

        srcRect.setXYWH(1, 1, 3, 3);
        dstRect.setXYWH(1.0f, 1.0f, 3.0f, 3.0f);
        secondCanvas.drawBitmapRect(fBM, &srcRect, dstRect, &paint);

        SkBitmap deviceBitmap = secondDevice->accessBitmap(false);

        srcRect.setXYWH(1, 1, 3, 3);
        dstRect.setXYWH(405.0f, 5.0f, 305.0f, 305.0f);
        canvas->drawBitmapRect(deviceBitmap, &srcRect, dstRect, &paint);

        // Test that bitmap blurring using a subrect
        // renders correctly
        srcRect.setXYWH(1, 1, 3, 3);
        dstRect.setXYWH(5.0f, 405.0f, 305.0f, 305.0f);
        SkMaskFilter* mf = SkBlurMaskFilter::Create(
            5,
            SkBlurMaskFilter::kNormal_BlurStyle,
            SkBlurMaskFilter::kHighQuality_BlurFlag |
            SkBlurMaskFilter::kIgnoreTransform_BlurFlag);
        paint.setMaskFilter(mf)->unref();
        canvas->drawBitmapRect(deviceBitmap, &srcRect, dstRect, &paint);

        // Blur and a rotation + NULL src rect
        // This should not trigger the texture domain code
        // but it will test a code path in SkGpuDevice::drawBitmap
        // that handles blurs with rects transformed to non-
        // orthogonal rects. It also tests the NULL src rect handling
    mf = SkBlurMaskFilter::Create(
            5,
            SkBlurMaskFilter::kNormal_BlurStyle,
            SkBlurMaskFilter::kHighQuality_BlurFlag);
        paint.setMaskFilter(mf)->unref();

        dstRect.setXYWH(-150.0f, -150.0f, 300.0f, 300.0f);
        canvas->translate(550, 550);
        canvas->rotate(45);
        canvas->drawBitmapRect(fBM, NULL, dstRect, &paint);
    }
Example #2
0
void GrVkGpuRTCommandBuffer::onClearStencilClip(const GrFixedClip& clip, bool insideStencilMask) {
    SkASSERT(!clip.hasWindowRectangles());

    CommandBufferInfo& cbInfo = fCommandBufferInfos[fCurrentCmdInfo];

    GrStencilAttachment* sb = fRenderTarget->renderTargetPriv().getStencilAttachment();
    // this should only be called internally when we know we have a
    // stencil buffer.
    SkASSERT(sb);
    int stencilBitCount = sb->bits();

    // The contract with the callers does not guarantee that we preserve all bits in the stencil
    // during this clear. Thus we will clear the entire stencil to the desired value.

    VkClearDepthStencilValue vkStencilColor;
    memset(&vkStencilColor, 0, sizeof(VkClearDepthStencilValue));
    if (insideStencilMask) {
        vkStencilColor.stencil = (1 << (stencilBitCount - 1));
    } else {
        vkStencilColor.stencil = 0;
    }

    VkClearRect clearRect;
    // Flip rect if necessary
    SkIRect vkRect;
    if (!clip.scissorEnabled()) {
        vkRect.setXYWH(0, 0, fRenderTarget->width(), fRenderTarget->height());
    } else if (kBottomLeft_GrSurfaceOrigin != fOrigin) {
        vkRect = clip.scissorRect();
    } else {
        const SkIRect& scissor = clip.scissorRect();
        vkRect.setLTRB(scissor.fLeft, fRenderTarget->height() - scissor.fBottom,
                       scissor.fRight, fRenderTarget->height() - scissor.fTop);
    }

    clearRect.rect.offset = { vkRect.fLeft, vkRect.fTop };
    clearRect.rect.extent = { (uint32_t)vkRect.width(), (uint32_t)vkRect.height() };

    clearRect.baseArrayLayer = 0;
    clearRect.layerCount = 1;

    uint32_t stencilIndex;
    SkAssertResult(cbInfo.fRenderPass->stencilAttachmentIndex(&stencilIndex));

    VkClearAttachment attachment;
    attachment.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
    attachment.colorAttachment = 0; // this value shouldn't matter
    attachment.clearValue.depthStencil = vkStencilColor;

    cbInfo.currentCmdBuf()->clearAttachments(fGpu, 1, &attachment, 1, &clearRect);
    cbInfo.fIsEmpty = false;

    // Update command buffer bounds
    if (!clip.scissorEnabled()) {
        cbInfo.fBounds.join(fRenderTarget->getBoundsRect());
    } else {
        cbInfo.fBounds.join(SkRect::Make(clip.scissorRect()));
    }
}
    virtual void onDraw(SkCanvas* canvas) {
        drawBG(canvas);

        SkBitmap sprite;
        sprite.setConfig(SkBitmap::kARGB_8888_Config, 4, 4, 4*sizeof(SkColor));
        const SkColor spriteData[16] = {
            SK_ColorBLACK,  SK_ColorCYAN,    SK_ColorMAGENTA, SK_ColorYELLOW,
            SK_ColorBLACK,  SK_ColorWHITE,   SK_ColorBLACK,   SK_ColorRED,
            SK_ColorGREEN,  SK_ColorBLACK,   SK_ColorWHITE,   SK_ColorBLUE,
            SK_ColorYELLOW, SK_ColorMAGENTA, SK_ColorCYAN,    SK_ColorBLACK
        };
        sprite.allocPixels();
        sprite.lockPixels();
        SkPMColor* addr = sprite.getAddr32(0, 0);
        for (size_t i = 0; i < SK_ARRAY_COUNT(spriteData); ++i) {
            addr[i] = SkPreMultiplyColor(spriteData[i]);
        }
        sprite.unlockPixels();

        // We draw a magnified subrect of the sprite
        // sample interpolation may cause color bleeding around edges
        // the subrect is a pure white area
        SkIRect srcRect;
        SkRect dstRect;
        SkPaint paint;
        paint.setFilterBitmap(true);
        //First row : full texture with and without filtering
        srcRect.setXYWH(0, 0, 4, 4);
        dstRect.setXYWH(SkIntToScalar(0), SkIntToScalar(0)
                        , SkIntToScalar(100), SkIntToScalar(100));
        canvas->drawBitmapRect(sprite, &srcRect, dstRect, &paint);
        dstRect.setXYWH(SkIntToScalar(100), SkIntToScalar(0)
                        , SkIntToScalar(100), SkIntToScalar(100));
        canvas->drawBitmapRect(sprite, &srcRect, dstRect);
        //Second row : sub rect of texture with and without filtering
        srcRect.setXYWH(1, 1, 2, 2);
        dstRect.setXYWH(SkIntToScalar(25), SkIntToScalar(125)
                        , SkIntToScalar(50), SkIntToScalar(50));
        canvas->drawBitmapRect(sprite, &srcRect, dstRect, &paint);
        dstRect.setXYWH(SkIntToScalar(125), SkIntToScalar(125)
                        , SkIntToScalar(50), SkIntToScalar(50));
        canvas->drawBitmapRect(sprite, &srcRect, dstRect);
    }
SkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pixels,
        size_t rowBytes, const AndroidOptions& options) {
    // We should only call this function when sampling.
    SkASSERT(options.fSampleSize > 1);

    // Create options struct for the codec.
    SkCodec::Options sampledOptions;
    sampledOptions.fZeroInitialized = options.fZeroInitialized;
    sampledOptions.fPremulBehavior = SkTransferFunctionBehavior::kIgnore;

    // FIXME: This was already called by onGetAndroidPixels. Can we reduce that?
    int sampleSize = options.fSampleSize;
    int nativeSampleSize;
    SkISize nativeSize = this->accountForNativeScaling(&sampleSize, &nativeSampleSize);

    // Check if there is a subset.
    SkIRect subset;
    int subsetY = 0;
    int subsetWidth = nativeSize.width();
    int subsetHeight = nativeSize.height();
    if (options.fSubset) {
        // We will need to know about subsetting in the y-dimension in order to use the
        // scanline decoder.
        // Update the subset to account for scaling done by this->codec().
        const SkIRect* subsetPtr = options.fSubset;

        // Do the divide ourselves, instead of calling get_scaled_dimension. If
        // X and Y are 0, they should remain 0, rather than being upgraded to 1
        // due to being smaller than the sampleSize.
        const int subsetX = subsetPtr->x() / nativeSampleSize;
        subsetY = subsetPtr->y() / nativeSampleSize;

        subsetWidth = get_scaled_dimension(subsetPtr->width(), nativeSampleSize);
        subsetHeight = get_scaled_dimension(subsetPtr->height(), nativeSampleSize);

        // The scanline decoder only needs to be aware of subsetting in the x-dimension.
        subset.setXYWH(subsetX, 0, subsetWidth, nativeSize.height());
        sampledOptions.fSubset = &subset;
    }

    // Since we guarantee that output dimensions are always at least one (even if the sampleSize
    // is greater than a given dimension), the input sampleSize is not always the sampleSize that
    // we use in practice.
    const int sampleX = subsetWidth / info.width();
    const int sampleY = subsetHeight / info.height();

    const int samplingOffsetY = get_start_coord(sampleY);
    const int startY = samplingOffsetY + subsetY;
    const int dstHeight = info.height();

    const SkImageInfo nativeInfo = info.makeWH(nativeSize.width(), nativeSize.height());

    {
        // Although startScanlineDecode expects the bottom and top to match the
        // SkImageInfo, startIncrementalDecode uses them to determine which rows to
        // decode.
        SkCodec::Options incrementalOptions = sampledOptions;
        SkIRect incrementalSubset;
        if (sampledOptions.fSubset) {
            incrementalSubset.fTop = subsetY;
            incrementalSubset.fBottom = subsetY + subsetHeight;
            incrementalSubset.fLeft = sampledOptions.fSubset->fLeft;
            incrementalSubset.fRight = sampledOptions.fSubset->fRight;
            incrementalOptions.fSubset = &incrementalSubset;
        }
        const SkCodec::Result startResult = this->codec()->startIncrementalDecode(nativeInfo,
                pixels, rowBytes, &incrementalOptions);
        if (SkCodec::kSuccess == startResult) {
            SkSampler* sampler = this->codec()->getSampler(true);
            if (!sampler) {
                return SkCodec::kUnimplemented;
            }

            if (sampler->setSampleX(sampleX) != info.width()) {
                return SkCodec::kInvalidScale;
            }
            if (get_scaled_dimension(subsetHeight, sampleY) != info.height()) {
                return SkCodec::kInvalidScale;
            }

            sampler->setSampleY(sampleY);

            int rowsDecoded;
            const SkCodec::Result incResult = this->codec()->incrementalDecode(&rowsDecoded);
            if (incResult == SkCodec::kSuccess) {
                return SkCodec::kSuccess;
            }
            SkASSERT(incResult == SkCodec::kIncompleteInput || incResult == SkCodec::kErrorInInput);

            SkASSERT(rowsDecoded <= info.height());
            this->codec()->fillIncompleteImage(info, pixels, rowBytes, options.fZeroInitialized,
                                               info.height(), rowsDecoded);
            return incResult;
        } else if (startResult != SkCodec::kUnimplemented) {
            return startResult;
        } // kUnimplemented means use the old method.
    }

    // Start the scanline decode.
    SkCodec::Result result = this->codec()->startScanlineDecode(nativeInfo,
            &sampledOptions);
    if (SkCodec::kSuccess != result) {
        return result;
    }

    SkSampler* sampler = this->codec()->getSampler(true);
    if (!sampler) {
        return SkCodec::kUnimplemented;
    }

    if (sampler->setSampleX(sampleX) != info.width()) {
        return SkCodec::kInvalidScale;
    }
    if (get_scaled_dimension(subsetHeight, sampleY) != info.height()) {
        return SkCodec::kInvalidScale;
    }

    switch(this->codec()->getScanlineOrder()) {
        case SkCodec::kTopDown_SkScanlineOrder: {
            if (!this->codec()->skipScanlines(startY)) {
                this->codec()->fillIncompleteImage(info, pixels, rowBytes, options.fZeroInitialized,
                        dstHeight, 0);
                return SkCodec::kIncompleteInput;
            }
            void* pixelPtr = pixels;
            for (int y = 0; y < dstHeight; y++) {
                if (1 != this->codec()->getScanlines(pixelPtr, 1, rowBytes)) {
                    this->codec()->fillIncompleteImage(info, pixels, rowBytes,
                            options.fZeroInitialized, dstHeight, y + 1);
                    return SkCodec::kIncompleteInput;
                }
                if (y < dstHeight - 1) {
                    if (!this->codec()->skipScanlines(sampleY - 1)) {
                        this->codec()->fillIncompleteImage(info, pixels, rowBytes,
                                options.fZeroInitialized, dstHeight, y + 1);
                        return SkCodec::kIncompleteInput;
                    }
                }
                pixelPtr = SkTAddOffset<void>(pixelPtr, rowBytes);
            }
            return SkCodec::kSuccess;
        }
        case SkCodec::kBottomUp_SkScanlineOrder: {
            // Note that these modes do not support subsetting.
            SkASSERT(0 == subsetY && nativeSize.height() == subsetHeight);
            int y;
            for (y = 0; y < nativeSize.height(); y++) {
                int srcY = this->codec()->nextScanline();
                if (is_coord_necessary(srcY, sampleY, dstHeight)) {
                    void* pixelPtr = SkTAddOffset<void>(pixels,
                            rowBytes * get_dst_coord(srcY, sampleY));
                    if (1 != this->codec()->getScanlines(pixelPtr, 1, rowBytes)) {
                        break;
                    }
                } else {
                    if (!this->codec()->skipScanlines(1)) {
                        break;
                    }
                }
            }

            if (nativeSize.height() == y) {
                return SkCodec::kSuccess;
            }

            // We handle filling uninitialized memory here instead of using this->codec().
            // this->codec() does not know that we are sampling.
            const uint64_t fillValue = this->codec()->getFillValue(info);
            const SkImageInfo fillInfo = info.makeWH(info.width(), 1);
            for (; y < nativeSize.height(); y++) {
                int srcY = this->codec()->outputScanline(y);
                if (!is_coord_necessary(srcY, sampleY, dstHeight)) {
                    continue;
                }

                void* rowPtr = SkTAddOffset<void>(pixels, rowBytes * get_dst_coord(srcY, sampleY));
                SkSampler::Fill(fillInfo, rowPtr, rowBytes, fillValue, options.fZeroInitialized);
            }
            return SkCodec::kIncompleteInput;
        }
        default:
            SkASSERT(false);
            return SkCodec::kUnimplemented;
    }
}
    void onDraw(SkCanvas* canvas) override {
        SkRect dstRect = { 0, 0, SkIntToScalar(64), SkIntToScalar(64)};
        static const int kMaxSrcRectSize = 1 << (SkNextLog2(gBmpSize) + 2);

        static const int kPadX = 30;
        static const int kPadY = 40;
        SkPaint paint;
        paint.setAlpha(0x20);
        canvas->drawBitmapRect(fLargeBitmap, SkRect::MakeIWH(gSize, gSize), &paint);
        canvas->translate(SK_Scalar1 * kPadX / 2,
                          SK_Scalar1 * kPadY / 2);
        SkPaint blackPaint;
        SkScalar titleHeight = SK_Scalar1 * 24;
        blackPaint.setColor(SK_ColorBLACK);
        blackPaint.setTextSize(titleHeight);
        blackPaint.setAntiAlias(true);
        sk_tool_utils::set_portable_typeface(&blackPaint);
        SkString title;
        title.printf("Bitmap size: %d x %d", gBmpSize, gBmpSize);
        canvas->drawText(title.c_str(), title.size(), 0,
                         titleHeight, blackPaint);

        canvas->translate(0, SK_Scalar1 * kPadY / 2  + titleHeight);
        int rowCount = 0;
        canvas->save();
        for (int w = 1; w <= kMaxSrcRectSize; w *= 4) {
            for (int h = 1; h <= kMaxSrcRectSize; h *= 4) {

                SkIRect srcRect = SkIRect::MakeXYWH((gBmpSize - w) / 2, (gBmpSize - h) / 2, w, h);
                fProc(canvas, fImage, fLargeBitmap, srcRect, dstRect);

                SkString label;
                label.appendf("%d x %d", w, h);
                blackPaint.setAntiAlias(true);
                blackPaint.setStyle(SkPaint::kFill_Style);
                blackPaint.setTextSize(SK_Scalar1 * 10);
                SkScalar baseline = dstRect.height() +
                                    blackPaint.getTextSize() + SK_Scalar1 * 3;
                canvas->drawText(label.c_str(), label.size(),
                                    0, baseline,
                                    blackPaint);
                blackPaint.setStyle(SkPaint::kStroke_Style);
                blackPaint.setStrokeWidth(SK_Scalar1);
                blackPaint.setAntiAlias(false);
                canvas->drawRect(dstRect, blackPaint);

                canvas->translate(dstRect.width() + SK_Scalar1 * kPadX, 0);
                ++rowCount;
                if ((dstRect.width() + kPadX) * rowCount > gSize) {
                    canvas->restore();
                    canvas->translate(0, dstRect.height() + SK_Scalar1 * kPadY);
                    canvas->save();
                    rowCount = 0;
                }
            }
        }

        {
            // test the following code path:
            // SkGpuDevice::drawPath() -> SkGpuDevice::drawWithMaskFilter()
            SkIRect srcRect;
            SkPaint paint;
            SkBitmap bm;

            bm = make_chessbm(5, 5);
            paint.setFilterQuality(kLow_SkFilterQuality);

            srcRect.setXYWH(1, 1, 3, 3);
            SkMaskFilter* mf = SkBlurMaskFilter::Create(
                kNormal_SkBlurStyle,
                SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(5)),
                SkBlurMaskFilter::kHighQuality_BlurFlag |
                SkBlurMaskFilter::kIgnoreTransform_BlurFlag);
            paint.setMaskFilter(mf)->unref();
            canvas->drawBitmapRect(bm, srcRect, dstRect, &paint);
        }
    }
Example #6
0
void GrVkGpuRTCommandBuffer::onClear(const GrFixedClip& clip, const SkPMColor4f& color) {
    GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(fRenderTarget);

    // parent class should never let us get here with no RT
    SkASSERT(!clip.hasWindowRectangles());

    CommandBufferInfo& cbInfo = fCommandBufferInfos[fCurrentCmdInfo];

    VkClearColorValue vkColor = {{color.fR, color.fG, color.fB, color.fA}};

    if (cbInfo.fIsEmpty && !clip.scissorEnabled()) {
        // Change the render pass to do a clear load
        GrVkRenderPass::LoadStoreOps vkColorOps(VK_ATTACHMENT_LOAD_OP_CLEAR,
                                                VK_ATTACHMENT_STORE_OP_STORE);
        // Preserve the stencil buffer's load & store settings
        GrVkRenderPass::LoadStoreOps vkStencilOps(fVkStencilLoadOp, fVkStencilStoreOp);

        const GrVkRenderPass* oldRP = cbInfo.fRenderPass;

        const GrVkResourceProvider::CompatibleRPHandle& rpHandle =
            vkRT->compatibleRenderPassHandle();
        if (rpHandle.isValid()) {
            cbInfo.fRenderPass = fGpu->resourceProvider().findRenderPass(rpHandle,
                                                                         vkColorOps,
                                                                         vkStencilOps);
        } else {
            cbInfo.fRenderPass = fGpu->resourceProvider().findRenderPass(*vkRT,
                                                                         vkColorOps,
                                                                         vkStencilOps);
        }

        SkASSERT(cbInfo.fRenderPass->isCompatible(*oldRP));
        oldRP->unref(fGpu);

        cbInfo.fColorClearValue.color = {{color.fR, color.fG, color.fB, color.fA}};
        cbInfo.fLoadStoreState = LoadStoreState::kStartsWithClear;
        // Update command buffer bounds
        cbInfo.fBounds.join(fRenderTarget->getBoundsRect());
        return;
    }

    // We always do a sub rect clear with clearAttachments since we are inside a render pass
    VkClearRect clearRect;
    // Flip rect if necessary
    SkIRect vkRect;
    if (!clip.scissorEnabled()) {
        vkRect.setXYWH(0, 0, fRenderTarget->width(), fRenderTarget->height());
    } else if (kBottomLeft_GrSurfaceOrigin != fOrigin) {
        vkRect = clip.scissorRect();
    } else {
        const SkIRect& scissor = clip.scissorRect();
        vkRect.setLTRB(scissor.fLeft, fRenderTarget->height() - scissor.fBottom,
                       scissor.fRight, fRenderTarget->height() - scissor.fTop);
    }
    clearRect.rect.offset = { vkRect.fLeft, vkRect.fTop };
    clearRect.rect.extent = { (uint32_t)vkRect.width(), (uint32_t)vkRect.height() };
    clearRect.baseArrayLayer = 0;
    clearRect.layerCount = 1;

    uint32_t colorIndex;
    SkAssertResult(cbInfo.fRenderPass->colorAttachmentIndex(&colorIndex));

    VkClearAttachment attachment;
    attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
    attachment.colorAttachment = colorIndex;
    attachment.clearValue.color = vkColor;

    cbInfo.currentCmdBuf()->clearAttachments(fGpu, 1, &attachment, 1, &clearRect);
    cbInfo.fIsEmpty = false;

    // Update command buffer bounds
    if (!clip.scissorEnabled()) {
        cbInfo.fBounds.join(fRenderTarget->getBoundsRect());
    } else {
        cbInfo.fBounds.join(SkRect::Make(clip.scissorRect()));
    }
    return;
}
void GrVkGpuCommandBuffer::onClear(GrRenderTarget* target, const GrFixedClip& clip, GrColor color) {
    // parent class should never let us get here with no RT
    SkASSERT(target);
    SkASSERT(!clip.hasWindowRectangles());

    VkClearColorValue vkColor;
    GrColorToRGBAFloat(color, vkColor.float32);

    GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(target);

    if (fIsEmpty && !clip.scissorEnabled()) {
        // We will change the render pass to do a clear load instead
        GrVkRenderPass::LoadStoreOps vkColorOps(VK_ATTACHMENT_LOAD_OP_CLEAR,
                                                VK_ATTACHMENT_STORE_OP_STORE);
        GrVkRenderPass::LoadStoreOps vkStencilOps(VK_ATTACHMENT_LOAD_OP_LOAD,
                                                  VK_ATTACHMENT_STORE_OP_STORE);

        const GrVkRenderPass* oldRP = fRenderPass;

        const GrVkResourceProvider::CompatibleRPHandle& rpHandle =
            vkRT->compatibleRenderPassHandle();
        if (rpHandle.isValid()) {
            fRenderPass = fGpu->resourceProvider().findRenderPass(rpHandle,
                                                                  vkColorOps,
                                                                  vkStencilOps);
        } else {
            fRenderPass = fGpu->resourceProvider().findRenderPass(*vkRT,
                                                                  vkColorOps,
                                                                  vkStencilOps);
        }

        SkASSERT(fRenderPass->isCompatible(*oldRP));
        oldRP->unref(fGpu);

        GrColorToRGBAFloat(color, fColorClearValue.color.float32);
        fStartsWithClear = true;
        return;
    }

    // We always do a sub rect clear with clearAttachments since we are inside a render pass
    VkClearRect clearRect;
    // Flip rect if necessary
    SkIRect vkRect;
    if (!clip.scissorEnabled()) {
        vkRect.setXYWH(0, 0, vkRT->width(), vkRT->height());
    } else if (kBottomLeft_GrSurfaceOrigin != vkRT->origin()) {
        vkRect = clip.scissorRect();
    } else {
        const SkIRect& scissor = clip.scissorRect();
        vkRect.setLTRB(scissor.fLeft, vkRT->height() - scissor.fBottom,
                       scissor.fRight, vkRT->height() - scissor.fTop);
    }
    clearRect.rect.offset = { vkRect.fLeft, vkRect.fTop };
    clearRect.rect.extent = { (uint32_t)vkRect.width(), (uint32_t)vkRect.height() };
    clearRect.baseArrayLayer = 0;
    clearRect.layerCount = 1;

    uint32_t colorIndex;
    SkAssertResult(fRenderPass->colorAttachmentIndex(&colorIndex));

    VkClearAttachment attachment;
    attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
    attachment.colorAttachment = colorIndex;
    attachment.clearValue.color = vkColor;

    fCommandBuffer->clearAttachments(fGpu, 1, &attachment, 1, &clearRect);
    fIsEmpty = false;
    return;
}
Example #8
0
SkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pixels,
        size_t rowBytes, const AndroidOptions& options) {
    // We should only call this function when sampling.
    SkASSERT(options.fSampleSize > 1);

    // Create options struct for the codec.
    SkCodec::Options sampledOptions;
    sampledOptions.fZeroInitialized = options.fZeroInitialized;

    // FIXME: This was already called by onGetAndroidPixels. Can we reduce that?
    int sampleSize = options.fSampleSize;
    int nativeSampleSize;
    SkISize nativeSize = this->accountForNativeScaling(&sampleSize, &nativeSampleSize);

    // Check if there is a subset.
    SkIRect subset;
    int subsetY = 0;
    int subsetWidth = nativeSize.width();
    int subsetHeight = nativeSize.height();
    if (options.fSubset) {
        // We will need to know about subsetting in the y-dimension in order to use the
        // scanline decoder.
        // Update the subset to account for scaling done by this->codec().
        SkIRect* subsetPtr = options.fSubset;

        // Do the divide ourselves, instead of calling get_scaled_dimension. If
        // X and Y are 0, they should remain 0, rather than being upgraded to 1
        // due to being smaller than the sampleSize.
        const int subsetX = subsetPtr->x() / nativeSampleSize;
        subsetY = subsetPtr->y() / nativeSampleSize;

        subsetWidth = get_scaled_dimension(subsetPtr->width(), nativeSampleSize);
        subsetHeight = get_scaled_dimension(subsetPtr->height(), nativeSampleSize);

        // The scanline decoder only needs to be aware of subsetting in the x-dimension.
        subset.setXYWH(subsetX, 0, subsetWidth, nativeSize.height());
        sampledOptions.fSubset = &subset;
    }

    // Start the scanline decode.
    SkCodec::Result result = this->codec()->startScanlineDecode(
            info.makeWH(nativeSize.width(), nativeSize.height()), &sampledOptions,
            options.fColorPtr, options.fColorCount);
    if (SkCodec::kSuccess != result) {
        return result;
    }

    SkSampler* sampler = this->codec()->getSampler(true);
    if (!sampler) {
        return SkCodec::kUnimplemented;
    }

    // Since we guarantee that output dimensions are always at least one (even if the sampleSize
    // is greater than a given dimension), the input sampleSize is not always the sampleSize that
    // we use in practice.
    const int sampleX = subsetWidth / info.width();
    const int sampleY = subsetHeight / info.height();
    if (sampler->setSampleX(sampleX) != info.width()) {
        return SkCodec::kInvalidScale;
    }
    if (get_scaled_dimension(subsetHeight, sampleY) != info.height()) {
        return SkCodec::kInvalidScale;
    }

    const int samplingOffsetY = get_start_coord(sampleY);
    const int startY = samplingOffsetY + subsetY;
    int dstHeight = info.height();
    switch(this->codec()->getScanlineOrder()) {
        case SkCodec::kTopDown_SkScanlineOrder: {
            if (!this->codec()->skipScanlines(startY)) {
                this->codec()->fillIncompleteImage(info, pixels, rowBytes, options.fZeroInitialized,
                        dstHeight, 0);
                return SkCodec::kIncompleteInput;
            }
            void* pixelPtr = pixels;
            for (int y = 0; y < dstHeight; y++) {
                if (1 != this->codec()->getScanlines(pixelPtr, 1, rowBytes)) {
                    this->codec()->fillIncompleteImage(info, pixels, rowBytes,
                            options.fZeroInitialized, dstHeight, y + 1);
                    return SkCodec::kIncompleteInput;
                }
                if (y < dstHeight - 1) {
                    if (!this->codec()->skipScanlines(sampleY - 1)) {
                        this->codec()->fillIncompleteImage(info, pixels, rowBytes,
                                options.fZeroInitialized, dstHeight, y + 1);
                        return SkCodec::kIncompleteInput;
                    }
                }
                pixelPtr = SkTAddOffset<void>(pixelPtr, rowBytes);
            }
            return SkCodec::kSuccess;
        }
        case SkCodec::kOutOfOrder_SkScanlineOrder:
        case SkCodec::kBottomUp_SkScanlineOrder: {
            // Note that these modes do not support subsetting.
            SkASSERT(0 == subsetY && nativeSize.height() == subsetHeight);
            int y;
            for (y = 0; y < nativeSize.height(); y++) {
                int srcY = this->codec()->nextScanline();
                if (is_coord_necessary(srcY, sampleY, dstHeight)) {
                    void* pixelPtr = SkTAddOffset<void>(pixels,
                            rowBytes * get_dst_coord(srcY, sampleY));
                    if (1 != this->codec()->getScanlines(pixelPtr, 1, rowBytes)) {
                        break;
                    }
                } else {
                    if (!this->codec()->skipScanlines(1)) {
                        break;
                    }
                }
            }

            if (nativeSize.height() == y) {
                return SkCodec::kSuccess;
            }

            // We handle filling uninitialized memory here instead of using this->codec().
            // this->codec() does not know that we are sampling.
            const uint32_t fillValue = this->codec()->getFillValue(info.colorType());
            const SkImageInfo fillInfo = info.makeWH(info.width(), 1);
            for (; y < nativeSize.height(); y++) {
                int srcY = this->codec()->outputScanline(y);
                if (!is_coord_necessary(srcY, sampleY, dstHeight)) {
                    continue;
                }

                void* rowPtr = SkTAddOffset<void>(pixels, rowBytes * get_dst_coord(srcY, sampleY));
                SkSampler::Fill(fillInfo, rowPtr, rowBytes, fillValue, options.fZeroInitialized);
            }
            return SkCodec::kIncompleteInput;
        }
        case SkCodec::kNone_SkScanlineOrder: {
            const int linesNeeded = subsetHeight - samplingOffsetY;
            SkAutoTMalloc<uint8_t> storage(linesNeeded * rowBytes);
            uint8_t* storagePtr = storage.get();

            if (!this->codec()->skipScanlines(startY)) {
                this->codec()->fillIncompleteImage(info, pixels, rowBytes, options.fZeroInitialized,
                        dstHeight, 0);
                return SkCodec::kIncompleteInput;
            }
            int scanlines = this->codec()->getScanlines(storagePtr, linesNeeded, rowBytes);

            for (int y = 0; y < dstHeight; y++) {
                memcpy(pixels, storagePtr, info.minRowBytes());
                storagePtr += sampleY * rowBytes;
                pixels = SkTAddOffset<void>(pixels, rowBytes);
            }

            if (scanlines < dstHeight) {
                // this->codec() has already handled filling uninitialized memory.
                return SkCodec::kIncompleteInput;
            }
            return SkCodec::kSuccess;
        }
        default:
            SkASSERT(false);
            return SkCodec::kUnimplemented;
    }
}