DEF_GPUTEST_FOR_NATIVE_CONTEXT(SkImage_newTextureImage, reporter, context, glContext) { GrContextFactory otherFactory; GrContextFactory::ContextInfo otherContextInfo = otherFactory.getContextInfo(GrContextFactory::kNative_GLContextType); glContext->makeCurrent(); std::function<SkImage*()> imageFactories[] = { create_image, create_codec_image, create_data_image, // Create an image from a picture. create_picture_image, // Create a texture image. [context] { return create_gpu_image(context); }, // Create a texture image in a another GrContext. [glContext, otherContextInfo] { otherContextInfo.fGLContext->makeCurrent(); SkImage* otherContextImage = create_gpu_image(otherContextInfo.fGrContext); glContext->makeCurrent(); return otherContextImage; } }; for (auto factory : imageFactories) { SkAutoTUnref<SkImage> image(factory()); if (!image) { ERRORF(reporter, "Error creating image."); continue; } GrTexture* origTexture = as_IB(image)->peekTexture(); SkAutoTUnref<SkImage> texImage(image->newTextureImage(context)); if (!texImage) { // We execpt to fail if image comes from a different GrContext. if (!origTexture || origTexture->getContext() == context) { ERRORF(reporter, "newTextureImage failed."); } continue; } GrTexture* copyTexture = as_IB(texImage)->peekTexture(); if (!copyTexture) { ERRORF(reporter, "newTextureImage returned non-texture image."); continue; } if (origTexture) { if (origTexture != copyTexture) { ERRORF(reporter, "newTextureImage made unnecessary texture copy."); } } if (image->width() != texImage->width() || image->height() != texImage->height()) { ERRORF(reporter, "newTextureImage changed the image size."); } if (image->isOpaque() != texImage->isOpaque()) { ERRORF(reporter, "newTextureImage changed image opaqueness."); } } }
SkShaderBase::Context* SkImageShader::onMakeContext(const ContextRec& rec, SkArenaAlloc* alloc) const { const auto info = as_IB(fImage)->onImageInfo(); if (info.colorType() != kN32_SkColorType) { return nullptr; } if (info.alphaType() == kUnpremul_SkAlphaType) { return nullptr; } #ifndef SK_SUPPORT_LEGACY_TILED_BITMAPS if (fTileModeX != fTileModeY) { return nullptr; } #endif if (fTileModeX == kDecal_TileMode || fTileModeY == kDecal_TileMode) { return nullptr; } SkMatrix inv; if (!this->computeTotalInverse(*rec.fMatrix, rec.fLocalMatrix, &inv) || !legacy_shader_can_handle(inv)) { return nullptr; } return SkBitmapProcLegacyShader::MakeContext(*this, fTileModeX, fTileModeY, SkBitmapProvider(fImage.get(), rec.fDstColorSpace), rec, alloc); }
SkImageInfo SkBitmapProvider::info() const { if (fImage) { return as_IB(fImage)->onImageInfo(); } else { return fBitmap.info(); } }
SkData* SkImage::encode(SkImageEncoder::Type type, int quality) const { SkBitmap bm; if (as_IB(this)->getROPixels(&bm)) { return SkImageEncoder::EncodeData(bm, type, quality); } return NULL; }
sk_sp<SkImage> SkImage::makeWithFilter(const SkImageFilter* filter, const SkIRect& subset, const SkIRect& clipBounds, SkIRect* outSubset, SkIPoint* offset) const { if (!filter || !outSubset || !offset || !this->bounds().contains(subset)) { return nullptr; } SkColorSpace* colorSpace = as_IB(this)->onImageInfo().colorSpace(); sk_sp<SkSpecialImage> srcSpecialImage = SkSpecialImage::MakeFromImage( subset, sk_ref_sp(const_cast<SkImage*>(this)), colorSpace); if (!srcSpecialImage) { return nullptr; } sk_sp<SkImageFilterCache> cache( SkImageFilterCache::Create(SkImageFilterCache::kDefaultTransientSize)); SkImageFilter::OutputProperties outputProperties(colorSpace); SkImageFilter::Context context(SkMatrix::I(), clipBounds, cache.get(), outputProperties); sk_sp<SkSpecialImage> result = filter->filterImage(srcSpecialImage.get(), context, offset); if (!result) { return nullptr; } *outSubset = SkIRect::MakeWH(result->width(), result->height()); if (!outSubset->intersect(clipBounds.makeOffset(-offset->x(), -offset->y()))) { return nullptr; } offset->fX += outSubset->x(); offset->fY += outSubset->y(); // Note that here we're returning the special image's entire backing store, loose padding // and all! return result->asImage(); }
void SkBitmapProvider::notifyAddedToCache() const { if (fImage) { as_IB(fImage)->notifyAddedToCache(); } else { fBitmap.pixelRef()->notifyAddedToCache(); } }
GrTexture* onAsTextureRef(GrContext* context) const override { #if SK_SUPPORT_GPU return as_IB(fImage)->asTextureRef(context, GrTextureParams::ClampNoFilter()); #else return nullptr; #endif }
void WindowContext::presentRenderSurface(sk_sp<SkSurface> renderSurface, sk_sp<GrRenderTarget> rt, int colorBits) { if (!this->isGpuContext() || colorBits > 24 || kRGBA_F16_SkColorType == fDisplayParams.fColorType) { // We made/have an off-screen surface. Get the contents as an SkImage: SkImageInfo info = SkImageInfo::Make(fWidth, fHeight, fDisplayParams.fColorType, kUnknown_SkAlphaType, fDisplayParams.fColorSpace); SkBitmap bm; bm.allocPixels(info); renderSurface->getCanvas()->readPixels(&bm, 0, 0); SkPixmap pm; bm.peekPixels(&pm); sk_sp<SkImage> image(SkImage::MakeTextureFromPixmap(fContext, pm, SkBudgeted::kNo)); GrTexture* texture = as_IB(image)->peekTexture(); SkASSERT(texture); // With ten-bit output, we need to manually apply the gamma of the output device // (unless we're in non-gamma correct mode, in which case our data is already // fake-sRGB, like we're expected to put in the 10-bit buffer): bool doGamma = (colorBits == 30) && SkImageInfoIsGammaCorrect(info); fContext->applyGamma(rt.get(), texture, doGamma ? 1.0f / 2.2f : 1.0f); } }
bool SkImage::peekPixels(SkPixmap* pm) const { SkPixmap tmp; if (!pm) { pm = &tmp; } return as_IB(this)->onPeekPixels(pm); }
sk_sp<SkImage> SkImageMakeRasterCopyAndAssignColorSpace(const SkImage* src, SkColorSpace* colorSpace) { // Read the pixels out of the source image, with no conversion SkImageInfo info = as_IB(src)->onImageInfo(); if (kUnknown_SkColorType == info.colorType()) { SkDEBUGFAIL("Unexpected color type"); return nullptr; } size_t rowBytes = info.minRowBytes(); size_t size = info.computeByteSize(rowBytes); if (SkImageInfo::ByteSizeOverflowed(size)) { return nullptr; } auto data = SkData::MakeUninitialized(size); if (!data) { return nullptr; } SkPixmap pm(info, data->writable_data(), rowBytes); if (!src->readPixels(pm, 0, 0, SkImage::kDisallow_CachingHint)) { return nullptr; } // Wrap them in a new image with a different color space return SkImage::MakeRasterData(info.makeColorSpace(sk_ref_sp(colorSpace)), data, rowBytes); }
void SkBaseDevice::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint& paint) { SkBitmap bm; if (as_IB(image)->getROPixels(&bm, this->imageInfo().colorSpace())) { this->drawBitmap(bm, x, y, paint); } }
bool SkBitmapProvider::asBitmap(SkBitmap* bm) const { if (fImage) { return as_IB(fImage)->getROPixels(bm); } else { *bm = fBitmap; return true; } }
GrYUVAImageTextureMaker::GrYUVAImageTextureMaker(GrContext* context, const SkImage* client, bool useDecal) : INHERITED(context, client->width(), client->height(), client->isAlphaOnly(), useDecal) , fImage(static_cast<const SkImage_GpuYUVA*>(client)) { SkASSERT(as_IB(client)->isYUVA()); GrMakeKeyFromImageID(&fOriginalKey, client->uniqueID(), SkIRect::MakeWH(this->width(), this->height())); }
sk_sp<SkData> SkImage::encodeToData(SkEncodedImageFormat type, int quality) const { SkBitmap bm; SkColorSpace* legacyColorSpace = nullptr; if (as_IB(this)->getROPixels(&bm, legacyColorSpace)) { return SkEncodeBitmap(bm, type, quality); } return nullptr; }
void SkBaseDevice::drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst, const SkPaint& paint, SkCanvas::SrcRectConstraint constraint) { SkBitmap bm; if (as_IB(image)->getROPixels(&bm, this->imageInfo().colorSpace())) { this->drawBitmapRect(bm, src, dst, paint, constraint); } }
bool SkBitmapProvider::asBitmap(SkBitmap* bm) const { if (fImage) { return as_IB(fImage)->getROPixels(bm, SkImage::kAllow_CachingHint); } else { *bm = fBitmap; return true; } }
bool getBitmapDeprecated(SkBitmap* result) const override { #if SK_SUPPORT_GPU if (GrTexture* texture = as_IB(fImage.get())->peekTexture()) { const SkImageInfo info = GrMakeInfoFromTexture(texture, fImage->width(), fImage->height(), fImage->isOpaque()); if (!result->setInfo(info)) { return false; } result->setPixelRef(new SkGrPixelRef(info, texture))->unref(); return true; } #endif return as_IB(fImage.get())->asBitmapForImageFilters(result); }
void SkBaseDevice::drawImage(const SkDraw& draw, const SkImage* image, SkScalar x, SkScalar y, const SkPaint& paint) { // Default impl : turns everything into raster bitmap SkBitmap bm; if (as_IB(image)->getROPixels(&bm)) { this->drawBitmap(draw, bm, SkMatrix::MakeTrans(x, y), paint); } }
bool SkImage::readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, int srcX, int srcY) const { SkReadPixelsRec rec(dstInfo, dstPixels, dstRowBytes, srcX, srcY); if (!rec.trim(this->width(), this->height())) { return false; } return as_IB(this)->onReadPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY); }
const GrFragmentProcessor* SkImageShader::asFragmentProcessor(GrContext* context, const SkMatrix& viewM, const SkMatrix* localMatrix, SkFilterQuality filterQuality, GrProcessorDataManager* mgr) const { SkMatrix matrix; matrix.setIDiv(fImage->width(), fImage->height()); SkMatrix lmInverse; if (!this->getLocalMatrix().invert(&lmInverse)) { return nullptr; } if (localMatrix) { SkMatrix inv; if (!localMatrix->invert(&inv)) { return nullptr; } lmInverse.postConcat(inv); } matrix.preConcat(lmInverse); SkShader::TileMode tm[] = { fTileModeX, fTileModeY }; // Must set wrap and filter on the sampler before requesting a texture. In two places below // we check the matrix scale factors to determine how to interpret the filter quality setting. // This completely ignores the complexity of the drawVertices case where explicit local coords // are provided by the caller. bool doBicubic; GrTextureParams::FilterMode textureFilterMode = GrSkFilterQualityToGrFilterMode(filterQuality, viewM, this->getLocalMatrix(), &doBicubic); GrTextureParams params(tm, textureFilterMode); SkImageUsageType usageType; if (kClamp_TileMode == fTileModeX && kClamp_TileMode == fTileModeY) { usageType = kUntiled_SkImageUsageType; } else if (GrTextureParams::kNone_FilterMode == textureFilterMode) { usageType = kTiled_Unfiltered_SkImageUsageType; } else { usageType = kTiled_Filtered_SkImageUsageType; } SkAutoTUnref<GrTexture> texture(as_IB(fImage)->asTextureRef(context, usageType)); if (!texture) { return nullptr; } SkAutoTUnref<GrFragmentProcessor> inner; if (doBicubic) { inner.reset(GrBicubicEffect::Create(mgr, texture, matrix, tm)); } else { inner.reset(GrSimpleTextureEffect::Create(mgr, texture, matrix, params)); } if (GrPixelConfigIsAlphaOnly(texture->config())) { return SkRef(inner.get()); } return GrFragmentProcessor::MulOuputByInputAlpha(inner); }
void SkBaseDevice::drawImageRect(const SkDraw& draw, const SkImage* image, const SkRect* src, const SkRect& dst, const SkPaint& paint, SkCanvas::SrcRectConstraint constraint) { // Default impl : turns everything into raster bitmap SkBitmap bm; if (as_IB(image)->getROPixels(&bm)) { this->drawBitmapRect(draw, bm, src, dst, paint, constraint); } }
sk_sp<SkSurface> onMakeTightSurface(const SkImageInfo& info) const override { #if SK_SUPPORT_GPU GrTexture* texture = as_IB(fImage.get())->peekTexture(); if (texture) { return SkSurface::MakeRenderTarget(texture->getContext(), SkBudgeted::kYes, info); } #endif return SkSurface::MakeRaster(info, nullptr); }
SkImage* SkSurface_Gpu::onNewImageSnapshot(Budgeted budgeted) { const int sampleCount = fDevice->accessRenderTarget()->numSamples(); SkImage* image = SkNewImageFromBitmapTexture(fDevice->accessBitmap(false), sampleCount, budgeted); if (image) { as_IB(image)->initWithProps(this->props()); } return image; }
sk_sp<SkImage> SkImage::makeTextureImage(GrContext *context) const { if (!context) { return nullptr; } if (GrTexture* peek = as_IB(this)->peekTexture()) { return peek->getContext() == context ? sk_ref_sp(const_cast<SkImage*>(this)) : nullptr; } if (SkImageCacherator* cacher = as_IB(this)->peekCacherator()) { GrImageTextureMaker maker(context, cacher, this, kDisallow_CachingHint); return create_image_from_maker(&maker, this->alphaType(), this->uniqueID()); } if (const SkBitmap* bmp = as_IB(this)->onPeekBitmap()) { GrBitmapTextureMaker maker(context, *bmp); return create_image_from_maker(&maker, this->alphaType(), this->uniqueID()); } return nullptr; }
void SkImage::preroll(GrContext* ctx) const { // For now, and to maintain parity w/ previous pixelref behavior, we just force the image // to produce a cached raster-bitmap form, so that drawing to a raster canvas should be fast. // SkBitmap bm; if (as_IB(this)->getROPixels(&bm)) { bm.lockPixels(); bm.unlockPixels(); } }
sk_sp<SkSpecialImage> SkSpecialImage::MakeFromImage(const SkIRect& subset, sk_sp<SkImage> image, const SkSurfaceProps* props) { SkASSERT(rect_fits(subset, image->width(), image->height())); #if SK_SUPPORT_GPU if (GrTexture* texture = as_IB(image)->peekTexture()) { return MakeFromGpu(subset, image->uniqueID(), sk_ref_sp(texture), sk_ref_sp(as_IB(image)->onImageInfo().colorSpace()), props); } else #endif { SkBitmap bm; if (as_IB(image)->getROPixels(&bm)) { return MakeFromRaster(subset, bm, props); } } return nullptr; }
const void* SkImage::peekPixels(SkImageInfo* info, size_t* rowBytes) const { SkImageInfo infoStorage; size_t rowBytesStorage; if (NULL == info) { info = &infoStorage; } if (NULL == rowBytes) { rowBytes = &rowBytesStorage; } return as_IB(this)->onPeekPixels(info, rowBytes); }
bool SkImage::readYUV8Planes(const SkISize sizes[3], void* const planes[3], const size_t rowBytes[3], SkYUVColorSpace colorSpace) const { #if SK_SUPPORT_GPU if (GrTexture* texture = as_IB(this)->peekTexture()) { if (GrTextureToYUVPlanes(texture, sizes, planes, rowBytes, colorSpace)) { return true; } } #endif return SkRGBAToYUV(this, sizes, planes, rowBytes, colorSpace); }
sk_sp<SkSpecialSurface> onMakeSurface(const SkImageInfo& info) const override { #if SK_SUPPORT_GPU GrTexture* texture = as_IB(fImage.get())->peekTexture(); if (texture) { GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(info, *texture->getContext()->caps()); desc.fFlags = kRenderTarget_GrSurfaceFlag; return SkSpecialSurface::MakeRenderTarget(texture->getContext(), desc); } #endif return SkSpecialSurface::MakeRaster(info, nullptr); }
sk_sp<SkImage> SkImage::makeTextureImage(GrContext *context) const { if (!context) { return nullptr; } if (GrTexture* peek = as_IB(this)->peekTexture()) { return peek->getContext() == context ? sk_ref_sp(const_cast<SkImage*>(this)) : nullptr; } // No way to check whether a image is premul or not? SkAlphaType at = this->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType; if (SkImageCacherator* cacher = as_IB(this)->peekCacherator()) { GrImageTextureMaker maker(context, cacher, this, kDisallow_CachingHint); return create_image_from_maker(&maker, at, this->uniqueID()); } SkBitmap bmp; if (!this->asLegacyBitmap(&bmp, kRO_LegacyBitmapMode)) { return nullptr; } GrBitmapTextureMaker maker(context, bmp); return create_image_from_maker(&maker, at, this->uniqueID()); }