Allow caller to specify if the want mip maps in makeTextureImage call.

Since Ganesh no longer will allocate mips late, this gives the clients a
way to tell skia that they want the texture they will be using to have mips.
It also supports allowing a client to take a non mipped texture backed
image and turn it into a new image which is mipped and texture backed.

Bug: chromium:834837
Change-Id: I1781ce618c22023b6309f248e7ee49e69bd3c6df
Reviewed-on: https://skia-review.googlesource.com/134323
Commit-Queue: Greg Daniel <egdaniel@google.com>
Reviewed-by: Eric Karl <ericrk@chromium.org>
Reviewed-by: Cary Clark <caryclark@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
This commit is contained in:
Greg Daniel 2018-06-12 16:39:59 -04:00 committed by Skia Commit-Bot
parent ed8ed91ec8
commit 5f4b09d523
7 changed files with 119 additions and 52 deletions

View File

@ -1774,18 +1774,22 @@ pixels in Image could not be read or copied.
# ------------------------------------------------------------------------------
#Method sk_sp<SkImage> makeTextureImage(GrContext* context, SkColorSpace* dstColorSpace) const
#Method sk_sp<SkImage> makeTextureImage(GrContext* context, SkColorSpace* dstColorSpace,
GrMipMapped mipMapped = GrMipMapped::kNo) const
#In Constructor
#Line # creates Image matching Color_Space if possible ##
Returns Image backed by GPU_Texture associated with context. Returned Image is
compatible with Surface created with dstColorSpace. Returns original
Image if context and dstColorSpace match.
compatible with Surface created with dstColorSpace. The returned Image will also
support the request GrMipMapped status. In other words if mipMapped is GrMipMapped::kYes,
then the backing texture will have Mip_Map levels allocated. Returns original Image if context
and dstColorSpace match and mipMapped is compatible with the backing GPU_Texture.
Returns nullptr if context is nullptr, or if Image was created with another
GrContext.
#Param context GPU_Context ##
#Param dstColorSpace range of colors of matching Surface on GPU ##
#Param mipMapped whether the returned SkImage's texture must have allocated Mip_Map levels ##
#Return created Image, or nullptr ##

View File

@ -740,17 +740,22 @@ public:
sk_sp<SkImage> makeSubset(const SkIRect& subset) const;
/** Returns SkImage backed by GPU texture associated with context. Returned SkImage is
compatible with SkSurface created with dstColorSpace. Returns original
SkImage if context and dstColorSpace match.
compatible with SkSurface created with dstColorSpace. The returned SkImage will also
support the request GrMipMapped status. In other words if mipMapped is GrMipMapped::kYes,
then the backing texture will have mip map levles allocated. Returns original SkImage if
context and dstColorSpace match and mipMapped is compatible with the backing GPU_Texture.
Returns nullptr if context is nullptr, or if SkImage was created with another
GrContext.
@param context GPU context
@param dstColorSpace range of colors of matching SkSurface on GPU
@param mipMapped whether the returned SkImage's texture must have allocated Mip_Map
levels.
@return created SkImage, or nullptr
*/
sk_sp<SkImage> makeTextureImage(GrContext* context, SkColorSpace* dstColorSpace) const;
sk_sp<SkImage> makeTextureImage(GrContext* context, SkColorSpace* dstColorSpace,
GrMipMapped mipMapped = GrMipMapped::kNo) const;
/** Returns raster image or lazy image. Copies SkImage backed by GPU texture into
CPU memory if needed. Returns original SkImage if decoded in raster bitmap,

View File

@ -235,3 +235,18 @@ sk_sp<GrTextureProxy> GrTextureProducer::refTextureProxyForParams(
(result->width() == this->width() && result->height() == this->height()));
return result;
}
sk_sp<GrTextureProxy> GrTextureProducer::refTextureProxy(GrMipMapped willNeedMips,
SkColorSpace* dstColorSpace,
sk_sp<SkColorSpace>* proxyColorSpace) {
GrSamplerState::Filter filter =
GrMipMapped::kNo == willNeedMips ? GrSamplerState::Filter::kNearest
: GrSamplerState::Filter::kMipMap;
GrSamplerState sampler(GrSamplerState::WrapMode::kClamp, filter);
auto result =
this->onRefTextureProxyForParams(sampler, dstColorSpace, proxyColorSpace, nullptr);
// Check that no scaling occured and we returned a proxy of the same size as the producer.
SkASSERT(!result || (result->width() == this->width() && result->height() == this->height()));
return result;
}

View File

@ -98,6 +98,21 @@ public:
proxyColorSpace, scaleAdjust);
}
/**
* Returns a texture that is safe for use with the dstColorSpace. If willNeedMips is true then
* the returned texture is guaranteed to have allocated mip map levels. This can be a
* performance win if future draws with the texture require mip maps.
*
* Places the color space of the texture in (*proxyColorSpace).
*/
// TODO: Once we remove support for npot textures, we should add a flag for must support repeat
// wrap mode. To support that flag now would require us to support scaleAdjust array like in
// refTextureProxyForParams, however the current public API that uses this call does not expose
// that array.
sk_sp<GrTextureProxy> refTextureProxy(GrMipMapped willNeedMips,
SkColorSpace* dstColorSpace,
sk_sp<SkColorSpace>* proxyColorSpace);
virtual ~GrTextureProducer() {}
int width() const { return fWidth; }

