void GrContext::drawFontCache(const SkRect& rect, GrMaskFormat format, const SkPaint& paint, GrRenderTarget* target) { GrBatchFontCache* cache = this->getBatchFontCache(); GrTexture* atlas = cache->getTexture(format); SkAutoTUnref<GrDrawContext> drawContext(this->drawContext(target)); // TODO: add drawContext method to encapsulate this. GrPaint grPaint; SkMatrix mat; mat.reset(); if (!SkPaintToGrPaint(this, paint, mat, &grPaint)) { return; } SkMatrix textureMat; textureMat.reset(); // TODO: use setScaleTranslate() textureMat[SkMatrix::kMScaleX] = 1.0f/rect.width(); textureMat[SkMatrix::kMScaleY] = 1.0f/rect.height(); textureMat[SkMatrix::kMTransX] = -rect.fLeft/rect.width(); textureMat[SkMatrix::kMTransY] = -rect.fTop/rect.height(); grPaint.addColorTextureProcessor(atlas, textureMat); GrClip clip; drawContext->drawRect(clip, grPaint, mat, rect); }
sk_sp<SkSpecialImage> SkImageFilter::DrawWithFP(GrContext* context, sk_sp<GrFragmentProcessor> fp, const SkIRect& bounds, sk_sp<SkColorSpace> colorSpace) { GrPaint paint; paint.addColorFragmentProcessor(std::move(fp)); paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); sk_sp<GrDrawContext> drawContext(context->makeDrawContext(SkBackingFit::kApprox, bounds.width(), bounds.height(), kRGBA_8888_GrPixelConfig, std::move(colorSpace))); if (!drawContext) { return nullptr; } SkIRect dstIRect = SkIRect::MakeWH(bounds.width(), bounds.height()); SkRect srcRect = SkRect::Make(bounds); SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height()); GrFixedClip clip(dstIRect); drawContext->fillRectToRect(clip, paint, SkMatrix::I(), dstRect, srcRect); return SkSpecialImage::MakeFromGpu(dstIRect, kNeedNewImageUniqueID_SpecialImage, drawContext->asTexture(), sk_ref_sp(drawContext->getColorSpace())); }
DEF_GPUTEST_FOR_ALL_CONTEXTS(TessellatingPathRendererTests, reporter, ctxInfo) { sk_sp<GrDrawContext> drawContext(ctxInfo.grContext()->newDrawContext(SkBackingFit::kApprox, 800, 800, kSkia8888_GrPixelConfig, 0, kTopLeft_GrSurfaceOrigin)); if (!drawContext) { return; } GrTestTarget tt; ctxInfo.grContext()->getTestTarget(&tt, drawContext); GrDrawTarget* dt = tt.target(); GrResourceProvider* rp = tt.resourceProvider(); test_path(dt, drawContext.get(), rp, create_path_0()); test_path(dt, drawContext.get(), rp, create_path_1()); test_path(dt, drawContext.get(), rp, create_path_2()); test_path(dt, drawContext.get(), rp, create_path_3()); test_path(dt, drawContext.get(), rp, create_path_4()); test_path(dt, drawContext.get(), rp, create_path_5()); test_path(dt, drawContext.get(), rp, create_path_6()); test_path(dt, drawContext.get(), rp, create_path_7()); test_path(dt, drawContext.get(), rp, create_path_8()); test_path(dt, drawContext.get(), rp, create_path_9()); test_path(dt, drawContext.get(), rp, create_path_10()); test_path(dt, drawContext.get(), rp, create_path_11()); test_path(dt, drawContext.get(), rp, create_path_12()); test_path(dt, drawContext.get(), rp, create_path_13()); test_path(dt, drawContext.get(), rp, create_path_14()); test_path(dt, drawContext.get(), rp, create_path_15()); }
sk_sp<SkSpecialImage> SkImageFilter::DrawWithFP(GrContext* context, sk_sp<GrFragmentProcessor> fp, const SkIRect& bounds) { GrPaint paint; paint.addColorFragmentProcessor(fp.get()); paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); GrSurfaceDesc desc; desc.fFlags = kRenderTarget_GrSurfaceFlag; desc.fWidth = bounds.width(); desc.fHeight = bounds.height(); desc.fConfig = kRGBA_8888_GrPixelConfig; sk_sp<GrTexture> dst(context->textureProvider()->createApproxTexture(desc)); if (!dst) { return nullptr; } sk_sp<GrDrawContext> drawContext(context->drawContext(sk_ref_sp(dst->asRenderTarget()))); if (!drawContext) { return nullptr; } SkRect srcRect = SkRect::Make(bounds); SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height()); GrClip clip(dstRect); drawContext->fillRectToRect(clip, paint, SkMatrix::I(), dstRect, srcRect); return SkSpecialImage::MakeFromGpu(SkIRect::MakeWH(bounds.width(), bounds.height()), kNeedNewImageUniqueID_SpecialImage, std::move(dst)); }
GrTexture* GrYUVProvider::refAsTexture(GrContext* ctx, const GrSurfaceDesc& desc, bool useCache) { SkYUVPlanesCache::Info yuvInfo; void* planes[3]; YUVScoper scoper; if (!scoper.init(this, &yuvInfo, planes, useCache)) { return nullptr; } GrSurfaceDesc yuvDesc; yuvDesc.fConfig = kAlpha_8_GrPixelConfig; SkAutoTUnref<GrTexture> yuvTextures[3]; for (int i = 0; i < 3; ++i) { yuvDesc.fWidth = yuvInfo.fSize[i].fWidth; yuvDesc.fHeight = yuvInfo.fSize[i].fHeight; // TODO: why do we need this check? bool needsExactTexture = (yuvDesc.fWidth != yuvInfo.fSize[0].fWidth) || (yuvDesc.fHeight != yuvInfo.fSize[0].fHeight); if (needsExactTexture) { yuvTextures[i].reset(ctx->textureProvider()->createTexture(yuvDesc, true)); } else { yuvTextures[i].reset(ctx->textureProvider()->createApproxTexture(yuvDesc)); } if (!yuvTextures[i] || !yuvTextures[i]->writePixels(0, 0, yuvDesc.fWidth, yuvDesc.fHeight, yuvDesc.fConfig, planes[i], yuvInfo.fRowBytes[i])) { return nullptr; } } GrSurfaceDesc rtDesc = desc; rtDesc.fFlags = rtDesc.fFlags | kRenderTarget_GrSurfaceFlag; SkAutoTUnref<GrTexture> result(ctx->textureProvider()->createTexture(rtDesc, true, nullptr, 0)); if (!result) { return nullptr; } GrRenderTarget* renderTarget = result->asRenderTarget(); SkASSERT(renderTarget); GrPaint paint; SkAutoTUnref<GrFragmentProcessor> yuvToRgbProcessor( GrYUVtoRGBEffect::Create(yuvTextures[0], yuvTextures[1], yuvTextures[2], yuvInfo.fSize, yuvInfo.fColorSpace)); paint.addColorFragmentProcessor(yuvToRgbProcessor); const SkRect r = SkRect::MakeIWH(yuvInfo.fSize[0].fWidth, yuvInfo.fSize[0].fHeight); SkAutoTUnref<GrDrawContext> drawContext(ctx->drawContext()); if (!drawContext) { return nullptr; } drawContext->drawRect(renderTarget, GrClip::WideOpen(), paint, SkMatrix::I(), r); return result.detach(); }
void Curve::draw(const QRectF& viewPort, qreal scale, qreal thickness, bool antiAliasing) { DrawContext drawContext(viewPort, drawer, scale, thickness, antiAliasing); for (QVector<CurveBranch*>::Iterator it = branches.begin(); it != branches.end(); it++) { (*it)->draw(drawContext); } }
bool SkImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const Context& ctx, SkBitmap* result, SkIPoint* offset) const { #if SK_SUPPORT_GPU SkBitmap input = src; SkASSERT(fInputCount == 1); SkIPoint srcOffset = SkIPoint::Make(0, 0); if (!this->filterInputGPU(0, proxy, src, ctx, &input, &srcOffset)) { return false; } GrTexture* srcTexture = input.getTexture(); SkIRect bounds; if (!this->applyCropRect(ctx, proxy, input, &srcOffset, &bounds, &input)) { return false; } SkRect srcRect = SkRect::Make(bounds); SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height()); GrContext* context = srcTexture->getContext(); GrSurfaceDesc desc; desc.fFlags = kRenderTarget_GrSurfaceFlag, desc.fWidth = bounds.width(); desc.fHeight = bounds.height(); desc.fConfig = kRGBA_8888_GrPixelConfig; SkAutoTUnref<GrTexture> dst(context->textureProvider()->createTexture(desc, GrTextureProvider::FromImageFilter(ctx.sizeConstraint()))); if (!dst) { return false; } // setup new clip GrClip clip(dstRect); GrFragmentProcessor* fp; offset->fX = bounds.left(); offset->fY = bounds.top(); bounds.offset(-srcOffset); SkMatrix matrix(ctx.ctm()); matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top())); GrPaint paint; if (this->asFragmentProcessor(&fp, srcTexture, matrix, bounds)) { SkASSERT(fp); paint.addColorFragmentProcessor(fp)->unref(); paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(dst->asRenderTarget())); if (drawContext) { drawContext->fillRectToRect(clip, paint, SkMatrix::I(), dstRect, srcRect); WrapTexture(dst, bounds.width(), bounds.height(), result); return true; } } #endif return false; }
// Create a mask of 'devPath' and place the result in 'mask'. static GrTexture* create_mask_GPU(GrContext* context, SkRect* maskRect, const SkPath& devPath, const GrStrokeInfo& strokeInfo, bool doAA, int sampleCnt) { // This mask will ultimately be drawn as a non-AA rect (see draw_mask). // Non-AA rects have a bad habit of snapping arbitrarily. Integerize here // so the mask draws in a reproducible manner. *maskRect = SkRect::Make(maskRect->roundOut()); GrSurfaceDesc desc; desc.fFlags = kRenderTarget_GrSurfaceFlag; desc.fWidth = SkScalarCeilToInt(maskRect->width()); desc.fHeight = SkScalarCeilToInt(maskRect->height()); desc.fSampleCnt = doAA ? sampleCnt : 0; // We actually only need A8, but it often isn't supported as a // render target so default to RGBA_8888 desc.fConfig = kRGBA_8888_GrPixelConfig; if (context->caps()->isConfigRenderable(kAlpha_8_GrPixelConfig, desc.fSampleCnt > 0)) { desc.fConfig = kAlpha_8_GrPixelConfig; } GrTexture* mask = context->textureProvider()->createApproxTexture(desc); if (nullptr == mask) { return nullptr; } SkRect clipRect = SkRect::MakeWH(maskRect->width(), maskRect->height()); SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(mask->asRenderTarget())); if (!drawContext) { return nullptr; } drawContext->clear(nullptr, 0x0, true); GrPaint tempPaint; tempPaint.setAntiAlias(doAA); tempPaint.setCoverageSetOpXPFactory(SkRegion::kReplace_Op); // setup new clip GrClip clip(clipRect); // Draw the mask into maskTexture with the path's integerized top-left at // the origin using tempPaint. SkMatrix translate; translate.setTranslate(-maskRect->fLeft, -maskRect->fTop); drawContext->drawPath(clip, tempPaint, translate, devPath, strokeInfo); return mask; }
void GrRenderTarget::discard() { // go through context so that all necessary flushing occurs GrContext* context = this->getContext(); if (!context) { return; } sk_sp<GrDrawContext> drawContext(context->drawContext(sk_ref_sp(this), nullptr)); if (!drawContext) { return; } drawContext->discard(); }
void OnPaint( wxPaintEvent &event ) { wxPaintDC drawContext(this); if(currentSample.IsOk()) { wxSize drawSize=currentSample.GetSize(); wxSize clientSize=this->GetClientSize(); if(drawSize!=clientSize) { RefreshDrawingArea(); } drawSize=currentSample.GetSize(); drawContext.Blit(0,0,drawSize.GetWidth(),drawSize.GetHeight(),¤tSample,0,0); } }
// Create a mask of 'devPath' and place the result in 'mask'. static sk_sp<GrTexture> create_mask_GPU(GrContext* context, const SkIRect& maskRect, const SkPath& devPath, SkStrokeRec::InitStyle fillOrHairline, bool doAA, int sampleCnt) { if (!doAA) { // Don't need MSAA if mask isn't AA sampleCnt = 0; } // We actually only need A8, but it often isn't supported as a // render target so default to RGBA_8888 GrPixelConfig config = kRGBA_8888_GrPixelConfig; if (context->caps()->isConfigRenderable(kAlpha_8_GrPixelConfig, sampleCnt > 0)) { config = kAlpha_8_GrPixelConfig; } sk_sp<GrDrawContext> drawContext(context->newDrawContext(SkBackingFit::kApprox, maskRect.width(), maskRect.height(), config, sampleCnt)); if (!drawContext) { return nullptr; } drawContext->clear(nullptr, 0x0, true); GrPaint tempPaint; tempPaint.setAntiAlias(doAA); tempPaint.setCoverageSetOpXPFactory(SkRegion::kReplace_Op); // setup new clip const SkIRect clipRect = SkIRect::MakeWH(maskRect.width(), maskRect.height()); GrFixedClip clip(clipRect); // Draw the mask into maskTexture with the path's integerized top-left at // the origin using tempPaint. SkMatrix translate; translate.setTranslate(-SkIntToScalar(maskRect.fLeft), -SkIntToScalar(maskRect.fTop)); drawContext->drawPath(clip, tempPaint, translate, devPath, GrStyle(fillOrHairline)); return drawContext->asTexture();; }
DEF_GPUTEST_FOR_ALL_CONTEXTS(VertexAttributeCount, reporter, ctxInfo) { GrContext* context = ctxInfo.grContext(); sk_sp<GrDrawContext> drawContext(context->newDrawContext(SkBackingFit::kApprox, 1, 1, kRGBA_8888_GrPixelConfig)); if (!drawContext) { ERRORF(reporter, "Could not create draw context."); return; } int attribCnt = context->caps()->maxVertexAttributes(); if (!attribCnt) { ERRORF(reporter, "No attributes allowed?!"); return; } context->flush(); context->resetGpuStats(); #if GR_GPU_STATS REPORTER_ASSERT(reporter, context->getGpu()->stats()->numDraws() == 0); REPORTER_ASSERT(reporter, context->getGpu()->stats()->numFailedDraws() == 0); #endif SkAutoTUnref<GrDrawBatch> batch; GrPaint grPaint; // This one should succeed. batch.reset(new Batch(attribCnt)); drawContext->drawContextPriv().testingOnly_drawBatch(grPaint, batch); context->flush(); #if GR_GPU_STATS REPORTER_ASSERT(reporter, context->getGpu()->stats()->numDraws() == 1); REPORTER_ASSERT(reporter, context->getGpu()->stats()->numFailedDraws() == 0); #endif context->resetGpuStats(); // This one should fail. batch.reset(new Batch(attribCnt+1)); drawContext->drawContextPriv().testingOnly_drawBatch(grPaint, batch); context->flush(); #if GR_GPU_STATS REPORTER_ASSERT(reporter, context->getGpu()->stats()->numDraws() == 0); REPORTER_ASSERT(reporter, context->getGpu()->stats()->numFailedDraws() == 1); #endif }
DEF_GPUTEST_FOR_ALL_GL_CONTEXTS(AADistanceFieldPathRenderer, reporter, ctxInfo) { // The DF PR only works with contexts that support derivatives if (!ctxInfo.grContext()->caps()->shaderCaps()->shaderDerivativeSupport()) { return; } sk_sp<GrDrawContext> drawContext(ctxInfo.grContext()->newDrawContext(SkBackingFit::kApprox, 800, 800, kSkia8888_GrPixelConfig, 0, kTopLeft_GrSurfaceOrigin)); if (!drawContext) { return; } GrAADistanceFieldPathRenderer dfpr; GrTestTarget tt; ctxInfo.grContext()->getTestTarget(&tt, drawContext); GrResourceProvider* rp = tt.resourceProvider(); test_far_from_origin(drawContext.get(), &dfpr, rp); ctxInfo.grContext()->flush(); }
// Create a mask of 'devPath' and place the result in 'mask'. static sk_sp<GrTexture> create_mask_GPU(GrContext* context, const SkIRect& maskRect, const SkPath& devPath, SkStrokeRec::InitStyle fillOrHairline, bool doAA, int sampleCnt) { if (!doAA) { // Don't need MSAA if mask isn't AA sampleCnt = 0; } sk_sp<GrDrawContext> drawContext(context->makeDrawContextWithFallback(SkBackingFit::kApprox, maskRect.width(), maskRect.height(), kAlpha_8_GrPixelConfig, nullptr, sampleCnt)); if (!drawContext) { return nullptr; } drawContext->clear(nullptr, 0x0, true); GrPaint tempPaint; tempPaint.setAntiAlias(doAA); tempPaint.setCoverageSetOpXPFactory(SkRegion::kReplace_Op); // setup new clip const SkIRect clipRect = SkIRect::MakeWH(maskRect.width(), maskRect.height()); GrFixedClip clip(clipRect); // Draw the mask into maskTexture with the path's integerized top-left at // the origin using tempPaint. SkMatrix translate; translate.setTranslate(-SkIntToScalar(maskRect.fLeft), -SkIntToScalar(maskRect.fTop)); drawContext->drawPath(clip, tempPaint, translate, devPath, GrStyle(fillOrHairline)); return drawContext->asTexture();; }
sk_sp<SkSpecialImage> SkImageFilter::DrawWithFP(GrContext* context, sk_sp<GrFragmentProcessor> fp, const SkIRect& bounds) { GrPaint paint; paint.addColorFragmentProcessor(fp.get()); paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); sk_sp<GrDrawContext> drawContext(context->newDrawContext(GrContext::kLoose_BackingFit, bounds.width(), bounds.height(), kRGBA_8888_GrPixelConfig)); if (!drawContext) { return nullptr; } SkRect srcRect = SkRect::Make(bounds); SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height()); GrClip clip(dstRect); drawContext->fillRectToRect(clip, paint, SkMatrix::I(), dstRect, srcRect); return SkSpecialImage::MakeFromGpu(SkIRect::MakeWH(bounds.width(), bounds.height()), kNeedNewImageUniqueID_SpecialImage, drawContext->asTexture()); }
static sk_sp<GrDrawContext> random_draw_context(GrContext* context, SkRandom* random, const GrCaps* caps) { GrSurfaceOrigin origin = random->nextBool() ? kTopLeft_GrSurfaceOrigin : kBottomLeft_GrSurfaceOrigin; int sampleCnt = random->nextBool() ? SkTMin(4, caps->maxSampleCount()) : 0; GrUniqueKey key; static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); GrUniqueKey::Builder builder(&key, kDomain, 2); builder[0] = origin; builder[1] = sampleCnt; builder.finish(); sk_sp<GrTexture> texture(context->textureProvider()->findAndRefTextureByUniqueKey(key)); if (texture) { sk_sp<GrRenderTarget> rt(sk_ref_sp(texture->asRenderTarget())); return context->drawContext(std::move(rt)); } sk_sp<GrDrawContext> drawContext(context->newDrawContext(SkBackingFit::kExact, kRenderTargetWidth, kRenderTargetHeight, kRGBA_8888_GrPixelConfig, sampleCnt, origin)); if (!drawContext) { return nullptr; } // TODO: need a real way to do this via the drawContext texture = drawContext->asTexture(); context->textureProvider()->assignUniqueKeyToTexture(key, texture.get()); return drawContext; }
sk_sp<SkSpecialImage> SkDisplacementMapEffect::onFilterImage(SkSpecialImage* source, const Context& ctx, SkIPoint* offset) const { SkIPoint colorOffset = SkIPoint::Make(0, 0); sk_sp<SkSpecialImage> color(this->filterInput(1, source, ctx, &colorOffset)); if (!color) { return nullptr; } SkIPoint displOffset = SkIPoint::Make(0, 0); sk_sp<SkSpecialImage> displ(this->filterInput(0, source, ctx, &displOffset)); if (!displ) { return nullptr; } const SkIRect srcBounds = SkIRect::MakeXYWH(colorOffset.x(), colorOffset.y(), color->width(), color->height()); // Both paths do bounds checking on color pixel access, we don't need to // pad the color bitmap to bounds here. SkIRect bounds; if (!this->applyCropRect(ctx, srcBounds, &bounds)) { return nullptr; } SkIRect displBounds; displ = this->applyCropRect(ctx, displ.get(), &displOffset, &displBounds); if (!displ) { return nullptr; } if (!bounds.intersect(displBounds)) { return nullptr; } const SkIRect colorBounds = bounds.makeOffset(-colorOffset.x(), -colorOffset.y()); SkVector scale = SkVector::Make(fScale, fScale); ctx.ctm().mapVectors(&scale, 1); #if SK_SUPPORT_GPU if (source->isTextureBacked()) { GrContext* context = source->getContext(); sk_sp<GrTexture> colorTexture(color->asTextureRef(context)); sk_sp<GrTexture> displTexture(displ->asTextureRef(context)); if (!colorTexture || !displTexture) { return nullptr; } GrSurfaceDesc desc; desc.fFlags = kRenderTarget_GrSurfaceFlag; desc.fWidth = bounds.width(); desc.fHeight = bounds.height(); desc.fConfig = kSkia8888_GrPixelConfig; SkAutoTUnref<GrTexture> dst(context->textureProvider()->createApproxTexture(desc)); if (!dst) { return nullptr; } GrPaint paint; SkMatrix offsetMatrix = GrCoordTransform::MakeDivByTextureWHMatrix(displTexture.get()); offsetMatrix.preTranslate(SkIntToScalar(colorOffset.fX - displOffset.fX), SkIntToScalar(colorOffset.fY - displOffset.fY)); paint.addColorFragmentProcessor( GrDisplacementMapEffect::Create(fXChannelSelector, fYChannelSelector, scale, displTexture.get(), offsetMatrix, colorTexture.get(), SkISize::Make(color->width(), color->height())))->unref(); paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); SkMatrix matrix; matrix.setTranslate(-SkIntToScalar(colorBounds.x()), -SkIntToScalar(colorBounds.y())); SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(dst->asRenderTarget())); if (!drawContext) { return nullptr; } drawContext->drawRect(GrClip::WideOpen(), paint, matrix, SkRect::Make(colorBounds)); offset->fX = bounds.left(); offset->fY = bounds.top(); return SkSpecialImage::MakeFromGpu(SkIRect::MakeWH(bounds.width(), bounds.height()), kNeedNewImageUniqueID_SpecialImage, dst); } #endif SkBitmap colorBM, displBM; if (!color->getROPixels(&colorBM) || !displ->getROPixels(&displBM)) { return nullptr; } if ((colorBM.colorType() != kN32_SkColorType) || (displBM.colorType() != kN32_SkColorType)) { return nullptr; } SkAutoLockPixels colorLock(colorBM), displLock(displBM); if (!colorBM.getPixels() || !displBM.getPixels()) { return nullptr; } SkImageInfo info = SkImageInfo::MakeN32(bounds.width(), bounds.height(), colorBM.alphaType()); SkBitmap dst; if (!dst.tryAllocPixels(info)) { return nullptr; } SkAutoLockPixels dstLock(dst); computeDisplacement(fXChannelSelector, fYChannelSelector, scale, &dst, displBM, colorOffset - displOffset, colorBM, colorBounds); offset->fX = bounds.left(); offset->fY = bounds.top(); return SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(bounds.width(), bounds.height()), dst); }
bool SkDisplacementMapEffect::filterImageGPU(Proxy* proxy, const SkBitmap& src, const Context& ctx, SkBitmap* result, SkIPoint* offset) const { SkBitmap colorBM = src; SkIPoint colorOffset = SkIPoint::Make(0, 0); if (!this->filterInputGPU(1, proxy, src, ctx, &colorBM, &colorOffset)) { return false; } SkBitmap displacementBM = src; SkIPoint displacementOffset = SkIPoint::Make(0, 0); if (!this->filterInputGPU(0, proxy, src, ctx, &displacementBM, &displacementOffset)) { return false; } SkIRect bounds; // Since GrDisplacementMapEffect does bounds checking on color pixel access, we don't need to // pad the color bitmap to bounds here. if (!this->applyCropRect(ctx, colorBM, colorOffset, &bounds)) { return false; } SkIRect displBounds; if (!this->applyCropRect(ctx, proxy, displacementBM, &displacementOffset, &displBounds, &displacementBM)) { return false; } if (!bounds.intersect(displBounds)) { return false; } GrTexture* color = colorBM.getTexture(); GrTexture* displacement = displacementBM.getTexture(); GrContext* context = color->getContext(); GrSurfaceDesc desc; desc.fFlags = kRenderTarget_GrSurfaceFlag; desc.fWidth = bounds.width(); desc.fHeight = bounds.height(); desc.fConfig = kSkia8888_GrPixelConfig; auto constraint = GrTextureProvider::FromImageFilter(ctx.sizeConstraint()); SkAutoTUnref<GrTexture> dst(context->textureProvider()->createTexture(desc, constraint)); if (!dst) { return false; } SkVector scale = SkVector::Make(fScale, fScale); ctx.ctm().mapVectors(&scale, 1); GrPaint paint; SkMatrix offsetMatrix = GrCoordTransform::MakeDivByTextureWHMatrix(displacement); offsetMatrix.preTranslate(SkIntToScalar(colorOffset.fX - displacementOffset.fX), SkIntToScalar(colorOffset.fY - displacementOffset.fY)); paint.addColorFragmentProcessor( GrDisplacementMapEffect::Create(fXChannelSelector, fYChannelSelector, scale, displacement, offsetMatrix, color, colorBM.dimensions()))->unref(); paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); SkIRect colorBounds = bounds; colorBounds.offset(-colorOffset); SkMatrix matrix; matrix.setTranslate(-SkIntToScalar(colorBounds.x()), -SkIntToScalar(colorBounds.y())); SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(dst->asRenderTarget())); if (!drawContext) { return false; } drawContext->drawRect(GrClip::WideOpen(), paint, matrix, SkRect::Make(colorBounds)); offset->fX = bounds.left(); offset->fY = bounds.top(); WrapTexture(dst, bounds.width(), bounds.height(), result); return true; }
bool SkXfermodeImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const Context& ctx, SkBitmap* result, SkIPoint* offset) const { SkBitmap background = src; SkIPoint backgroundOffset = SkIPoint::Make(0, 0); if (!this->filterInputGPU(0, proxy, src, ctx, &background, &backgroundOffset)) { return false; } GrTexture* backgroundTex = background.getTexture(); if (nullptr == backgroundTex) { SkASSERT(false); return false; } SkBitmap foreground = src; SkIPoint foregroundOffset = SkIPoint::Make(0, 0); if (!this->filterInputGPU(1, proxy, src, ctx, &foreground, &foregroundOffset)) { return false; } GrTexture* foregroundTex = foreground.getTexture(); GrContext* context = foregroundTex->getContext(); SkIRect bounds = background.bounds().makeOffset(backgroundOffset.x(), backgroundOffset.y()); bounds.join(foreground.bounds().makeOffset(foregroundOffset.x(), foregroundOffset.y())); if (bounds.isEmpty()) { return false; } const GrFragmentProcessor* xferFP = nullptr; GrSurfaceDesc desc; desc.fFlags = kRenderTarget_GrSurfaceFlag; desc.fWidth = bounds.width(); desc.fHeight = bounds.height(); desc.fConfig = kSkia8888_GrPixelConfig; SkAutoTUnref<GrTexture> dst(context->textureProvider()->createApproxTexture(desc)); if (!dst) { return false; } GrPaint paint; SkMatrix backgroundMatrix; backgroundMatrix.setIDiv(backgroundTex->width(), backgroundTex->height()); backgroundMatrix.preTranslate(SkIntToScalar(-backgroundOffset.fX), SkIntToScalar(-backgroundOffset.fY)); SkAutoTUnref<const GrFragmentProcessor> bgFP(GrTextureDomainEffect::Create( backgroundTex, backgroundMatrix, GrTextureDomain::MakeTexelDomain(backgroundTex, background.bounds()), GrTextureDomain::kDecal_Mode, GrTextureParams::kNone_FilterMode) ); if (!fMode || !fMode->asFragmentProcessor(&xferFP, bgFP)) { // canFilterImageGPU() should've taken care of this SkASSERT(false); return false; } SkMatrix foregroundMatrix; foregroundMatrix.setIDiv(foregroundTex->width(), foregroundTex->height()); foregroundMatrix.preTranslate(SkIntToScalar(-foregroundOffset.fX), SkIntToScalar(-foregroundOffset.fY)); SkAutoTUnref<const GrFragmentProcessor> foregroundFP(GrTextureDomainEffect::Create( foregroundTex, foregroundMatrix, GrTextureDomain::MakeTexelDomain(foregroundTex, foreground.bounds()), GrTextureDomain::kDecal_Mode, GrTextureParams::kNone_FilterMode) ); paint.addColorFragmentProcessor(foregroundFP.get()); if (xferFP) { paint.addColorFragmentProcessor(xferFP)->unref(); } paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(dst->asRenderTarget())); if (!drawContext) { return false; } SkMatrix matrix; matrix.setTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top())); drawContext->drawRect(GrClip::WideOpen(), paint, matrix, SkRect::Make(bounds)); offset->fX = bounds.left(); offset->fY = bounds.top(); GrWrapTextureInBitmap(dst, bounds.width(), bounds.height(), false, result); return true; }
sk_sp<SkSpecialImage> SkBlurImageFilter::onFilterImage(SkSpecialImage* source, const Context& ctx, SkIPoint* offset) const { SkIPoint inputOffset = SkIPoint::Make(0, 0); sk_sp<SkSpecialImage> input(this->filterInput(0, source, ctx, &inputOffset)); if (!input) { return nullptr; } SkIRect inputBounds = SkIRect::MakeXYWH(inputOffset.fX, inputOffset.fY, input->width(), input->height()); SkIRect dstBounds; if (!this->applyCropRect(this->mapContext(ctx), inputBounds, &dstBounds)) { return nullptr; } if (!inputBounds.intersect(dstBounds)) { return nullptr; } const SkVector sigma = map_sigma(fSigma, ctx.ctm()); #if SK_SUPPORT_GPU if (source->isTextureBacked()) { GrContext* context = source->getContext(); sk_sp<GrTexture> inputTexture(input->asTextureRef(context)); SkASSERT(inputTexture); if (0 == sigma.x() && 0 == sigma.y()) { offset->fX = inputBounds.x(); offset->fY = inputBounds.y(); return input->makeSubset(inputBounds.makeOffset(-inputOffset.x(), -inputOffset.y())); } offset->fX = dstBounds.fLeft; offset->fY = dstBounds.fTop; inputBounds.offset(-inputOffset); dstBounds.offset(-inputOffset); sk_sp<GrDrawContext> drawContext(SkGpuBlurUtils::GaussianBlur( context, inputTexture.get(), source->props().isGammaCorrect(), dstBounds, &inputBounds, sigma.x(), sigma.y())); if (!drawContext) { return nullptr; } return SkSpecialImage::MakeFromGpu(SkIRect::MakeWH(dstBounds.width(), dstBounds.height()), kNeedNewImageUniqueID_SpecialImage, drawContext->asTexture(), &source->props()); } #endif int kernelSizeX, kernelSizeX3, lowOffsetX, highOffsetX; int kernelSizeY, kernelSizeY3, lowOffsetY, highOffsetY; get_box3_params(sigma.x(), &kernelSizeX, &kernelSizeX3, &lowOffsetX, &highOffsetX); get_box3_params(sigma.y(), &kernelSizeY, &kernelSizeY3, &lowOffsetY, &highOffsetY); if (kernelSizeX < 0 || kernelSizeY < 0) { return nullptr; } if (kernelSizeX == 0 && kernelSizeY == 0) { offset->fX = inputBounds.x(); offset->fY = inputBounds.y(); return input->makeSubset(inputBounds.makeOffset(-inputOffset.x(), -inputOffset.y())); } SkBitmap inputBM; if (!input->getROPixels(&inputBM)) { return nullptr; } if (inputBM.colorType() != kN32_SkColorType) { return nullptr; } SkImageInfo info = SkImageInfo::Make(dstBounds.width(), dstBounds.height(), inputBM.colorType(), inputBM.alphaType()); SkBitmap tmp, dst; if (!tmp.tryAllocPixels(info) || !dst.tryAllocPixels(info)) { return nullptr; } SkAutoLockPixels inputLock(inputBM), tmpLock(tmp), dstLock(dst); offset->fX = dstBounds.fLeft; offset->fY = dstBounds.fTop; SkPMColor* t = tmp.getAddr32(0, 0); SkPMColor* d = dst.getAddr32(0, 0); int w = dstBounds.width(), h = dstBounds.height(); const SkPMColor* s = inputBM.getAddr32(inputBounds.x() - inputOffset.x(), inputBounds.y() - inputOffset.y()); inputBounds.offset(-dstBounds.x(), -dstBounds.y()); dstBounds.offset(-dstBounds.x(), -dstBounds.y()); SkIRect inputBoundsT = SkIRect::MakeLTRB(inputBounds.top(), inputBounds.left(), inputBounds.bottom(), inputBounds.right()); SkIRect dstBoundsT = SkIRect::MakeWH(dstBounds.height(), dstBounds.width()); int sw = int(inputBM.rowBytes() >> 2); /** * * In order to make memory accesses cache-friendly, we reorder the passes to * use contiguous memory reads wherever possible. * * For example, the 6 passes of the X-and-Y blur case are rewritten as * follows. Instead of 3 passes in X and 3 passes in Y, we perform * 2 passes in X, 1 pass in X transposed to Y on write, 2 passes in X, * then 1 pass in X transposed to Y on write. * * +----+ +----+ +----+ +---+ +---+ +---+ +----+ * + AB + ----> | AB | ----> | AB | -----> | A | ----> | A | ----> | A | -----> | AB | * +----+ blurX +----+ blurX +----+ blurXY | B | blurX | B | blurX | B | blurXY +----+ * +---+ +---+ +---+ * * In this way, two of the y-blurs become x-blurs applied to transposed * images, and all memory reads are contiguous. */ if (kernelSizeX > 0 && kernelSizeY > 0) { SkOpts::box_blur_xx(s, sw, inputBounds, t, kernelSizeX, lowOffsetX, highOffsetX, w, h); SkOpts::box_blur_xx(t, w, dstBounds, d, kernelSizeX, highOffsetX, lowOffsetX, w, h); SkOpts::box_blur_xy(d, w, dstBounds, t, kernelSizeX3, highOffsetX, highOffsetX, w, h); SkOpts::box_blur_xx(t, h, dstBoundsT, d, kernelSizeY, lowOffsetY, highOffsetY, h, w); SkOpts::box_blur_xx(d, h, dstBoundsT, t, kernelSizeY, highOffsetY, lowOffsetY, h, w); SkOpts::box_blur_xy(t, h, dstBoundsT, d, kernelSizeY3, highOffsetY, highOffsetY, h, w); } else if (kernelSizeX > 0) { SkOpts::box_blur_xx(s, sw, inputBounds, d, kernelSizeX, lowOffsetX, highOffsetX, w, h); SkOpts::box_blur_xx(d, w, dstBounds, t, kernelSizeX, highOffsetX, lowOffsetX, w, h); SkOpts::box_blur_xx(t, w, dstBounds, d, kernelSizeX3, highOffsetX, highOffsetX, w, h); } else if (kernelSizeY > 0) { SkOpts::box_blur_yx(s, sw, inputBoundsT, d, kernelSizeY, lowOffsetY, highOffsetY, h, w); SkOpts::box_blur_xx(d, h, dstBoundsT, t, kernelSizeY, highOffsetY, lowOffsetY, h, w); SkOpts::box_blur_xy(t, h, dstBoundsT, d, kernelSizeY3, highOffsetY, highOffsetY, h, w); } return SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(dstBounds.width(), dstBounds.height()), dst, &source->props()); }
SkImage* SkImage::NewFromYUVTexturesCopy(GrContext* ctx , SkYUVColorSpace colorSpace, const GrBackendObject yuvTextureHandles[3], const SkISize yuvSizes[3], GrSurfaceOrigin origin) { const SkSurface::Budgeted budgeted = SkSurface::kYes_Budgeted; if (yuvSizes[0].fWidth <= 0 || yuvSizes[0].fHeight <= 0 || yuvSizes[1].fWidth <= 0 || yuvSizes[1].fHeight <= 0 || yuvSizes[2].fWidth <= 0 || yuvSizes[2].fHeight <= 0) { return nullptr; } static const GrPixelConfig kConfig = kAlpha_8_GrPixelConfig; GrBackendTextureDesc yDesc; yDesc.fConfig = kConfig; yDesc.fOrigin = origin; yDesc.fSampleCnt = 0; yDesc.fTextureHandle = yuvTextureHandles[0]; yDesc.fWidth = yuvSizes[0].fWidth; yDesc.fHeight = yuvSizes[0].fHeight; GrBackendTextureDesc uDesc; uDesc.fConfig = kConfig; uDesc.fOrigin = origin; uDesc.fSampleCnt = 0; uDesc.fTextureHandle = yuvTextureHandles[1]; uDesc.fWidth = yuvSizes[1].fWidth; uDesc.fHeight = yuvSizes[1].fHeight; GrBackendTextureDesc vDesc; vDesc.fConfig = kConfig; vDesc.fOrigin = origin; vDesc.fSampleCnt = 0; vDesc.fTextureHandle = yuvTextureHandles[2]; vDesc.fWidth = yuvSizes[2].fWidth; vDesc.fHeight = yuvSizes[2].fHeight; SkAutoTUnref<GrTexture> yTex(ctx->textureProvider()->wrapBackendTexture( yDesc, kBorrow_GrWrapOwnership)); SkAutoTUnref<GrTexture> uTex(ctx->textureProvider()->wrapBackendTexture( uDesc, kBorrow_GrWrapOwnership)); SkAutoTUnref<GrTexture> vTex(ctx->textureProvider()->wrapBackendTexture( vDesc, kBorrow_GrWrapOwnership)); if (!yTex || !uTex || !vTex) { return nullptr; } GrSurfaceDesc dstDesc; // Needs to be a render target in order to draw to it for the yuv->rgb conversion. dstDesc.fFlags = kRenderTarget_GrSurfaceFlag; dstDesc.fOrigin = origin; dstDesc.fWidth = yuvSizes[0].fWidth; dstDesc.fHeight = yuvSizes[0].fHeight; dstDesc.fConfig = kRGBA_8888_GrPixelConfig; dstDesc.fSampleCnt = 0; SkAutoTUnref<GrTexture> dst(ctx->textureProvider()->createTexture(dstDesc, true)); if (!dst) { return nullptr; } GrPaint paint; paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); paint.addColorFragmentProcessor(GrYUVtoRGBEffect::Create(paint.getProcessorDataManager(), yTex, uTex, vTex, yuvSizes, colorSpace))->unref(); const SkRect rect = SkRect::MakeWH(SkIntToScalar(dstDesc.fWidth), SkIntToScalar(dstDesc.fHeight)); SkAutoTUnref<GrDrawContext> drawContext(ctx->drawContext()); if (!drawContext) { return nullptr; } drawContext->drawRect(dst->asRenderTarget(), GrClip::WideOpen(), paint, SkMatrix::I(), rect); ctx->flushSurfaceWrites(dst); return new SkImage_Gpu(dstDesc.fWidth, dstDesc.fHeight, kNeedNewImageUniqueID, kOpaque_SkAlphaType, dst, budgeted); }
bool GrDrawingManager::ProgramUnitTest(GrContext* context, int maxStages) { GrDrawingManager* drawingManager = context->drawingManager(); // setup dummy textures GrSurfaceDesc dummyDesc; dummyDesc.fFlags = kRenderTarget_GrSurfaceFlag; dummyDesc.fConfig = kSkia8888_GrPixelConfig; dummyDesc.fWidth = 34; dummyDesc.fHeight = 18; SkAutoTUnref<GrTexture> dummyTexture1( context->textureProvider()->createTexture(dummyDesc, SkBudgeted::kNo, nullptr, 0)); dummyDesc.fFlags = kNone_GrSurfaceFlags; dummyDesc.fConfig = kAlpha_8_GrPixelConfig; dummyDesc.fWidth = 16; dummyDesc.fHeight = 22; SkAutoTUnref<GrTexture> dummyTexture2( context->textureProvider()->createTexture(dummyDesc, SkBudgeted::kNo, nullptr, 0)); if (!dummyTexture1 || ! dummyTexture2) { SkDebugf("Could not allocate dummy textures"); return false; } GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()}; // 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<GrDrawContext> drawContext(random_draw_context(context, &random, context->caps())); if (!drawContext) { SkDebugf("Could not allocate drawContext"); return false; } GrPaint grPaint; SkAutoTUnref<GrDrawBatch> batch(GrRandomDrawBatch(&random, context)); SkASSERT(batch); GrProcessorTestData ptd(&random, context, context->caps(), drawContext.get(), dummyTextures); set_random_color_coverage_stages(&grPaint, &ptd, maxStages); set_random_xpf(&grPaint, &ptd); bool snapToCenters = set_random_state(&grPaint, &random); const GrUserStencilSettings* uss = get_random_stencil(&random); drawContext->drawContextPriv().testingOnly_drawBatch(grPaint, batch, uss, snapToCenters); } // Flush everything, test passes if flush is successful(ie, no asserts are hit, no crashes) drawingManager->flush(); // Validate that GrFPs work correctly without an input. sk_sp<GrDrawContext> drawContext(context->newDrawContext(SkBackingFit::kExact, kRenderTargetWidth, kRenderTargetHeight, kRGBA_8888_GrPixelConfig)); if (!drawContext) { SkDebugf("Could not allocate a drawContext"); 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) { SkAutoTUnref<GrDrawBatch> batch(GrRandomDrawBatch(&random, context)); SkASSERT(batch); GrProcessorTestData ptd(&random, context, context->caps(), drawContext.get(), dummyTextures); GrPaint grPaint; grPaint.setXPFactory(GrPorterDuffXPFactory::Make(SkXfermode::kSrc_Mode)); sk_sp<GrFragmentProcessor> fp( GrProcessorTestFactory<GrFragmentProcessor>::MakeIdx(i, &ptd)); sk_sp<GrFragmentProcessor> blockFP( BlockInputFragmentProcessor::Make(std::move(fp))); grPaint.addColorFragmentProcessor(std::move(blockFP)); drawContext->drawContextPriv().testingOnly_drawBatch(grPaint, batch); drawingManager->flush(); } } return true; }
// creates a new texture that is the input texture scaled up. If optionalKey is valid it will be // set on the new texture. stretch controls whether the scaling is done using nearest or bilerp // filtering and the size to stretch the texture to. GrTexture* stretch_texture(GrTexture* inputTexture, const SkGrStretch& stretch, SkPixelRef* pixelRef, const GrUniqueKey& optionalKey) { SkASSERT(SkGrStretch::kNone_Type != stretch.fType); GrContext* context = inputTexture->getContext(); SkASSERT(context); const GrCaps* caps = context->caps(); // Either it's a cache miss or the original wasn't cached to begin with. GrSurfaceDesc rtDesc = inputTexture->desc(); rtDesc.fFlags = rtDesc.fFlags | kRenderTarget_GrSurfaceFlag; rtDesc.fWidth = stretch.fWidth; rtDesc.fHeight = stretch.fHeight; rtDesc.fConfig = GrMakePixelConfigUncompressed(rtDesc.fConfig); // If the config isn't renderable try converting to either A8 or an 32 bit config. Otherwise, // fail. if (!caps->isConfigRenderable(rtDesc.fConfig, false)) { if (GrPixelConfigIsAlphaOnly(rtDesc.fConfig)) { if (caps->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) { rtDesc.fConfig = kAlpha_8_GrPixelConfig; } else if (caps->isConfigRenderable(kSkia8888_GrPixelConfig, false)) { rtDesc.fConfig = kSkia8888_GrPixelConfig; } else { return nullptr; } } else if (kRGB_GrColorComponentFlags == (kRGB_GrColorComponentFlags & GrPixelConfigComponentMask(rtDesc.fConfig))) { if (caps->isConfigRenderable(kSkia8888_GrPixelConfig, false)) { rtDesc.fConfig = kSkia8888_GrPixelConfig; } else { return nullptr; } } else { return nullptr; } } SkAutoTUnref<GrTexture> stretched(GrCreateTextureForPixels(context, optionalKey, rtDesc, pixelRef, nullptr,0)); if (!stretched) { return nullptr; } GrPaint paint; // If filtering is not desired then we want to ensure all texels in the resampled image are // copies of texels from the original. GrTextureParams params(SkShader::kClamp_TileMode, SkGrStretch::kBilerp_Type == stretch.fType ? GrTextureParams::kBilerp_FilterMode : GrTextureParams::kNone_FilterMode); paint.addColorTextureProcessor(inputTexture, SkMatrix::I(), params); SkRect rect = SkRect::MakeWH(SkIntToScalar(rtDesc.fWidth), SkIntToScalar(rtDesc.fHeight)); SkRect localRect = SkRect::MakeWH(1.f, 1.f); SkAutoTUnref<GrDrawContext> drawContext(context->drawContext()); if (!drawContext) { return nullptr; } drawContext->drawNonAARectToRect(stretched->asRenderTarget(), GrClip::WideOpen(), paint, SkMatrix::I(), rect, localRect); return stretched.detach(); }
// Show the contexts on the screen. // Must be called from the main thread. void debugContexts (void) { static volatile bool inDebugContexts = false; // Prevent this function from being called from within itself. CONTEXT orgContext; CONTEXT debugDrawContext; // We're going to use this context to draw in. FRAME debugDrawFrame; double hueIncrement; size_t visibleContextI; CONTEXT context; size_t contextCount; FRAME savedScreen; // Prevent this function from being called from within itself. if (inDebugContexts) return; inDebugContexts = true; contextCount = countVisibleContexts (); if (contextCount == 0) { goto out; } savedScreen = getScreen (); FlushGraphics (); // Make sure that the screen has actually been captured, // before we use the frame. // Create a new frame to draw on. debugDrawContext = CreateContext ("debugDrawContext"); // New work frame is a copy of the original. debugDrawFrame = CaptureDrawable (CloneFrame (savedScreen)); orgContext = SetContext (debugDrawContext); SetContextFGFrame (debugDrawFrame); hueIncrement = 360.0 / contextCount; visibleContextI = 0; for (context = GetFirstContext (); context != NULL; context = GetNextContext (context)) { if (context == debugDrawContext) { // Skip our own context. continue; } if (isContextVisible (context)) { // Only draw the visible contexts. drawContext (context, visibleContextI * hueIncrement); visibleContextI++; } describeContext (stderr, context); } // Blit the final debugging frame to the screen. putScreen (debugDrawFrame); // Wait for a key: { WAIT_STATE state; state.InputFunc = waitForKey; DoInput(&state, TRUE); } SetContext (orgContext); // Destroy the debugging frame and context. DestroyContext (debugDrawContext); // This does nothing with the drawable set with // SetContextFGFrame(). DestroyDrawable (ReleaseDrawable (debugDrawFrame)); putScreen (savedScreen); DestroyDrawable (ReleaseDrawable (savedScreen)); out: inDebugContexts = false; }
GrTexture* GrYUVProvider::refAsTexture(GrContext* ctx, const GrSurfaceDesc& desc, bool useCache) { SkYUVPlanesCache::Info yuvInfo; void* planes[3]; YUVScoper scoper; if (!scoper.init(this, &yuvInfo, planes, useCache)) { return nullptr; } GrSurfaceDesc yuvDesc; yuvDesc.fConfig = kAlpha_8_GrPixelConfig; SkAutoTUnref<GrTexture> yuvTextures[3]; for (int i = 0; i < 3; i++) { yuvDesc.fWidth = yuvInfo.fSizeInfo.fSizes[i].fWidth; yuvDesc.fHeight = yuvInfo.fSizeInfo.fSizes[i].fHeight; // TODO: why do we need this check? bool needsExactTexture = (yuvDesc.fWidth != yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fWidth) || (yuvDesc.fHeight != yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight); if (needsExactTexture) { yuvTextures[i].reset(ctx->textureProvider()->createTexture(yuvDesc, SkBudgeted::kYes)); } else { yuvTextures[i].reset(ctx->textureProvider()->createApproxTexture(yuvDesc)); } if (!yuvTextures[i] || !yuvTextures[i]->writePixels(0, 0, yuvDesc.fWidth, yuvDesc.fHeight, yuvDesc.fConfig, planes[i], yuvInfo.fSizeInfo.fWidthBytes[i])) { return nullptr; } } GrSurfaceDesc rtDesc = desc; rtDesc.fFlags = rtDesc.fFlags | kRenderTarget_GrSurfaceFlag; SkAutoTUnref<GrTexture> result(ctx->textureProvider()->createTexture(rtDesc, SkBudgeted::kYes, nullptr, 0)); if (!result) { return nullptr; } GrRenderTarget* renderTarget = result->asRenderTarget(); SkASSERT(renderTarget); GrPaint paint; // We may be decoding an sRGB image, but the result of our linear math on the YUV planes // is already in sRGB in that case. Don't convert (which will make the image too bright). paint.setDisableOutputConversionToSRGB(true); SkAutoTUnref<const GrFragmentProcessor> yuvToRgbProcessor( GrYUVEffect::CreateYUVToRGB(yuvTextures[0], yuvTextures[1], yuvTextures[2], yuvInfo.fSizeInfo.fSizes, yuvInfo.fColorSpace)); paint.addColorFragmentProcessor(yuvToRgbProcessor); paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); const SkRect r = SkRect::MakeIWH(yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fWidth, yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight); SkAutoTUnref<GrDrawContext> drawContext(ctx->drawContext(renderTarget)); if (!drawContext) { return nullptr; } drawContext->drawRect(GrClip::WideOpen(), paint, SkMatrix::I(), r); return result.release(); }
sk_sp<SkImage> SkImage::MakeFromYUVTexturesCopy(GrContext* ctx , SkYUVColorSpace colorSpace, const GrBackendObject yuvTextureHandles[3], const SkISize yuvSizes[3], GrSurfaceOrigin origin) { const SkBudgeted budgeted = SkBudgeted::kYes; if (yuvSizes[0].fWidth <= 0 || yuvSizes[0].fHeight <= 0 || yuvSizes[1].fWidth <= 0 || yuvSizes[1].fHeight <= 0 || yuvSizes[2].fWidth <= 0 || yuvSizes[2].fHeight <= 0) { return nullptr; } static const GrPixelConfig kConfig = kAlpha_8_GrPixelConfig; GrBackendTextureDesc yDesc; yDesc.fConfig = kConfig; yDesc.fOrigin = origin; yDesc.fSampleCnt = 0; yDesc.fTextureHandle = yuvTextureHandles[0]; yDesc.fWidth = yuvSizes[0].fWidth; yDesc.fHeight = yuvSizes[0].fHeight; GrBackendTextureDesc uDesc; uDesc.fConfig = kConfig; uDesc.fOrigin = origin; uDesc.fSampleCnt = 0; uDesc.fTextureHandle = yuvTextureHandles[1]; uDesc.fWidth = yuvSizes[1].fWidth; uDesc.fHeight = yuvSizes[1].fHeight; GrBackendTextureDesc vDesc; vDesc.fConfig = kConfig; vDesc.fOrigin = origin; vDesc.fSampleCnt = 0; vDesc.fTextureHandle = yuvTextureHandles[2]; vDesc.fWidth = yuvSizes[2].fWidth; vDesc.fHeight = yuvSizes[2].fHeight; SkAutoTUnref<GrTexture> yTex(ctx->textureProvider()->wrapBackendTexture( yDesc, kBorrow_GrWrapOwnership)); SkAutoTUnref<GrTexture> uTex(ctx->textureProvider()->wrapBackendTexture( uDesc, kBorrow_GrWrapOwnership)); SkAutoTUnref<GrTexture> vTex(ctx->textureProvider()->wrapBackendTexture( vDesc, kBorrow_GrWrapOwnership)); if (!yTex || !uTex || !vTex) { return nullptr; } const int width = yuvSizes[0].fWidth; const int height = yuvSizes[0].fHeight; // Needs to be a render target in order to draw to it for the yuv->rgb conversion. sk_sp<GrDrawContext> drawContext(ctx->newDrawContext(GrContext::kTight_BackingFit, width, height, kRGBA_8888_GrPixelConfig, 0, origin)); if (!drawContext) { return nullptr; } GrPaint paint; paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); paint.addColorFragmentProcessor(GrYUVEffect::CreateYUVToRGB(yTex, uTex, vTex, yuvSizes, colorSpace))->unref(); const SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)); drawContext->drawRect(GrClip::WideOpen(), paint, SkMatrix::I(), rect); ctx->flushSurfaceWrites(drawContext->accessRenderTarget()); return sk_make_sp<SkImage_Gpu>(width, height, kNeedNewImageUniqueID, kOpaque_SkAlphaType, drawContext->asTexture().get(), budgeted); }
sk_sp<GrTexture> GrYUVProvider::refAsTexture(GrContext* ctx, const GrSurfaceDesc& desc, bool useCache) { SkYUVPlanesCache::Info yuvInfo; void* planes[3]; YUVScoper scoper; if (!scoper.init(this, &yuvInfo, planes, useCache)) { return nullptr; } GrSurfaceDesc yuvDesc; yuvDesc.fConfig = kAlpha_8_GrPixelConfig; SkAutoTUnref<GrTexture> yuvTextures[3]; for (int i = 0; i < 3; i++) { yuvDesc.fWidth = yuvInfo.fSizeInfo.fSizes[i].fWidth; yuvDesc.fHeight = yuvInfo.fSizeInfo.fSizes[i].fHeight; // TODO: why do we need this check? bool needsExactTexture = (yuvDesc.fWidth != yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fWidth) || (yuvDesc.fHeight != yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight); if (needsExactTexture) { yuvTextures[i].reset(ctx->textureProvider()->createTexture(yuvDesc, SkBudgeted::kYes)); } else { yuvTextures[i].reset(ctx->textureProvider()->createApproxTexture(yuvDesc)); } if (!yuvTextures[i] || !yuvTextures[i]->writePixels(0, 0, yuvDesc.fWidth, yuvDesc.fHeight, yuvDesc.fConfig, planes[i], yuvInfo.fSizeInfo.fWidthBytes[i])) { return nullptr; } } sk_sp<GrDrawContext> drawContext(ctx->newDrawContext(SkBackingFit::kExact, desc.fWidth, desc.fHeight, desc.fConfig, desc.fSampleCnt)); if (!drawContext) { return nullptr; } GrPaint paint; sk_sp<GrFragmentProcessor> yuvToRgbProcessor( GrYUVEffect::MakeYUVToRGB(yuvTextures[0], yuvTextures[1], yuvTextures[2], yuvInfo.fSizeInfo.fSizes, yuvInfo.fColorSpace, false)); paint.addColorFragmentProcessor(std::move(yuvToRgbProcessor)); // If we're decoding an sRGB image, the result of our linear math on the YUV planes is already // in sRGB. (The encoding is just math on bytes, with no concept of color spaces.) So, we need // to output the results of that math directly to the buffer that we will then consider sRGB. // If we have sRGB write control, we can just tell the HW not to do the Linear -> sRGB step. // Otherwise, we do our shader math to go from YUV -> sRGB, manually convert sRGB -> Linear, // then let the HW convert Linear -> sRGB. if (GrPixelConfigIsSRGB(desc.fConfig)) { if (ctx->caps()->srgbWriteControl()) { paint.setDisableOutputConversionToSRGB(true); } else { paint.addColorFragmentProcessor(GrGammaEffect::Make(2.2f)); } } paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); const SkRect r = SkRect::MakeIWH(yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fWidth, yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight); drawContext->drawRect(GrNoClip(), paint, SkMatrix::I(), r); return drawContext->asTexture(); }
static GrTexture* copy_on_gpu(GrTexture* inputTexture, const SkIRect* subset, const CopyParams& copyParams) { SkASSERT(!subset || !subset->isEmpty()); GrContext* context = inputTexture->getContext(); SkASSERT(context); const GrCaps* caps = context->caps(); // Either it's a cache miss or the original wasn't cached to begin with. GrSurfaceDesc rtDesc = inputTexture->desc(); rtDesc.fFlags = rtDesc.fFlags | kRenderTarget_GrSurfaceFlag; rtDesc.fWidth = copyParams.fWidth; rtDesc.fHeight = copyParams.fHeight; rtDesc.fConfig = GrMakePixelConfigUncompressed(rtDesc.fConfig); // If the config isn't renderable try converting to either A8 or an 32 bit config. Otherwise, // fail. if (!caps->isConfigRenderable(rtDesc.fConfig, false)) { if (GrPixelConfigIsAlphaOnly(rtDesc.fConfig)) { if (caps->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) { rtDesc.fConfig = kAlpha_8_GrPixelConfig; } else if (caps->isConfigRenderable(kSkia8888_GrPixelConfig, false)) { rtDesc.fConfig = kSkia8888_GrPixelConfig; } else { return nullptr; } } else if (kRGB_GrColorComponentFlags == (kRGB_GrColorComponentFlags & GrPixelConfigComponentMask(rtDesc.fConfig))) { if (caps->isConfigRenderable(kSkia8888_GrPixelConfig, false)) { rtDesc.fConfig = kSkia8888_GrPixelConfig; } else { return nullptr; } } else { return nullptr; } } SkAutoTUnref<GrTexture> copy(context->textureProvider()->createTexture(rtDesc, SkBudgeted::kYes)); if (!copy) { return nullptr; } // TODO: If no scaling is being performed then use copySurface. GrPaint paint; paint.setGammaCorrect(true); // TODO: Initializing these values for no reason cause the compiler is complaining SkScalar sx = 0.f; SkScalar sy = 0.f; if (subset) { sx = 1.f / inputTexture->width(); sy = 1.f / inputTexture->height(); } if (copyParams.fFilter != GrTextureParams::kNone_FilterMode && subset && (subset->width() != copyParams.fWidth || subset->height() != copyParams.fHeight)) { SkRect domain; domain.fLeft = (subset->fLeft + 0.5f) * sx; domain.fTop = (subset->fTop + 0.5f)* sy; domain.fRight = (subset->fRight - 0.5f) * sx; domain.fBottom = (subset->fBottom - 0.5f) * sy; // This would cause us to read values from outside the subset. Surely, the caller knows // better! SkASSERT(copyParams.fFilter != GrTextureParams::kMipMap_FilterMode); paint.addColorFragmentProcessor( GrTextureDomainEffect::Make(inputTexture, SkMatrix::I(), domain, GrTextureDomain::kClamp_Mode, copyParams.fFilter)); } else { GrTextureParams params(SkShader::kClamp_TileMode, copyParams.fFilter); paint.addColorTextureProcessor(inputTexture, SkMatrix::I(), params); } paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); SkRect localRect; if (subset) { localRect = SkRect::Make(*subset); localRect.fLeft *= sx; localRect.fTop *= sy; localRect.fRight *= sx; localRect.fBottom *= sy; } else { localRect = SkRect::MakeWH(1.f, 1.f); } sk_sp<GrDrawContext> drawContext(context->drawContext(sk_ref_sp(copy->asRenderTarget()))); if (!drawContext) { return nullptr; } SkRect dstRect = SkRect::MakeWH(SkIntToScalar(rtDesc.fWidth), SkIntToScalar(rtDesc.fHeight)); drawContext->fillRectToRect(GrNoClip(), paint, SkMatrix::I(), dstRect, localRect); return copy.release(); }
bool SkXfermodeImageFilter::filterImageGPUDeprecated(Proxy* proxy, const SkBitmap& src, const Context& ctx, SkBitmap* result, SkIPoint* offset) const { GrContext* context = nullptr; SkBitmap background = src; SkIPoint backgroundOffset = SkIPoint::Make(0, 0); if (!this->filterInputGPUDeprecated(0, proxy, src, ctx, &background, &backgroundOffset)) { background.reset(); } GrTexture* backgroundTex = background.getTexture(); if (backgroundTex) { context = backgroundTex->getContext(); } SkBitmap foreground = src; SkIPoint foregroundOffset = SkIPoint::Make(0, 0); if (!this->filterInputGPUDeprecated(1, proxy, src, ctx, &foreground, &foregroundOffset)) { foreground.reset(); } GrTexture* foregroundTex = foreground.getTexture(); if (foregroundTex) { context = foregroundTex->getContext(); } if (!context) { return false; } SkIRect bounds = background.bounds().makeOffset(backgroundOffset.x(), backgroundOffset.y()); bounds.join(foreground.bounds().makeOffset(foregroundOffset.x(), foregroundOffset.y())); if (bounds.isEmpty()) { return false; } GrSurfaceDesc desc; desc.fFlags = kRenderTarget_GrSurfaceFlag; desc.fWidth = bounds.width(); desc.fHeight = bounds.height(); desc.fConfig = kSkia8888_GrPixelConfig; SkAutoTUnref<GrTexture> dst(context->textureProvider()->createApproxTexture(desc)); if (!dst) { return false; } GrPaint paint; SkAutoTUnref<const GrFragmentProcessor> bgFP; if (backgroundTex) { SkMatrix backgroundMatrix; backgroundMatrix.setIDiv(backgroundTex->width(), backgroundTex->height()); backgroundMatrix.preTranslate(SkIntToScalar(-backgroundOffset.fX), SkIntToScalar(-backgroundOffset.fY)); bgFP.reset(GrTextureDomainEffect::Create( backgroundTex, backgroundMatrix, GrTextureDomain::MakeTexelDomain(backgroundTex, background.bounds()), GrTextureDomain::kDecal_Mode, GrTextureParams::kNone_FilterMode)); } else { bgFP.reset(GrConstColorProcessor::Create(GrColor_TRANSPARENT_BLACK, GrConstColorProcessor::kIgnore_InputMode)); } if (foregroundTex) { SkMatrix foregroundMatrix; foregroundMatrix.setIDiv(foregroundTex->width(), foregroundTex->height()); foregroundMatrix.preTranslate(SkIntToScalar(-foregroundOffset.fX), SkIntToScalar(-foregroundOffset.fY)); SkAutoTUnref<const GrFragmentProcessor> foregroundFP; foregroundFP.reset(GrTextureDomainEffect::Create( foregroundTex, foregroundMatrix, GrTextureDomain::MakeTexelDomain(foregroundTex, foreground.bounds()), GrTextureDomain::kDecal_Mode, GrTextureParams::kNone_FilterMode)); paint.addColorFragmentProcessor(foregroundFP.get()); // A null fMode is interpreted to mean kSrcOver_Mode (to match raster). SkAutoTUnref<SkXfermode> mode(SkSafeRef(fMode.get())); if (!mode) { // It would be awesome to use SkXfermode::Create here but it knows better // than us and won't return a kSrcOver_Mode SkXfermode. That means we // have to get one the hard way. struct ProcCoeff rec; rec.fProc = SkXfermode::GetProc(SkXfermode::kSrcOver_Mode); SkXfermode::ModeAsCoeff(SkXfermode::kSrcOver_Mode, &rec.fSC, &rec.fDC); mode.reset(new SkProcCoeffXfermode(rec, SkXfermode::kSrcOver_Mode)); } SkAutoTUnref<const GrFragmentProcessor> xferFP(mode->getFragmentProcessorForImageFilter(bgFP)); // A null 'xferFP' here means kSrc_Mode was used in which case we can just proceed if (xferFP) { paint.addColorFragmentProcessor(xferFP); } } else { paint.addColorFragmentProcessor(bgFP); } paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(dst->asRenderTarget())); if (!drawContext) { return false; } SkMatrix matrix; matrix.setTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top())); drawContext->drawRect(GrClip::WideOpen(), paint, matrix, SkRect::Make(bounds)); offset->fX = bounds.left(); offset->fY = bounds.top(); GrWrapTextureInBitmap(dst, bounds.width(), bounds.height(), false, result); return true; }
sk_sp<SkSpecialImage> SkXfermodeImageFilter::filterImageGPU(SkSpecialImage* source, sk_sp<SkSpecialImage> background, const SkIPoint& backgroundOffset, sk_sp<SkSpecialImage> foreground, const SkIPoint& foregroundOffset, const SkIRect& bounds) const { SkASSERT(source->isTextureBacked()); GrContext* context = source->getContext(); sk_sp<GrTexture> backgroundTex, foregroundTex; if (background) { backgroundTex = background->asTextureRef(context); } if (foreground) { foregroundTex = foreground->asTextureRef(context); } GrPaint paint; // SRGBTODO: AllowSRGBInputs? sk_sp<GrFragmentProcessor> bgFP; if (backgroundTex) { SkMatrix backgroundMatrix; backgroundMatrix.setIDiv(backgroundTex->width(), backgroundTex->height()); backgroundMatrix.preTranslate(SkIntToScalar(-backgroundOffset.fX), SkIntToScalar(-backgroundOffset.fY)); bgFP = GrTextureDomainEffect::Make( backgroundTex.get(), nullptr, backgroundMatrix, GrTextureDomain::MakeTexelDomain(backgroundTex.get(), background->subset()), GrTextureDomain::kDecal_Mode, GrTextureParams::kNone_FilterMode); } else { bgFP = GrConstColorProcessor::Make(GrColor_TRANSPARENT_BLACK, GrConstColorProcessor::kIgnore_InputMode); } if (foregroundTex) { SkMatrix foregroundMatrix; foregroundMatrix.setIDiv(foregroundTex->width(), foregroundTex->height()); foregroundMatrix.preTranslate(SkIntToScalar(-foregroundOffset.fX), SkIntToScalar(-foregroundOffset.fY)); sk_sp<GrFragmentProcessor> foregroundFP; foregroundFP = GrTextureDomainEffect::Make( foregroundTex.get(), nullptr, foregroundMatrix, GrTextureDomain::MakeTexelDomain(foregroundTex.get(), foreground->subset()), GrTextureDomain::kDecal_Mode, GrTextureParams::kNone_FilterMode); paint.addColorFragmentProcessor(std::move(foregroundFP)); // A null fMode is interpreted to mean kSrcOver_Mode (to match raster). SkAutoTUnref<SkXfermode> mode(SkSafeRef(fMode.get())); if (!mode) { // It would be awesome to use SkXfermode::Create here but it knows better // than us and won't return a kSrcOver_Mode SkXfermode. That means we // have to get one the hard way. struct ProcCoeff rec; rec.fProc = SkXfermode::GetProc(SkXfermode::kSrcOver_Mode); SkXfermode::ModeAsCoeff(SkXfermode::kSrcOver_Mode, &rec.fSC, &rec.fDC); mode.reset(new SkProcCoeffXfermode(rec, SkXfermode::kSrcOver_Mode)); } sk_sp<GrFragmentProcessor> xferFP( mode->makeFragmentProcessorForImageFilter(std::move(bgFP))); // A null 'xferFP' here means kSrc_Mode was used in which case we can just proceed if (xferFP) { paint.addColorFragmentProcessor(std::move(xferFP)); } } else { paint.addColorFragmentProcessor(std::move(bgFP)); } paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); sk_sp<GrDrawContext> drawContext(context->makeDrawContext(SkBackingFit::kApprox, bounds.width(), bounds.height(), kSkia8888_GrPixelConfig, sk_ref_sp(source->getColorSpace()))); if (!drawContext) { return nullptr; } SkMatrix matrix; matrix.setTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top())); drawContext->drawRect(GrNoClip(), paint, matrix, SkRect::Make(bounds)); return SkSpecialImage::MakeFromGpu(SkIRect::MakeWH(bounds.width(), bounds.height()), kNeedNewImageUniqueID_SpecialImage, drawContext->asTexture(), sk_ref_sp(drawContext->getColorSpace())); }