Add an arg to SkImage::makeSubset to take a direct context
This is part of a larger effort to force users to provide a context when manipulating GPU images which may be shared, instead of having images themselves retain powerful context pointers. Chrome flag landed in Chrome CL 2292800 Bug: skia:10466 Change-Id: Ic530a2c5eb1f4399db899d243ea944760fdf2055 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/300707 Commit-Queue: Adlai Holler <adlai@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com> Reviewed-by: Robert Phillips <robertphillips@google.com>
This commit is contained in:
parent
31bc350754
commit
872a32c58d
@ -199,7 +199,7 @@ DEF_BENCH( return new ColorFilterBench("gaussian", []() {
|
||||
return SkColorFilterPriv::MakeGaussian();
|
||||
}); )
|
||||
|
||||
#ifdef SK_SUPPORT_GPU
|
||||
#if SK_SUPPORT_GPU
|
||||
DEF_BENCH( return new ColorFilterBench("src_runtime", []() {
|
||||
static sk_sp<SkRuntimeEffect> gEffect = std::get<0>(
|
||||
SkRuntimeEffect::Make(SkString(RuntimeNone_GPU_SRC)));
|
||||
|
@ -57,7 +57,7 @@ DEF_SIMPLE_GPU_GM_CAN_FAIL(cross_context_image, context, rtc, canvas, errorMsg,
|
||||
canvas->drawImage(images[i], 0, 0);
|
||||
canvas->translate(0, 256 + 10);
|
||||
|
||||
canvas->drawImage(images[i]->makeSubset(SkIRect::MakeXYWH(64, 64, 128, 128)), 0, 0);
|
||||
canvas->drawImage(images[i]->makeSubset(SkIRect::MakeXYWH(64, 64, 128, 128), direct), 0, 0);
|
||||
canvas->translate(128, 0);
|
||||
|
||||
SkPaint paint;
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "include/core/SkTypeface.h"
|
||||
#include "include/core/SkTypes.h"
|
||||
#include "include/effects/SkGradientShader.h"
|
||||
#include "include/gpu/GrDirectContext.h"
|
||||
#include "src/core/SkBlurMask.h"
|
||||
#include "src/core/SkMathPriv.h"
|
||||
#include "tools/ToolUtils.h"
|
||||
@ -133,7 +134,8 @@ static void imagesubsetproc(SkCanvas* canvas, SkImage* image, const SkBitmap& bm
|
||||
return;
|
||||
}
|
||||
|
||||
if (sk_sp<SkImage> subset = image->makeSubset(srcR)) {
|
||||
auto direct = GrAsDirectContext(canvas->recordingContext());
|
||||
if (sk_sp<SkImage> subset = image->makeSubset(srcR, direct)) {
|
||||
canvas->drawImageRect(subset, dstR, paint);
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "include/core/SkSize.h"
|
||||
#include "include/core/SkSurface.h"
|
||||
#include "include/core/SkTypes.h"
|
||||
#include "include/gpu/GrDirectContext.h"
|
||||
#include "tools/ToolUtils.h"
|
||||
|
||||
namespace {
|
||||
@ -82,7 +83,8 @@ DEF_SIMPLE_GM(imagemasksubset, canvas, 480, 480) {
|
||||
sk_sp<SkImage> image = makers[i](canvas, info);
|
||||
if (image) {
|
||||
canvas->drawImageRect(image, SkRect::Make(kSubset), kDest, &paint);
|
||||
sk_sp<SkImage> subset = image->makeSubset(kSubset);
|
||||
auto direct = GrAsDirectContext(canvas->recordingContext());
|
||||
sk_sp<SkImage> subset = image->makeSubset(kSubset, direct);
|
||||
canvas->drawImageRect(subset, kDest.makeOffset(kSize.width() * 1.5f, 0), &paint);
|
||||
}
|
||||
canvas->translate(0, kSize.height() * 1.5f);
|
||||
|
@ -1618,6 +1618,7 @@ protected:
|
||||
void onDraw(GrRecordingContext* context, GrRenderTargetContext*, SkCanvas* canvas) override {
|
||||
SkASSERT(fImages[0][0] && fImages[0][1] && fImages[1][0] && fImages[1][1]);
|
||||
|
||||
auto direct = context->asDirectContext();
|
||||
int x = kPad;
|
||||
for (int tagged : { 0, 1 }) {
|
||||
for (int opaque : { 0, 1 }) {
|
||||
@ -1634,8 +1635,8 @@ protected:
|
||||
canvas->drawImage(yuv, x, y);
|
||||
y += kTileWidthHeight + kPad;
|
||||
|
||||
auto subset = yuv->makeSubset(SkIRect::MakeWH(kTileWidthHeight / 2,
|
||||
kTileWidthHeight / 2));
|
||||
SkIRect bounds = SkIRect::MakeWH(kTileWidthHeight / 2, kTileWidthHeight / 2);
|
||||
auto subset = yuv->makeSubset(bounds, direct);
|
||||
canvas->drawImage(subset, x, y);
|
||||
y += kTileWidthHeight + kPad;
|
||||
|
||||
|
@ -104,6 +104,7 @@ tests_sources = [
|
||||
"$_tests/GrContextAbandonTest.cpp",
|
||||
"$_tests/GrContextFactoryTest.cpp",
|
||||
"$_tests/GrContextOOM.cpp",
|
||||
"$_tests/GrDDLImageTest.cpp",
|
||||
"$_tests/GrFinishedFlushTest.cpp",
|
||||
"$_tests/GrMemoryPoolTest.cpp",
|
||||
"$_tests/GrMeshTest.cpp",
|
||||
|
@ -32,6 +32,8 @@ class SkPicture;
|
||||
class SkSurface;
|
||||
class GrBackendTexture;
|
||||
class GrContext;
|
||||
class GrDirectContext;
|
||||
class GrRecordingContext;
|
||||
class GrContextThreadSafeProxy;
|
||||
class GrRecordingContext;
|
||||
|
||||
@ -1166,15 +1168,21 @@ public:
|
||||
/** Returns subset of SkImage. subset must be fully contained by SkImage dimensions().
|
||||
The implementation may share pixels, or may copy them.
|
||||
|
||||
Returns nullptr if subset is empty, or subset is not contained by bounds, or
|
||||
pixels in SkImage could not be read or copied.
|
||||
Returns nullptr if any of the following are true:
|
||||
- Subset is empty
|
||||
- Subset is not contained by bounds
|
||||
- Pixels in SkImage could not be read or copied
|
||||
|
||||
If this image is texture-backed, the context parameter is required and must match the
|
||||
context of the source image.
|
||||
|
||||
@param subset bounds of returned SkImage
|
||||
@param context the GrDirectContext in play, if it exists
|
||||
@return partial or full SkImage, or nullptr
|
||||
|
||||
example: https://fiddle.skia.org/c/@Image_makeSubset
|
||||
*/
|
||||
sk_sp<SkImage> makeSubset(const SkIRect& subset) const;
|
||||
sk_sp<SkImage> makeSubset(const SkIRect& subset, GrDirectContext* direct = nullptr) const;
|
||||
|
||||
/** Returns SkImage backed by GPU texture associated with context. Returned SkImage is
|
||||
compatible with SkSurface created with dstColorSpace. The returned SkImage respects
|
||||
|
@ -69,7 +69,7 @@ protected:
|
||||
uint32_t contextID() const;
|
||||
|
||||
bool matches(GrContext_Base* candidate) const {
|
||||
return candidate->contextID() == this->contextID();
|
||||
return candidate && candidate->contextID() == this->contextID();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -24,6 +24,7 @@ class GrCaps;
|
||||
class GrColorInfo;
|
||||
class GrColorSpaceXform;
|
||||
class GrContext;
|
||||
class GrDirectContext;
|
||||
class GrFragmentProcessor;
|
||||
class GrPaint;
|
||||
class GrRecordingContext;
|
||||
|
@ -29,6 +29,7 @@
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
#include "include/gpu/GrDirectContext.h"
|
||||
#include "src/gpu/GrContextPriv.h"
|
||||
#include "src/image/SkImage_Gpu.h"
|
||||
#endif
|
||||
#include "include/gpu/GrBackendSurface.h"
|
||||
@ -170,7 +171,7 @@ sk_sp<SkImage> SkImage::MakeFromEncoded(sk_sp<SkData> encoded, const SkIRect* su
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
sk_sp<SkImage> SkImage::makeSubset(const SkIRect& subset) const {
|
||||
sk_sp<SkImage> SkImage::makeSubset(const SkIRect& subset, GrDirectContext* direct) const {
|
||||
if (subset.isEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -180,17 +181,24 @@ sk_sp<SkImage> SkImage::makeSubset(const SkIRect& subset) const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
auto myContext = as_IB(this)->context();
|
||||
#ifdef SK_IMAGE_SUBSET_USE_SOURCE_CONTEXT
|
||||
if (!direct) {
|
||||
direct = GrAsDirectContext(myContext);
|
||||
}
|
||||
#endif
|
||||
if (myContext && !myContext->priv().matches(direct)) {
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
// optimization : return self if the subset == our bounds
|
||||
if (bounds == subset) {
|
||||
return sk_ref_sp(const_cast<SkImage*>(this));
|
||||
}
|
||||
|
||||
// CONTEXT TODO: propagate the context parameter to the top-level API
|
||||
#if SK_SUPPORT_GPU
|
||||
return as_IB(this)->onMakeSubset(as_IB(this)->context(), subset);
|
||||
#else
|
||||
return as_IB(this)->onMakeSubset(nullptr, subset);
|
||||
#endif
|
||||
return as_IB(this)->onMakeSubset(subset, direct);
|
||||
}
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
|
@ -17,12 +17,12 @@
|
||||
#include "src/gpu/GrSurfaceProxyView.h"
|
||||
#include "src/gpu/GrTextureProxy.h"
|
||||
|
||||
class GrRecordingContext;
|
||||
class GrTexture;
|
||||
#endif
|
||||
|
||||
#include <new>
|
||||
|
||||
class GrDirectContext;
|
||||
class GrSamplerState;
|
||||
class SkCachedData;
|
||||
struct SkYUVASizeInfo;
|
||||
@ -98,7 +98,7 @@ public:
|
||||
// but only inspect them (or encode them).
|
||||
virtual bool getROPixels(SkBitmap*, CachingHint = kAllow_CachingHint) const = 0;
|
||||
|
||||
virtual sk_sp<SkImage> onMakeSubset(GrRecordingContext*, const SkIRect&) const = 0;
|
||||
virtual sk_sp<SkImage> onMakeSubset(const SkIRect&, GrDirectContext*) const = 0;
|
||||
|
||||
virtual sk_sp<SkCachedData> getPlanes(SkYUVASizeInfo*, SkYUVAIndex[4],
|
||||
SkYUVColorSpace*, const void* planes[4]);
|
||||
|
@ -755,13 +755,15 @@ bool SkImage::MakeBackendTextureFromSkImage(GrContext* ctx,
|
||||
sk_sp<SkImage> image,
|
||||
GrBackendTexture* backendTexture,
|
||||
BackendTextureReleaseProc* releaseProc) {
|
||||
if (!image || !ctx || !backendTexture || !releaseProc) {
|
||||
// TODO: Elevate direct context requirement to public API.
|
||||
auto direct = GrAsDirectContext(ctx);
|
||||
if (!image || !direct || !backendTexture || !releaseProc) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ensure we have a texture backed image.
|
||||
if (!image->isTextureBacked()) {
|
||||
image = image->makeTextureImage(ctx);
|
||||
image = image->makeTextureImage(direct);
|
||||
if (!image) {
|
||||
return false;
|
||||
}
|
||||
@ -774,19 +776,19 @@ bool SkImage::MakeBackendTextureFromSkImage(GrContext* ctx,
|
||||
}
|
||||
|
||||
// If the image's context doesn't match the provided context, fail.
|
||||
if (texture->getContext() != ctx) {
|
||||
if (texture->getContext() != direct) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Flush any pending IO on the texture.
|
||||
ctx->priv().flushSurface(as_IB(image)->peekProxy());
|
||||
direct->priv().flushSurface(as_IB(image)->peekProxy());
|
||||
|
||||
// We must make a copy of the image if the image is not unique, if the GrTexture owned by the
|
||||
// image is not unique, or if the texture wraps an external object.
|
||||
if (!image->unique() || !texture->unique() ||
|
||||
texture->resourcePriv().refsWrappedObjects()) {
|
||||
// onMakeSubset will always copy the image.
|
||||
image = as_IB(image)->onMakeSubset(ctx, image->bounds());
|
||||
image = as_IB(image)->onMakeSubset(image->bounds(), direct);
|
||||
if (!image) {
|
||||
return false;
|
||||
}
|
||||
@ -797,7 +799,7 @@ bool SkImage::MakeBackendTextureFromSkImage(GrContext* ctx,
|
||||
}
|
||||
|
||||
// Flush to ensure that the copy is completed before we return the texture.
|
||||
ctx->priv().flushSurface(as_IB(image)->peekProxy());
|
||||
direct->priv().flushSurface(as_IB(image)->peekProxy());
|
||||
}
|
||||
|
||||
SkASSERT(!texture->resourcePriv().refsWrappedObjects());
|
||||
|
@ -134,16 +134,16 @@ bool SkImage_GpuBase::getROPixels(SkBitmap* dst, CachingHint chint) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
sk_sp<SkImage> SkImage_GpuBase::onMakeSubset(GrRecordingContext* context,
|
||||
const SkIRect& subset) const {
|
||||
if (!context || !fContext->priv().matches(context)) {
|
||||
sk_sp<SkImage> SkImage_GpuBase::onMakeSubset(const SkIRect& subset,
|
||||
GrDirectContext* direct) const {
|
||||
if (!direct || !fContext->priv().matches(direct)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const GrSurfaceProxyView* view = this->view(context);
|
||||
const GrSurfaceProxyView* view = this->view(direct);
|
||||
SkASSERT(view && view->proxy());
|
||||
|
||||
auto copyView = GrSurfaceProxyView::Copy(context, *view, GrMipMapped::kNo, subset,
|
||||
auto copyView = GrSurfaceProxyView::Copy(direct, *view, GrMipMapped::kNo, subset,
|
||||
SkBackingFit::kExact, view->proxy()->isBudgeted());
|
||||
|
||||
if (!copyView) {
|
||||
@ -151,7 +151,7 @@ sk_sp<SkImage> SkImage_GpuBase::onMakeSubset(GrRecordingContext* context,
|
||||
}
|
||||
|
||||
// MDB: this call is okay bc we know 'sContext' was kExact
|
||||
return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID, std::move(copyView),
|
||||
return sk_make_sp<SkImage_Gpu>(sk_ref_sp(direct), kNeedNewImageUniqueID, std::move(copyView),
|
||||
this->colorType(), this->alphaType(), this->refColorSpace());
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include "include/core/SkDeferredDisplayListRecorder.h"
|
||||
#include "include/core/SkYUVAIndex.h"
|
||||
#include "include/gpu/GrBackendSurface.h"
|
||||
#include "include/gpu/GrContext.h"
|
||||
#include "include/gpu/GrDirectContext.h"
|
||||
#include "include/private/GrTypesPriv.h"
|
||||
#include "src/image/SkImage_Base.h"
|
||||
|
||||
@ -23,7 +23,7 @@ public:
|
||||
GrContext* context() const final { return fContext.get(); }
|
||||
|
||||
bool getROPixels(SkBitmap*, CachingHint) const final;
|
||||
sk_sp<SkImage> onMakeSubset(GrRecordingContext*, const SkIRect& subset) const final;
|
||||
sk_sp<SkImage> onMakeSubset(const SkIRect& subset, GrDirectContext*) const final;
|
||||
|
||||
bool onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
|
||||
int srcX, int srcY, CachingHint) const override;
|
||||
@ -90,6 +90,7 @@ protected:
|
||||
GrSurfaceProxyView views[4],
|
||||
const SkYUVAIndex yuvaIndices[4]);
|
||||
|
||||
// TODO: Migrate this to something much weaker, such as GrContextThreadSafeProxy.
|
||||
sk_sp<GrContext> fContext;
|
||||
|
||||
private:
|
||||
|
@ -239,8 +239,7 @@ GrSurfaceProxyView SkImage_Lazy::refView(GrRecordingContext* context, GrMipMappe
|
||||
}
|
||||
#endif
|
||||
|
||||
sk_sp<SkImage> SkImage_Lazy::onMakeSubset(GrRecordingContext* context,
|
||||
const SkIRect& subset) const {
|
||||
sk_sp<SkImage> SkImage_Lazy::onMakeSubset(const SkIRect& subset, GrDirectContext*) const {
|
||||
SkASSERT(this->bounds().contains(subset));
|
||||
SkASSERT(this->bounds() != subset);
|
||||
|
||||
|
@ -48,7 +48,7 @@ public:
|
||||
SkYUVColorSpace*, const void* planes[4]) override;
|
||||
#endif
|
||||
sk_sp<SkData> onRefEncoded() const override;
|
||||
sk_sp<SkImage> onMakeSubset(GrRecordingContext*, const SkIRect&) const override;
|
||||
sk_sp<SkImage> onMakeSubset(const SkIRect&, GrDirectContext*) const override;
|
||||
bool getROPixels(SkBitmap*, CachingHint) const override;
|
||||
bool onIsLazyGenerated() const override { return true; }
|
||||
sk_sp<SkImage> onMakeColorTypeAndColorSpace(GrRecordingContext*,
|
||||
|
@ -89,7 +89,7 @@ public:
|
||||
#endif
|
||||
|
||||
bool getROPixels(SkBitmap*, CachingHint) const override;
|
||||
sk_sp<SkImage> onMakeSubset(GrRecordingContext*, const SkIRect&) const override;
|
||||
sk_sp<SkImage> onMakeSubset(const SkIRect&, GrDirectContext*) const override;
|
||||
|
||||
SkPixelRef* getPixelRef() const { return fBitmap.pixelRef(); }
|
||||
|
||||
@ -233,7 +233,7 @@ void SkImage_Raster::onUnpinAsTexture(GrContext* ctx) const {
|
||||
}
|
||||
#endif
|
||||
|
||||
sk_sp<SkImage> SkImage_Raster::onMakeSubset(GrRecordingContext*, const SkIRect& subset) const {
|
||||
sk_sp<SkImage> SkImage_Raster::onMakeSubset(const SkIRect& subset, GrDirectContext*) const {
|
||||
SkImageInfo info = fBitmap.info().makeDimensions(subset.size());
|
||||
SkBitmap bitmap;
|
||||
if (!bitmap.tryAllocPixels(info)) {
|
||||
|
62
tests/GrDDLImageTest.cpp
Normal file
62
tests/GrDDLImageTest.cpp
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2020 Google LLC
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "include/core/SkImage.h"
|
||||
#include "include/core/SkSurface.h"
|
||||
#include "include/core/SkSurfaceCharacterization.h"
|
||||
#include "tests/Test.h"
|
||||
|
||||
DEF_GPUTEST(GrDDLImage_MakeSubset, reporter, options) {
|
||||
sk_gpu_test::GrContextFactory factory(options);
|
||||
for (int ct = 0; ct < sk_gpu_test::GrContextFactory::kContextTypeCnt; ++ct) {
|
||||
auto contextType = static_cast<sk_gpu_test::GrContextFactory::ContextType>(ct);
|
||||
auto direct = factory.get(contextType);
|
||||
if (!direct) {
|
||||
continue;
|
||||
}
|
||||
SkIRect subsetBounds = SkIRect::MakeLTRB(4,4,8,8);
|
||||
SkImageInfo ii = SkImageInfo::Make(16, 16, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
|
||||
|
||||
// Raster image:
|
||||
SkBitmap bm;
|
||||
bm.setInfo(ii);
|
||||
bm.allocPixels();
|
||||
bm.eraseColor(SK_ColorBLACK);
|
||||
bm.setImmutable();
|
||||
auto rasterImg = SkImage::MakeFromBitmap(bm);
|
||||
REPORTER_ASSERT(reporter, rasterImg->isValid(static_cast<GrRecordingContext*>(nullptr)));
|
||||
|
||||
// raster + context:
|
||||
auto subImg1 = rasterImg->makeSubset(subsetBounds, direct);
|
||||
REPORTER_ASSERT(reporter, subImg1->isValid(direct));
|
||||
|
||||
// raster + no context:
|
||||
auto subImg2 = rasterImg->makeSubset(subsetBounds, nullptr);
|
||||
REPORTER_ASSERT(reporter, subImg2->isValid(static_cast<GrRecordingContext*>(nullptr)));
|
||||
|
||||
// Texture image:
|
||||
auto surf = SkSurface::MakeRenderTarget(direct, SkBudgeted::kNo, ii);
|
||||
SkSurfaceCharacterization sc;
|
||||
REPORTER_ASSERT(reporter, surf->characterize(&sc));
|
||||
GrBackendTexture tex = direct->createBackendTexture(sc);
|
||||
auto gpuImage = SkImage::MakeFromTexture(direct, tex, kTopLeft_GrSurfaceOrigin,
|
||||
ii.colorType(), ii.alphaType(),
|
||||
ii.refColorSpace());
|
||||
REPORTER_ASSERT(reporter, gpuImage->isValid(direct));
|
||||
|
||||
// gpu image + context:
|
||||
auto subImg5 = gpuImage->makeSubset(subsetBounds, direct);
|
||||
REPORTER_ASSERT(reporter, subImg5->isValid(direct));
|
||||
|
||||
// gpu image + nullptr:
|
||||
REPORTER_ASSERT(reporter, !gpuImage->makeSubset(subsetBounds, nullptr));
|
||||
|
||||
direct->flush();
|
||||
direct->submit(true);
|
||||
direct->deleteBackendTexture(tex);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user