diff options
author | 2015-11-17 22:53:28 -0800 | |
---|---|---|
committer | 2015-11-17 22:53:28 -0800 | |
commit | 4e18413b78236391f507875ab5d60aa14cb3c1a5 (patch) | |
tree | e203184a6e3a05193f53c0a5dcba24ae54e69588 /tests | |
parent | cbf4fba43933302a846872e4c5ce8f1adb8b325e (diff) |
Move SkImage tests from SurfaceTest to ImageTest
The general SkImage features seem to be tested in
ImageTest instead of SurfaceTest.
Helps in reviewing further reformatting of SurfaceTest.
BUG=skia:2992
Review URL: https://codereview.chromium.org/1452123002
Diffstat (limited to 'tests')
-rw-r--r-- | tests/ImageTest.cpp | 430 | ||||
-rw-r--r-- | tests/SurfaceTest.cpp | 427 |
2 files changed, 432 insertions, 425 deletions
diff --git a/tests/ImageTest.cpp b/tests/ImageTest.cpp index 4768b8b0d4..d139ca7075 100644 --- a/tests/ImageTest.cpp +++ b/tests/ImageTest.cpp @@ -361,3 +361,433 @@ DEF_TEST(ImageFromIndex8Bitmap, r) { SkAutoTUnref<SkImage> img(SkImage::NewFromBitmap(bm)); REPORTER_ASSERT(r, img.get() != nullptr); } + +// TODO: The tests below were moved from SurfaceTests and should be reformatted. + +enum ImageType { + kRasterCopy_ImageType, + kRasterData_ImageType, + kRasterProc_ImageType, + kGpu_ImageType, + kCodec_ImageType, +}; + +#include "SkImageGenerator.h" + +class EmptyGenerator : public SkImageGenerator { +public: + EmptyGenerator() : SkImageGenerator(SkImageInfo::MakeN32Premul(0, 0)) {} +}; + +static void test_empty_image(skiatest::Reporter* reporter) { + const SkImageInfo info = SkImageInfo::Make(0, 0, kN32_SkColorType, kPremul_SkAlphaType); + + REPORTER_ASSERT(reporter, nullptr == SkImage::NewRasterCopy(info, nullptr, 0)); + REPORTER_ASSERT(reporter, nullptr == SkImage::NewRasterData(info, nullptr, 0)); + REPORTER_ASSERT(reporter, nullptr == SkImage::NewFromRaster(info, nullptr, 0, nullptr, nullptr)); + REPORTER_ASSERT(reporter, nullptr == SkImage::NewFromGenerator(new EmptyGenerator)); +} + +static void test_image(skiatest::Reporter* reporter) { + SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1); + size_t rowBytes = info.minRowBytes(); + size_t size = info.getSafeSize(rowBytes); + SkData* data = SkData::NewUninitialized(size); + + REPORTER_ASSERT(reporter, data->unique()); + SkImage* image = SkImage::NewRasterData(info, data, rowBytes); + REPORTER_ASSERT(reporter, !data->unique()); + image->unref(); + REPORTER_ASSERT(reporter, data->unique()); + data->unref(); +} + +// Want to ensure that our Release is called when the owning image is destroyed +struct ReleaseDataContext { + skiatest::Reporter* fReporter; + SkData* fData; + + static void Release(const void* pixels, void* context) { + ReleaseDataContext* state = (ReleaseDataContext*)context; + REPORTER_ASSERT(state->fReporter, state->fData); + state->fData->unref(); + state->fData = nullptr; + } +}; + +// May we (soon) eliminate the need to keep testing this, by hiding the bloody device! +#include "SkDevice.h" +static uint32_t get_legacy_gen_id(SkSurface* surf) { + SkBaseDevice* device = surf->getCanvas()->getDevice_just_for_deprecated_compatibility_testing(); + return device->accessBitmap(false).getGenerationID(); +} + +/* + * Test legacy behavor of bumping the surface's device's bitmap's genID when we access its + * texture handle for writing. + * + * Note: this needs to be tested separately from checking newImageSnapshot, as calling that + * can also incidentally bump the genID (when a new backing surface is created). + */ +template <class F> +static void test_texture_handle_genID(skiatest::Reporter* reporter, SkSurface* surf, F f) { + const uint32_t gen0 = get_legacy_gen_id(surf); + f(surf, SkSurface::kFlushRead_BackendHandleAccess); + const uint32_t gen1 = get_legacy_gen_id(surf); + REPORTER_ASSERT(reporter, gen0 == gen1); + + f(surf, SkSurface::kFlushWrite_BackendHandleAccess); + const uint32_t gen2 = get_legacy_gen_id(surf); + REPORTER_ASSERT(reporter, gen0 != gen2); + + f(surf, SkSurface::kDiscardWrite_BackendHandleAccess); + const uint32_t gen3 = get_legacy_gen_id(surf); + REPORTER_ASSERT(reporter, gen0 != gen3); + REPORTER_ASSERT(reporter, gen2 != gen3); +} + +template <class F> +static void test_backend_handle(skiatest::Reporter* reporter, SkSurface* surf, F f) { + SkAutoTUnref<SkImage> image0(surf->newImageSnapshot()); + GrBackendObject obj = f(surf, SkSurface::kFlushRead_BackendHandleAccess); + REPORTER_ASSERT(reporter, obj != 0); + SkAutoTUnref<SkImage> image1(surf->newImageSnapshot()); + // just read access should not affect the snapshot + REPORTER_ASSERT(reporter, image0->uniqueID() == image1->uniqueID()); + + obj = f(surf, SkSurface::kFlushWrite_BackendHandleAccess); + REPORTER_ASSERT(reporter, obj != 0); + SkAutoTUnref<SkImage> image2(surf->newImageSnapshot()); + // expect a new image, since we claimed we would write + REPORTER_ASSERT(reporter, image0->uniqueID() != image2->uniqueID()); + + obj = f(surf, SkSurface::kDiscardWrite_BackendHandleAccess); + REPORTER_ASSERT(reporter, obj != 0); + SkAutoTUnref<SkImage> image3(surf->newImageSnapshot()); + // expect a new(er) image, since we claimed we would write + REPORTER_ASSERT(reporter, image0->uniqueID() != image3->uniqueID()); + REPORTER_ASSERT(reporter, image2->uniqueID() != image3->uniqueID()); +} + +static SkImage* create_image(skiatest::Reporter* reporter, + ImageType imageType, GrContext* context, SkColor color, + ReleaseDataContext* releaseContext) { + const SkPMColor pmcolor = SkPreMultiplyColor(color); + const SkImageInfo info = SkImageInfo::MakeN32Premul(10, 10); + const size_t rowBytes = info.minRowBytes(); + const size_t size = rowBytes * info.height(); + + SkAutoTUnref<SkData> data(SkData::NewUninitialized(size)); + void* addr = data->writable_data(); + sk_memset32((SkPMColor*)addr, pmcolor, SkToInt(size >> 2)); + + switch (imageType) { + case kRasterCopy_ImageType: + return SkImage::NewRasterCopy(info, addr, rowBytes); + case kRasterData_ImageType: + return SkImage::NewRasterData(info, data, rowBytes); + case kRasterProc_ImageType: + SkASSERT(releaseContext); + releaseContext->fData = SkRef(data.get()); + return SkImage::NewFromRaster(info, addr, rowBytes, + ReleaseDataContext::Release, releaseContext); + case kGpu_ImageType: { + SkAutoTUnref<SkSurface> surf( + SkSurface::NewRenderTarget(context, SkSurface::kNo_Budgeted, info, 0)); + surf->getCanvas()->clear(color); + // test our backing texture / rendertarget while were here... + auto textureAccessorFunc = + [](SkSurface* surf, SkSurface::BackendHandleAccess access) -> GrBackendObject { + return surf->getTextureHandle(access); }; + auto renderTargetAccessorFunc = + [](SkSurface* surf, SkSurface::BackendHandleAccess access) -> GrBackendObject { + GrBackendObject obj; + SkAssertResult(surf->getRenderTargetHandle(&obj, access)); + return obj; }; + test_backend_handle(reporter, surf, textureAccessorFunc); + test_backend_handle(reporter, surf, renderTargetAccessorFunc); + test_texture_handle_genID(reporter, surf, textureAccessorFunc); + test_texture_handle_genID(reporter, surf, renderTargetAccessorFunc); + + // redraw so our returned image looks as expected. + surf->getCanvas()->clear(color); + return surf->newImageSnapshot(); + } + case kCodec_ImageType: { + SkBitmap bitmap; + bitmap.installPixels(info, addr, rowBytes); + SkAutoTUnref<SkData> src( + SkImageEncoder::EncodeData(bitmap, SkImageEncoder::kPNG_Type, 100)); + return SkImage::NewFromEncoded(src); + } + } + SkASSERT(false); + return nullptr; +} + +static void set_pixels(SkPMColor pixels[], int count, SkPMColor color) { + sk_memset32(pixels, color, count); +} +static bool has_pixels(const SkPMColor pixels[], int count, SkPMColor expected) { + for (int i = 0; i < count; ++i) { + if (pixels[i] != expected) { + return false; + } + } + return true; +} + +static void test_image_readpixels(skiatest::Reporter* reporter, SkImage* image, + SkPMColor expected) { + const SkPMColor notExpected = ~expected; + + const int w = 2, h = 2; + const size_t rowBytes = w * sizeof(SkPMColor); + SkPMColor pixels[w*h]; + + SkImageInfo info; + + info = SkImageInfo::MakeUnknown(w, h); + REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, 0, 0)); + + // out-of-bounds should fail + info = SkImageInfo::MakeN32Premul(w, h); + REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, -w, 0)); + REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, 0, -h)); + REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, image->width(), 0)); + REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, 0, image->height())); + + // top-left should succeed + set_pixels(pixels, w*h, notExpected); + REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes, 0, 0)); + REPORTER_ASSERT(reporter, has_pixels(pixels, w*h, expected)); + + // bottom-right should succeed + set_pixels(pixels, w*h, notExpected); + REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes, + image->width() - w, image->height() - h)); + REPORTER_ASSERT(reporter, has_pixels(pixels, w*h, expected)); + + // partial top-left should succeed + set_pixels(pixels, w*h, notExpected); + REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes, -1, -1)); + REPORTER_ASSERT(reporter, pixels[3] == expected); + REPORTER_ASSERT(reporter, has_pixels(pixels, w*h - 1, notExpected)); + + // partial bottom-right should succeed + set_pixels(pixels, w*h, notExpected); + REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes, + image->width() - 1, image->height() - 1)); + REPORTER_ASSERT(reporter, pixels[0] == expected); + REPORTER_ASSERT(reporter, has_pixels(&pixels[1], w*h - 1, notExpected)); +} + +static void check_legacy_bitmap(skiatest::Reporter* reporter, const SkImage* image, + const SkBitmap& bitmap, SkImage::LegacyBitmapMode mode) { + REPORTER_ASSERT(reporter, image->width() == bitmap.width()); + REPORTER_ASSERT(reporter, image->height() == bitmap.height()); + REPORTER_ASSERT(reporter, image->isOpaque() == bitmap.isOpaque()); + + if (SkImage::kRO_LegacyBitmapMode == mode) { + REPORTER_ASSERT(reporter, bitmap.isImmutable()); + } + + SkAutoLockPixels alp(bitmap); + REPORTER_ASSERT(reporter, bitmap.getPixels()); + + const SkImageInfo info = SkImageInfo::MakeN32(1, 1, bitmap.alphaType()); + SkPMColor imageColor; + REPORTER_ASSERT(reporter, image->readPixels(info, &imageColor, sizeof(SkPMColor), 0, 0)); + REPORTER_ASSERT(reporter, imageColor == *bitmap.getAddr32(0, 0)); +} + +static void test_legacy_bitmap(skiatest::Reporter* reporter, const SkImage* image) { + const SkImage::LegacyBitmapMode modes[] = { + SkImage::kRO_LegacyBitmapMode, + SkImage::kRW_LegacyBitmapMode, + }; + for (size_t i = 0; i < SK_ARRAY_COUNT(modes); ++i) { + SkBitmap bitmap; + REPORTER_ASSERT(reporter, image->asLegacyBitmap(&bitmap, modes[i])); + check_legacy_bitmap(reporter, image, bitmap, modes[i]); + + // Test subsetting to exercise the rowBytes logic. + SkBitmap tmp; + REPORTER_ASSERT(reporter, bitmap.extractSubset(&tmp, SkIRect::MakeWH(image->width() / 2, + image->height() / 2))); + SkAutoTUnref<SkImage> subsetImage(SkImage::NewFromBitmap(tmp)); + REPORTER_ASSERT(reporter, subsetImage); + + SkBitmap subsetBitmap; + REPORTER_ASSERT(reporter, subsetImage->asLegacyBitmap(&subsetBitmap, modes[i])); + check_legacy_bitmap(reporter, subsetImage, subsetBitmap, modes[i]); + } +} + +static void test_imagepeek(skiatest::Reporter* reporter, GrContextFactory* factory) { + static const struct { + ImageType fType; + bool fPeekShouldSucceed; + const char* fName; + } gRec[] = { + { kRasterCopy_ImageType, true, "RasterCopy" }, + { kRasterData_ImageType, true, "RasterData" }, + { kRasterProc_ImageType, true, "RasterProc" }, + { kGpu_ImageType, false, "Gpu" }, + { kCodec_ImageType, false, "Codec" }, + }; + + const SkColor color = SK_ColorRED; + const SkPMColor pmcolor = SkPreMultiplyColor(color); + + GrContext* ctx = nullptr; +#if SK_SUPPORT_GPU + ctx = factory->get(GrContextFactory::kNative_GLContextType); + if (nullptr == ctx) { + return; + } +#endif + + ReleaseDataContext releaseCtx; + releaseCtx.fReporter = reporter; + + for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) { + SkImageInfo info; + size_t rowBytes; + + releaseCtx.fData = nullptr; + SkAutoTUnref<SkImage> image(create_image(reporter, gRec[i].fType, ctx, color, &releaseCtx)); + if (!image.get()) { + SkDebugf("failed to createImage[%d] %s\n", i, gRec[i].fName); + continue; // gpu may not be enabled + } + if (kRasterProc_ImageType == gRec[i].fType) { + REPORTER_ASSERT(reporter, nullptr != releaseCtx.fData); // we are tracking the data + } else { + REPORTER_ASSERT(reporter, nullptr == releaseCtx.fData); // we ignored the context + } + + test_legacy_bitmap(reporter, image); + + const void* addr = image->peekPixels(&info, &rowBytes); + bool success = SkToBool(addr); + REPORTER_ASSERT(reporter, gRec[i].fPeekShouldSucceed == success); + if (success) { + REPORTER_ASSERT(reporter, 10 == info.width()); + REPORTER_ASSERT(reporter, 10 == info.height()); + REPORTER_ASSERT(reporter, kN32_SkColorType == info.colorType()); + REPORTER_ASSERT(reporter, kPremul_SkAlphaType == info.alphaType() || + kOpaque_SkAlphaType == info.alphaType()); + REPORTER_ASSERT(reporter, info.minRowBytes() <= rowBytes); + REPORTER_ASSERT(reporter, pmcolor == *(const SkPMColor*)addr); + } + + test_image_readpixels(reporter, image, pmcolor); + } + REPORTER_ASSERT(reporter, nullptr == releaseCtx.fData); // we released the data +} +#if SK_SUPPORT_GPU + +struct ReleaseTextureContext { + ReleaseTextureContext(skiatest::Reporter* reporter) { + fReporter = reporter; + fIsReleased = false; + } + + skiatest::Reporter* fReporter; + bool fIsReleased; + + void doRelease() { + REPORTER_ASSERT(fReporter, false == fIsReleased); + fIsReleased = true; + } + + static void ReleaseProc(void* context) { + ((ReleaseTextureContext*)context)->doRelease(); + } +}; + +static SkImage* make_desc_image(GrContext* ctx, int w, int h, GrBackendObject texID, + ReleaseTextureContext* releaseContext) { + GrBackendTextureDesc desc; + desc.fConfig = kSkia8888_GrPixelConfig; + // need to be a rendertarget for now... + desc.fFlags = kRenderTarget_GrBackendTextureFlag; + desc.fWidth = w; + desc.fHeight = h; + desc.fSampleCnt = 0; + desc.fTextureHandle = texID; + return releaseContext + ? SkImage::NewFromTexture(ctx, desc, kPremul_SkAlphaType, + ReleaseTextureContext::ReleaseProc, releaseContext) + : SkImage::NewFromTextureCopy(ctx, desc, kPremul_SkAlphaType); +} + +static void test_image_color(skiatest::Reporter* reporter, SkImage* image, SkPMColor expected) { + const SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1); + SkPMColor pixel; + REPORTER_ASSERT(reporter, image->readPixels(info, &pixel, sizeof(pixel), 0, 0)); + REPORTER_ASSERT(reporter, pixel == expected); +} + +DEF_GPUTEST(SkImage_NewFromTexture, reporter, factory) { + GrContext* ctx = factory->get(GrContextFactory::kNative_GLContextType); + if (!ctx) { + REPORTER_ASSERT(reporter, false); + return; + } + GrTextureProvider* provider = ctx->textureProvider(); + + const int w = 10; + const int h = 10; + SkPMColor storage[w * h]; + const SkPMColor expected0 = SkPreMultiplyColor(SK_ColorRED); + sk_memset32(storage, expected0, w * h); + + GrSurfaceDesc desc; + desc.fFlags = kRenderTarget_GrSurfaceFlag; // needs to be a rendertarget for readpixels(); + desc.fOrigin = kDefault_GrSurfaceOrigin; + desc.fWidth = w; + desc.fHeight = h; + desc.fConfig = kSkia8888_GrPixelConfig; + desc.fSampleCnt = 0; + + SkAutoTUnref<GrTexture> tex(provider->createTexture(desc, false, storage, w * 4)); + if (!tex) { + REPORTER_ASSERT(reporter, false); + return; + } + + GrBackendObject srcTex = tex->getTextureHandle(); + ReleaseTextureContext releaseCtx(reporter); + + SkAutoTUnref<SkImage> refImg(make_desc_image(ctx, w, h, srcTex, &releaseCtx)); + SkAutoTUnref<SkImage> cpyImg(make_desc_image(ctx, w, h, srcTex, nullptr)); + + test_image_color(reporter, refImg, expected0); + test_image_color(reporter, cpyImg, expected0); + + // Now lets jam new colors into our "external" texture, and see if the images notice + const SkPMColor expected1 = SkPreMultiplyColor(SK_ColorBLUE); + sk_memset32(storage, expected1, w * h); + tex->writePixels(0, 0, w, h, kSkia8888_GrPixelConfig, storage, GrContext::kFlushWrites_PixelOp); + + // The cpy'd one should still see the old color +#if 0 + // There is no guarantee that refImg sees the new color. We are free to have made a copy. Our + // write pixels call violated the contract with refImg and refImg is now undefined. + test_image_color(reporter, refImg, expected1); +#endif + test_image_color(reporter, cpyImg, expected0); + + // Now exercise the release proc + REPORTER_ASSERT(reporter, !releaseCtx.fIsReleased); + refImg.reset(nullptr); // force a release of the image + REPORTER_ASSERT(reporter, releaseCtx.fIsReleased); +} +#endif +DEF_GPUTEST(ImageTestsFromSurfaceTestsTODO, reporter, factory) { + test_image(reporter); + test_empty_image(reporter); + test_imagepeek(reporter, factory); +} diff --git a/tests/SurfaceTest.cpp b/tests/SurfaceTest.cpp index a6739e3308..7e07e17f89 100644 --- a/tests/SurfaceTest.cpp +++ b/tests/SurfaceTest.cpp @@ -65,30 +65,6 @@ static SkSurface* create_surface(SurfaceType surfaceType, GrContext* context, return nullptr; } -enum ImageType { - kRasterCopy_ImageType, - kRasterData_ImageType, - kRasterProc_ImageType, - kGpu_ImageType, - kCodec_ImageType, -}; - -#include "SkImageGenerator.h" - -class EmptyGenerator : public SkImageGenerator { -public: - EmptyGenerator() : SkImageGenerator(SkImageInfo::MakeN32Premul(0, 0)) {} -}; - -static void test_empty_image(skiatest::Reporter* reporter) { - const SkImageInfo info = SkImageInfo::Make(0, 0, kN32_SkColorType, kPremul_SkAlphaType); - - REPORTER_ASSERT(reporter, nullptr == SkImage::NewRasterCopy(info, nullptr, 0)); - REPORTER_ASSERT(reporter, nullptr == SkImage::NewRasterData(info, nullptr, 0)); - REPORTER_ASSERT(reporter, nullptr == SkImage::NewFromRaster(info, nullptr, 0, nullptr, nullptr)); - REPORTER_ASSERT(reporter, nullptr == SkImage::NewFromGenerator(new EmptyGenerator)); -} - static void test_empty_surface(skiatest::Reporter* reporter, GrContext* ctx) { const SkImageInfo info = SkImageInfo::Make(0, 0, kN32_SkColorType, kPremul_SkAlphaType); @@ -175,304 +151,6 @@ static void test_wrapped_texture_surface(skiatest::Reporter* reporter, GrContext #endif -static void test_image(skiatest::Reporter* reporter) { - SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1); - size_t rowBytes = info.minRowBytes(); - size_t size = info.getSafeSize(rowBytes); - SkData* data = SkData::NewUninitialized(size); - - REPORTER_ASSERT(reporter, data->unique()); - SkImage* image = SkImage::NewRasterData(info, data, rowBytes); - REPORTER_ASSERT(reporter, !data->unique()); - image->unref(); - REPORTER_ASSERT(reporter, data->unique()); - data->unref(); -} - -// Want to ensure that our Release is called when the owning image is destroyed -struct ReleaseDataContext { - skiatest::Reporter* fReporter; - SkData* fData; - - static void Release(const void* pixels, void* context) { - ReleaseDataContext* state = (ReleaseDataContext*)context; - REPORTER_ASSERT(state->fReporter, state->fData); - state->fData->unref(); - state->fData = nullptr; - } -}; - -// May we (soon) eliminate the need to keep testing this, by hiding the bloody device! -#include "SkDevice.h" -static uint32_t get_legacy_gen_id(SkSurface* surf) { - SkBaseDevice* device = surf->getCanvas()->getDevice_just_for_deprecated_compatibility_testing(); - return device->accessBitmap(false).getGenerationID(); -} - -/* - * Test legacy behavor of bumping the surface's device's bitmap's genID when we access its - * texture handle for writing. - * - * Note: this needs to be tested separately from checking newImageSnapshot, as calling that - * can also incidentally bump the genID (when a new backing surface is created). - */ -template <class F> -static void test_texture_handle_genID(skiatest::Reporter* reporter, SkSurface* surf, F f) { - const uint32_t gen0 = get_legacy_gen_id(surf); - f(surf, SkSurface::kFlushRead_BackendHandleAccess); - const uint32_t gen1 = get_legacy_gen_id(surf); - REPORTER_ASSERT(reporter, gen0 == gen1); - - f(surf, SkSurface::kFlushWrite_BackendHandleAccess); - const uint32_t gen2 = get_legacy_gen_id(surf); - REPORTER_ASSERT(reporter, gen0 != gen2); - - f(surf, SkSurface::kDiscardWrite_BackendHandleAccess); - const uint32_t gen3 = get_legacy_gen_id(surf); - REPORTER_ASSERT(reporter, gen0 != gen3); - REPORTER_ASSERT(reporter, gen2 != gen3); -} - -template <class F> -static void test_backend_handle(skiatest::Reporter* reporter, SkSurface* surf, F f) { - SkAutoTUnref<SkImage> image0(surf->newImageSnapshot()); - GrBackendObject obj = f(surf, SkSurface::kFlushRead_BackendHandleAccess); - REPORTER_ASSERT(reporter, obj != 0); - SkAutoTUnref<SkImage> image1(surf->newImageSnapshot()); - // just read access should not affect the snapshot - REPORTER_ASSERT(reporter, image0->uniqueID() == image1->uniqueID()); - - obj = f(surf, SkSurface::kFlushWrite_BackendHandleAccess); - REPORTER_ASSERT(reporter, obj != 0); - SkAutoTUnref<SkImage> image2(surf->newImageSnapshot()); - // expect a new image, since we claimed we would write - REPORTER_ASSERT(reporter, image0->uniqueID() != image2->uniqueID()); - - obj = f(surf, SkSurface::kDiscardWrite_BackendHandleAccess); - REPORTER_ASSERT(reporter, obj != 0); - SkAutoTUnref<SkImage> image3(surf->newImageSnapshot()); - // expect a new(er) image, since we claimed we would write - REPORTER_ASSERT(reporter, image0->uniqueID() != image3->uniqueID()); - REPORTER_ASSERT(reporter, image2->uniqueID() != image3->uniqueID()); -} - -static SkImage* create_image(skiatest::Reporter* reporter, - ImageType imageType, GrContext* context, SkColor color, - ReleaseDataContext* releaseContext) { - const SkPMColor pmcolor = SkPreMultiplyColor(color); - const SkImageInfo info = SkImageInfo::MakeN32Premul(10, 10); - const size_t rowBytes = info.minRowBytes(); - const size_t size = rowBytes * info.height(); - - SkAutoTUnref<SkData> data(SkData::NewUninitialized(size)); - void* addr = data->writable_data(); - sk_memset32((SkPMColor*)addr, pmcolor, SkToInt(size >> 2)); - - switch (imageType) { - case kRasterCopy_ImageType: - return SkImage::NewRasterCopy(info, addr, rowBytes); - case kRasterData_ImageType: - return SkImage::NewRasterData(info, data, rowBytes); - case kRasterProc_ImageType: - SkASSERT(releaseContext); - releaseContext->fData = SkRef(data.get()); - return SkImage::NewFromRaster(info, addr, rowBytes, - ReleaseDataContext::Release, releaseContext); - case kGpu_ImageType: { - SkAutoTUnref<SkSurface> surf( - SkSurface::NewRenderTarget(context, SkSurface::kNo_Budgeted, info, 0)); - surf->getCanvas()->clear(color); - // test our backing texture / rendertarget while were here... - auto textureAccessorFunc = - [](SkSurface* surf, SkSurface::BackendHandleAccess access) -> GrBackendObject { - return surf->getTextureHandle(access); }; - auto renderTargetAccessorFunc = - [](SkSurface* surf, SkSurface::BackendHandleAccess access) -> GrBackendObject { - GrBackendObject obj; - SkAssertResult(surf->getRenderTargetHandle(&obj, access)); - return obj; }; - test_backend_handle(reporter, surf, textureAccessorFunc); - test_backend_handle(reporter, surf, renderTargetAccessorFunc); - test_texture_handle_genID(reporter, surf, textureAccessorFunc); - test_texture_handle_genID(reporter, surf, renderTargetAccessorFunc); - - // redraw so our returned image looks as expected. - surf->getCanvas()->clear(color); - return surf->newImageSnapshot(); - } - case kCodec_ImageType: { - SkBitmap bitmap; - bitmap.installPixels(info, addr, rowBytes); - SkAutoTUnref<SkData> src( - SkImageEncoder::EncodeData(bitmap, SkImageEncoder::kPNG_Type, 100)); - return SkImage::NewFromEncoded(src); - } - } - SkASSERT(false); - return nullptr; -} - -static void set_pixels(SkPMColor pixels[], int count, SkPMColor color) { - sk_memset32(pixels, color, count); -} -static bool has_pixels(const SkPMColor pixels[], int count, SkPMColor expected) { - for (int i = 0; i < count; ++i) { - if (pixels[i] != expected) { - return false; - } - } - return true; -} - -static void test_image_readpixels(skiatest::Reporter* reporter, SkImage* image, - SkPMColor expected) { - const SkPMColor notExpected = ~expected; - - const int w = 2, h = 2; - const size_t rowBytes = w * sizeof(SkPMColor); - SkPMColor pixels[w*h]; - - SkImageInfo info; - - info = SkImageInfo::MakeUnknown(w, h); - REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, 0, 0)); - - // out-of-bounds should fail - info = SkImageInfo::MakeN32Premul(w, h); - REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, -w, 0)); - REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, 0, -h)); - REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, image->width(), 0)); - REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, 0, image->height())); - - // top-left should succeed - set_pixels(pixels, w*h, notExpected); - REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes, 0, 0)); - REPORTER_ASSERT(reporter, has_pixels(pixels, w*h, expected)); - - // bottom-right should succeed - set_pixels(pixels, w*h, notExpected); - REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes, - image->width() - w, image->height() - h)); - REPORTER_ASSERT(reporter, has_pixels(pixels, w*h, expected)); - - // partial top-left should succeed - set_pixels(pixels, w*h, notExpected); - REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes, -1, -1)); - REPORTER_ASSERT(reporter, pixels[3] == expected); - REPORTER_ASSERT(reporter, has_pixels(pixels, w*h - 1, notExpected)); - - // partial bottom-right should succeed - set_pixels(pixels, w*h, notExpected); - REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes, - image->width() - 1, image->height() - 1)); - REPORTER_ASSERT(reporter, pixels[0] == expected); - REPORTER_ASSERT(reporter, has_pixels(&pixels[1], w*h - 1, notExpected)); -} - -static void check_legacy_bitmap(skiatest::Reporter* reporter, const SkImage* image, - const SkBitmap& bitmap, SkImage::LegacyBitmapMode mode) { - REPORTER_ASSERT(reporter, image->width() == bitmap.width()); - REPORTER_ASSERT(reporter, image->height() == bitmap.height()); - REPORTER_ASSERT(reporter, image->isOpaque() == bitmap.isOpaque()); - - if (SkImage::kRO_LegacyBitmapMode == mode) { - REPORTER_ASSERT(reporter, bitmap.isImmutable()); - } - - SkAutoLockPixels alp(bitmap); - REPORTER_ASSERT(reporter, bitmap.getPixels()); - - const SkImageInfo info = SkImageInfo::MakeN32(1, 1, bitmap.alphaType()); - SkPMColor imageColor; - REPORTER_ASSERT(reporter, image->readPixels(info, &imageColor, sizeof(SkPMColor), 0, 0)); - REPORTER_ASSERT(reporter, imageColor == *bitmap.getAddr32(0, 0)); -} - -static void test_legacy_bitmap(skiatest::Reporter* reporter, const SkImage* image) { - const SkImage::LegacyBitmapMode modes[] = { - SkImage::kRO_LegacyBitmapMode, - SkImage::kRW_LegacyBitmapMode, - }; - for (size_t i = 0; i < SK_ARRAY_COUNT(modes); ++i) { - SkBitmap bitmap; - REPORTER_ASSERT(reporter, image->asLegacyBitmap(&bitmap, modes[i])); - check_legacy_bitmap(reporter, image, bitmap, modes[i]); - - // Test subsetting to exercise the rowBytes logic. - SkBitmap tmp; - REPORTER_ASSERT(reporter, bitmap.extractSubset(&tmp, SkIRect::MakeWH(image->width() / 2, - image->height() / 2))); - SkAutoTUnref<SkImage> subsetImage(SkImage::NewFromBitmap(tmp)); - REPORTER_ASSERT(reporter, subsetImage); - - SkBitmap subsetBitmap; - REPORTER_ASSERT(reporter, subsetImage->asLegacyBitmap(&subsetBitmap, modes[i])); - check_legacy_bitmap(reporter, subsetImage, subsetBitmap, modes[i]); - } -} - -static void test_imagepeek(skiatest::Reporter* reporter, GrContextFactory* factory) { - static const struct { - ImageType fType; - bool fPeekShouldSucceed; - const char* fName; - } gRec[] = { - { kRasterCopy_ImageType, true, "RasterCopy" }, - { kRasterData_ImageType, true, "RasterData" }, - { kRasterProc_ImageType, true, "RasterProc" }, - { kGpu_ImageType, false, "Gpu" }, - { kCodec_ImageType, false, "Codec" }, - }; - - const SkColor color = SK_ColorRED; - const SkPMColor pmcolor = SkPreMultiplyColor(color); - - GrContext* ctx = nullptr; -#if SK_SUPPORT_GPU - ctx = factory->get(GrContextFactory::kNative_GLContextType); - if (nullptr == ctx) { - return; - } -#endif - - ReleaseDataContext releaseCtx; - releaseCtx.fReporter = reporter; - - for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) { - SkImageInfo info; - size_t rowBytes; - - releaseCtx.fData = nullptr; - SkAutoTUnref<SkImage> image(create_image(reporter, gRec[i].fType, ctx, color, &releaseCtx)); - if (!image.get()) { - SkDebugf("failed to createImage[%d] %s\n", i, gRec[i].fName); - continue; // gpu may not be enabled - } - if (kRasterProc_ImageType == gRec[i].fType) { - REPORTER_ASSERT(reporter, nullptr != releaseCtx.fData); // we are tracking the data - } else { - REPORTER_ASSERT(reporter, nullptr == releaseCtx.fData); // we ignored the context - } - - test_legacy_bitmap(reporter, image); - - const void* addr = image->peekPixels(&info, &rowBytes); - bool success = SkToBool(addr); - REPORTER_ASSERT(reporter, gRec[i].fPeekShouldSucceed == success); - if (success) { - REPORTER_ASSERT(reporter, 10 == info.width()); - REPORTER_ASSERT(reporter, 10 == info.height()); - REPORTER_ASSERT(reporter, kN32_SkColorType == info.colorType()); - REPORTER_ASSERT(reporter, kPremul_SkAlphaType == info.alphaType() || - kOpaque_SkAlphaType == info.alphaType()); - REPORTER_ASSERT(reporter, info.minRowBytes() <= rowBytes); - REPORTER_ASSERT(reporter, pmcolor == *(const SkPMColor*)addr); - } - - test_image_readpixels(reporter, image, pmcolor); - } - REPORTER_ASSERT(reporter, nullptr == releaseCtx.fData); // we released the data -} static void test_canvaspeek(skiatest::Reporter* reporter, GrContextFactory* factory) { @@ -883,17 +561,15 @@ static void TestSurfaceNoCanvas(skiatest::Reporter* reporter, } DEF_GPUTEST(Surface, reporter, factory) { - test_image(reporter); - TestSurfaceCopyOnWrite(reporter, kRaster_SurfaceType, nullptr); TestSurfaceWritableAfterSnapshotRelease(reporter, kRaster_SurfaceType, nullptr); TestSurfaceNoCanvas(reporter, kRaster_SurfaceType, nullptr, SkSurface::kDiscard_ContentChangeMode); TestSurfaceNoCanvas(reporter, kRaster_SurfaceType, nullptr, SkSurface::kRetain_ContentChangeMode); - test_empty_image(reporter); + test_empty_surface(reporter, nullptr); - test_imagepeek(reporter, factory); + test_canvaspeek(reporter, factory); test_accessPixels(reporter, factory); @@ -931,103 +607,4 @@ DEF_GPUTEST(Surface, reporter, factory) { #endif } -#if SK_SUPPORT_GPU - -struct ReleaseTextureContext { - ReleaseTextureContext(skiatest::Reporter* reporter) { - fReporter = reporter; - fIsReleased = false; - } - - skiatest::Reporter* fReporter; - bool fIsReleased; - - void doRelease() { - REPORTER_ASSERT(fReporter, false == fIsReleased); - fIsReleased = true; - } - - static void ReleaseProc(void* context) { - ((ReleaseTextureContext*)context)->doRelease(); - } -}; - -static SkImage* make_desc_image(GrContext* ctx, int w, int h, GrBackendObject texID, - ReleaseTextureContext* releaseContext) { - GrBackendTextureDesc desc; - desc.fConfig = kSkia8888_GrPixelConfig; - // need to be a rendertarget for now... - desc.fFlags = kRenderTarget_GrBackendTextureFlag; - desc.fWidth = w; - desc.fHeight = h; - desc.fSampleCnt = 0; - desc.fTextureHandle = texID; - return releaseContext - ? SkImage::NewFromTexture(ctx, desc, kPremul_SkAlphaType, - ReleaseTextureContext::ReleaseProc, releaseContext) - : SkImage::NewFromTextureCopy(ctx, desc, kPremul_SkAlphaType); -} - -static void test_image_color(skiatest::Reporter* reporter, SkImage* image, SkPMColor expected) { - const SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1); - SkPMColor pixel; - REPORTER_ASSERT(reporter, image->readPixels(info, &pixel, sizeof(pixel), 0, 0)); - REPORTER_ASSERT(reporter, pixel == expected); -} - -DEF_GPUTEST(SkImage_NewFromTexture, reporter, factory) { - GrContext* ctx = factory->get(GrContextFactory::kNative_GLContextType); - if (!ctx) { - REPORTER_ASSERT(reporter, false); - return; - } - GrTextureProvider* provider = ctx->textureProvider(); - - const int w = 10; - const int h = 10; - SkPMColor storage[w * h]; - const SkPMColor expected0 = SkPreMultiplyColor(SK_ColorRED); - sk_memset32(storage, expected0, w * h); - - GrSurfaceDesc desc; - desc.fFlags = kRenderTarget_GrSurfaceFlag; // needs to be a rendertarget for readpixels(); - desc.fOrigin = kDefault_GrSurfaceOrigin; - desc.fWidth = w; - desc.fHeight = h; - desc.fConfig = kSkia8888_GrPixelConfig; - desc.fSampleCnt = 0; - - SkAutoTUnref<GrTexture> tex(provider->createTexture(desc, false, storage, w * 4)); - if (!tex) { - REPORTER_ASSERT(reporter, false); - return; - } - - GrBackendObject srcTex = tex->getTextureHandle(); - ReleaseTextureContext releaseCtx(reporter); - - SkAutoTUnref<SkImage> refImg(make_desc_image(ctx, w, h, srcTex, &releaseCtx)); - SkAutoTUnref<SkImage> cpyImg(make_desc_image(ctx, w, h, srcTex, nullptr)); - test_image_color(reporter, refImg, expected0); - test_image_color(reporter, cpyImg, expected0); - - // Now lets jam new colors into our "external" texture, and see if the images notice - const SkPMColor expected1 = SkPreMultiplyColor(SK_ColorBLUE); - sk_memset32(storage, expected1, w * h); - tex->writePixels(0, 0, w, h, kSkia8888_GrPixelConfig, storage, GrContext::kFlushWrites_PixelOp); - - // The cpy'd one should still see the old color -#if 0 - // There is no guarantee that refImg sees the new color. We are free to have made a copy. Our - // write pixels call violated the contract with refImg and refImg is now undefined. - test_image_color(reporter, refImg, expected1); -#endif - test_image_color(reporter, cpyImg, expected0); - - // Now exercise the release proc - REPORTER_ASSERT(reporter, !releaseCtx.fIsReleased); - refImg.reset(nullptr); // force a release of the image - REPORTER_ASSERT(reporter, releaseCtx.fIsReleased); -} -#endif |