View File

@ -385,7 +385,8 @@ sk_sp<SkImage> SkImage::MakeFromNV12TexturesCopy(GrContext* ctx, SkYUVColorSpace
return nullptr;
}
sk_sp<SkImage> SkImage::makeTextureImage(GrContext*, SkColorSpace* dstColorSpace) const {
sk_sp<SkImage> SkImage::makeTextureImage(GrContext*, SkColorSpace* dstColorSpace,
GrMipMapped mipMapped) const {
return nullptr;
}

View File

@ -498,12 +498,13 @@ sk_sp<SkImage> SkImage::MakeFromNV12TexturesCopy(GrContext* ctx, SkYUVColorSpace
size, origin, std::move(imageColorSpace));
}
static sk_sp<SkImage> create_image_from_maker(GrContext* context, GrTextureMaker* maker,
SkAlphaType at, uint32_t id,
SkColorSpace* dstColorSpace) {
static sk_sp<SkImage> create_image_from_producer(GrContext* context, GrTextureProducer* producer,
SkAlphaType at, uint32_t id,
SkColorSpace* dstColorSpace,
GrMipMapped mipMapped) {
sk_sp<SkColorSpace> texColorSpace;
sk_sp<GrTextureProxy> proxy(maker->refTextureProxyForParams(
GrSamplerState::ClampNearest(), dstColorSpace, &texColorSpace, nullptr));
sk_sp<GrTextureProxy> proxy(producer->refTextureProxy(mipMapped, dstColorSpace,
&texColorSpace));
if (!proxy) {
return nullptr;
}
@ -511,24 +512,36 @@ static sk_sp<SkImage> create_image_from_maker(GrContext* context, GrTextureMaker
std::move(texColorSpace), SkBudgeted::kNo);
}
sk_sp<SkImage> SkImage::makeTextureImage(GrContext* context, SkColorSpace* dstColorSpace) const {
sk_sp<SkImage> SkImage::makeTextureImage(GrContext* context, SkColorSpace* dstColorSpace,
GrMipMapped mipMapped) const {
if (!context) {
return nullptr;
}
if (GrContext* incumbent = as_IB(this)->context()) {
return incumbent == context ? sk_ref_sp(const_cast<SkImage*>(this)) : nullptr;
if (incumbent != context) {
return nullptr;
}
sk_sp<GrTextureProxy> proxy = as_IB(this)->asTextureProxyRef();
SkASSERT(proxy);
if (GrMipMapped::kNo == mipMapped || proxy->mipMapped() == mipMapped) {
return sk_ref_sp(const_cast<SkImage*>(this));
}
GrTextureAdjuster adjuster(context, std::move(proxy), this->alphaType(),
this->uniqueID(), this->colorSpace());
return create_image_from_producer(context, &adjuster, this->alphaType(),
this->uniqueID(), dstColorSpace, mipMapped);
}
if (this->isLazyGenerated()) {
GrImageTextureMaker maker(context, this, kDisallow_CachingHint);
return create_image_from_maker(context, &maker, this->alphaType(),
this->uniqueID(), dstColorSpace);
return create_image_from_producer(context, &maker, this->alphaType(),
this->uniqueID(), dstColorSpace, mipMapped);
}
if (const SkBitmap* bmp = as_IB(this)->onPeekBitmap()) {
GrBitmapTextureMaker maker(context, *bmp);
return create_image_from_maker(context, &maker, this->alphaType(),
this->uniqueID(), dstColorSpace);
return create_image_from_producer(context, &maker, this->alphaType(),
this->uniqueID(), dstColorSpace, mipMapped);
}
return nullptr;
}

View File

@ -147,9 +147,10 @@ static sk_sp<SkImage> create_codec_image() {
sk_sp<SkData> src(sk_tool_utils::EncodeImageToData(bitmap, SkEncodedImageFormat::kPNG, 100));
return SkImage::MakeFromEncoded(std::move(src));
}
static sk_sp<SkImage> create_gpu_image(GrContext* context) {
static sk_sp<SkImage> create_gpu_image(GrContext* context, bool withMips = false) {
const SkImageInfo info = SkImageInfo::MakeN32(20, 20, kOpaque_SkAlphaType);
auto surface(SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info));
auto surface(SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info, 0,
kBottomLeft_GrSurfaceOrigin, nullptr, withMips));
draw_image_test_pattern(surface->getCanvas());
return surface->makeImageSnapshot();
}
@ -385,6 +386,8 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkImage_makeTextureImage, reporter, contextIn
create_picture_image,
// Create a texture image.
[context] { return create_gpu_image(context); },
// Create a texture image with mips
//[context] { return create_gpu_image(context, true); },
// Create a texture image in a another GrContext.
[otherContextInfo] {
auto restore = otherContextInfo.testContext()->makeCurrentAndAutoRestore();
@ -400,43 +403,54 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkImage_makeTextureImage, reporter, contextIn
};
for (auto& dstColorSpace : dstColorSpaces) {
for (auto factory : imageFactories) {
sk_sp<SkImage> image(factory());
if (!image) {
ERRORF(reporter, "Error creating image.");
continue;
}
sk_sp<SkImage> texImage(image->makeTextureImage(context, dstColorSpace.get()));
if (!texImage) {
GrContext* imageContext = as_IB(image)->context();
// We expect to fail if image comes from a different GrContext.
if (!image->isTextureBacked() || imageContext == context) {
ERRORF(reporter, "makeTextureImage failed.");
for (auto mipMapped : {GrMipMapped::kNo, GrMipMapped::kYes}) {
for (auto factory : imageFactories) {
sk_sp<SkImage> image(factory());
if (!image) {
ERRORF(reporter, "Error creating image.");
continue;
}
continue;
}
if (!texImage->isTextureBacked()) {
ERRORF(reporter, "makeTextureImage returned non-texture image.");
continue;
}
if (image->isTextureBacked()) {
GrSurfaceProxy* origProxy = as_IB(image)->peekProxy();
GrSurfaceProxy* copyProxy = as_IB(texImage)->peekProxy();
if (origProxy->underlyingUniqueID() != copyProxy->underlyingUniqueID()) {
ERRORF(reporter, "makeTextureImage made unnecessary texture copy.");
sk_sp<SkImage> texImage(image->makeTextureImage(context, dstColorSpace.get(),
mipMapped));
if (!texImage) {
GrContext* imageContext = as_IB(image)->context();
// We expect to fail if image comes from a different GrContext.
if (!image->isTextureBacked() || imageContext == context) {
ERRORF(reporter, "makeTextureImage failed.");
}
continue;
}
if (!texImage->isTextureBacked()) {
ERRORF(reporter, "makeTextureImage returned non-texture image.");
continue;
}
if (GrMipMapped::kYes == mipMapped &&
as_IB(texImage)->peekProxy()->mipMapped() != mipMapped) {
ERRORF(reporter, "makeTextureImage returned non-mipmapped texture.");
continue;
}
if (image->isTextureBacked()) {
GrSurfaceProxy* origProxy = as_IB(image)->peekProxy();
GrSurfaceProxy* copyProxy = as_IB(texImage)->peekProxy();
if (origProxy->underlyingUniqueID() != copyProxy->underlyingUniqueID()) {
SkASSERT(origProxy->asTextureProxy());
if (GrMipMapped::kNo == mipMapped ||
GrMipMapped::kYes == origProxy->asTextureProxy()->mipMapped()) {
ERRORF(reporter, "makeTextureImage made unnecessary texture copy.");
}
}
}
if (image->width() != texImage->width() || image->height() != texImage->height()) {
ERRORF(reporter, "makeTextureImage changed the image size.");
}
if (image->alphaType() != texImage->alphaType()) {
ERRORF(reporter, "makeTextureImage changed image alpha type.");
}
}
if (image->width() != texImage->width() || image->height() != texImage->height()) {
ERRORF(reporter, "makeTextureImage changed the image size.");
}
if (image->alphaType() != texImage->alphaType()) {
ERRORF(reporter, "makeTextureImage changed image alpha type.");
}
}
context->flush();
}
}