Reland "Add async rescale and read APIs to SkImage."
This reverts commit 1caf3789f8
.
Makes the image GMs detect an abandoned context just like the surface
GMs.
Bug: skia:10431
Change-Id: I56a3631a75e6b0383f96a73f461cfa314ee29afa
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/299379
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
This commit is contained in:
parent
56079c4c3e
commit
63a0a758ce
2
BUILD.gn
2
BUILD.gn
@ -1410,6 +1410,8 @@ if (skia_enable_tools) {
|
||||
deps = []
|
||||
public_deps = []
|
||||
sources = [
|
||||
"tools/gpu/BackendTextureImageFactory.cpp",
|
||||
"tools/gpu/BackendTextureImageFactory.h",
|
||||
"tools/gpu/GrContextFactory.cpp",
|
||||
"tools/gpu/GrTest.cpp",
|
||||
"tools/gpu/MemoryCache.cpp",
|
||||
|
@ -16,6 +16,9 @@ Milestone 86
|
||||
* Enable BackendSemaphores for the Direct3D backend.
|
||||
https://review.skia.org/298752
|
||||
|
||||
* Added SkImage:asyncRescaleAndReadPixels and SkImage::asyncRescaleAndReadPixelsYUV420
|
||||
https://review.skia.org/299281
|
||||
|
||||
* * *
|
||||
|
||||
Milestone 85
|
||||
|
@ -23,14 +23,14 @@
|
||||
namespace {
|
||||
struct AsyncContext {
|
||||
bool fCalled = false;
|
||||
std::unique_ptr<const SkSurface::AsyncReadResult> fResult;
|
||||
std::unique_ptr<const SkImage::AsyncReadResult> fResult;
|
||||
};
|
||||
} // anonymous namespace
|
||||
|
||||
// Making this a lambda in the test functions caused:
|
||||
// "error: cannot compile this forwarded non-trivially copyable parameter yet"
|
||||
// on x86/Win/Clang bot, referring to 'result'.
|
||||
static void async_callback(void* c, std::unique_ptr<const SkSurface::AsyncReadResult> result) {
|
||||
static void async_callback(void* c, std::unique_ptr<const SkImage::AsyncReadResult> result) {
|
||||
auto context = static_cast<AsyncContext*>(c);
|
||||
context->fResult = std::move(result);
|
||||
context->fCalled = true;
|
||||
@ -38,61 +38,70 @@ static void async_callback(void* c, std::unique_ptr<const SkSurface::AsyncReadRe
|
||||
|
||||
// Draws the image to a surface, does a asyncRescaleAndReadPixels of the image, and then sticks
|
||||
// the result in a raster image.
|
||||
static sk_sp<SkImage> do_read_and_scale(SkSurface* surface, const SkIRect& srcRect,
|
||||
const SkImageInfo& ii, SkSurface::RescaleGamma rescaleGamma,
|
||||
template <typename Src>
|
||||
static sk_sp<SkImage> do_read_and_scale(Src* src,
|
||||
GrContext* context,
|
||||
const SkIRect& srcRect,
|
||||
const SkImageInfo& ii,
|
||||
SkImage::RescaleGamma rescaleGamma,
|
||||
SkFilterQuality quality) {
|
||||
auto* context = new AsyncContext();
|
||||
surface->asyncRescaleAndReadPixels(ii, srcRect, rescaleGamma, quality, async_callback, context);
|
||||
if (auto ctx = surface->getContext()) {
|
||||
ctx->submit();
|
||||
auto* asyncContext = new AsyncContext();
|
||||
src->asyncRescaleAndReadPixels(ii, srcRect, rescaleGamma, quality, async_callback,
|
||||
asyncContext);
|
||||
if (context) {
|
||||
context->submit();
|
||||
}
|
||||
while (!context->fCalled) {
|
||||
while (!asyncContext->fCalled) {
|
||||
// Only GPU should actually be asynchronous.
|
||||
SkASSERT(surface->getCanvas()->getGrContext());
|
||||
surface->getCanvas()->getGrContext()->checkAsyncWorkCompletion();
|
||||
SkASSERT(context);
|
||||
context->checkAsyncWorkCompletion();
|
||||
}
|
||||
if (!context->fResult) {
|
||||
if (!asyncContext->fResult) {
|
||||
return nullptr;
|
||||
}
|
||||
SkPixmap pixmap(ii, context->fResult->data(0), context->fResult->rowBytes(0));
|
||||
SkPixmap pixmap(ii, asyncContext->fResult->data(0), asyncContext->fResult->rowBytes(0));
|
||||
auto releasePixels = [](const void*, void* c) { delete static_cast<AsyncContext*>(c); };
|
||||
return SkImage::MakeFromRaster(pixmap, releasePixels, context);
|
||||
return SkImage::MakeFromRaster(pixmap, releasePixels, asyncContext);
|
||||
}
|
||||
|
||||
static sk_sp<SkImage> do_read_and_scale_yuv(SkSurface* surface, SkYUVColorSpace yuvCS,
|
||||
const SkIRect& srcRect, SkISize size,
|
||||
SkSurface::RescaleGamma rescaleGamma,
|
||||
SkFilterQuality quality, SkScopeExit* cleanup) {
|
||||
template <typename Src>
|
||||
static sk_sp<SkImage> do_read_and_scale_yuv(Src* src,
|
||||
GrContext* context,
|
||||
SkYUVColorSpace yuvCS,
|
||||
const SkIRect& srcRect,
|
||||
SkISize size,
|
||||
SkImage::RescaleGamma rescaleGamma,
|
||||
SkFilterQuality quality,
|
||||
SkScopeExit* cleanup) {
|
||||
SkASSERT(!(size.width() & 0b1) && !(size.height() & 0b1));
|
||||
|
||||
SkISize uvSize = {size.width()/2, size.height()/2};
|
||||
SkImageInfo yII = SkImageInfo::Make(size, kGray_8_SkColorType, kPremul_SkAlphaType);
|
||||
SkImageInfo uvII = SkImageInfo::Make(uvSize, kGray_8_SkColorType, kPremul_SkAlphaType);
|
||||
|
||||
AsyncContext context;
|
||||
surface->asyncRescaleAndReadPixelsYUV420(yuvCS, SkColorSpace::MakeSRGB(), srcRect, size,
|
||||
rescaleGamma, quality, async_callback, &context);
|
||||
if (auto ctx = surface->getContext()) {
|
||||
ctx->submit();
|
||||
AsyncContext asyncContext;
|
||||
src->asyncRescaleAndReadPixelsYUV420(yuvCS, SkColorSpace::MakeSRGB(), srcRect, size,
|
||||
rescaleGamma, quality, async_callback, &asyncContext);
|
||||
if (context) {
|
||||
context->submit();
|
||||
}
|
||||
while (!context.fCalled) {
|
||||
while (!asyncContext.fCalled) {
|
||||
// Only GPU should actually be asynchronous.
|
||||
SkASSERT(surface->getCanvas()->getGrContext());
|
||||
surface->getCanvas()->getGrContext()->checkAsyncWorkCompletion();
|
||||
SkASSERT(context);
|
||||
context->checkAsyncWorkCompletion();
|
||||
}
|
||||
if (!context.fResult) {
|
||||
if (!asyncContext.fResult) {
|
||||
return nullptr;
|
||||
}
|
||||
auto* gr = surface->getCanvas()->getGrContext();
|
||||
GrBackendTexture backendTextures[3];
|
||||
|
||||
SkPixmap yPM(yII, context.fResult->data(0), context.fResult->rowBytes(0));
|
||||
SkPixmap uPM(uvII, context.fResult->data(1), context.fResult->rowBytes(1));
|
||||
SkPixmap vPM(uvII, context.fResult->data(2), context.fResult->rowBytes(2));
|
||||
SkPixmap yPM(yII, asyncContext.fResult->data(0), asyncContext.fResult->rowBytes(0));
|
||||
SkPixmap uPM(uvII, asyncContext.fResult->data(1), asyncContext.fResult->rowBytes(1));
|
||||
SkPixmap vPM(uvII, asyncContext.fResult->data(2), asyncContext.fResult->rowBytes(2));
|
||||
|
||||
backendTextures[0] = gr->createBackendTexture(yPM, GrRenderable::kNo, GrProtected::kNo);
|
||||
backendTextures[1] = gr->createBackendTexture(uPM, GrRenderable::kNo, GrProtected::kNo);
|
||||
backendTextures[2] = gr->createBackendTexture(vPM, GrRenderable::kNo, GrProtected::kNo);
|
||||
backendTextures[0] = context->createBackendTexture(yPM, GrRenderable::kNo, GrProtected::kNo);
|
||||
backendTextures[1] = context->createBackendTexture(uPM, GrRenderable::kNo, GrProtected::kNo);
|
||||
backendTextures[2] = context->createBackendTexture(vPM, GrRenderable::kNo, GrProtected::kNo);
|
||||
|
||||
SkYUVAIndex indices[4] = {
|
||||
{ 0, SkColorChannel::kR},
|
||||
@ -101,25 +110,31 @@ static sk_sp<SkImage> do_read_and_scale_yuv(SkSurface* surface, SkYUVColorSpace
|
||||
{-1, SkColorChannel::kR}
|
||||
};
|
||||
|
||||
*cleanup = {[gr, backendTextures] {
|
||||
*cleanup = {[context, backendTextures] {
|
||||
GrFlushInfo flushInfo;
|
||||
flushInfo.fFlags = kSyncCpu_GrFlushFlag;
|
||||
gr->flush(flushInfo);
|
||||
gr->submit(true);
|
||||
gr->deleteBackendTexture(backendTextures[0]);
|
||||
gr->deleteBackendTexture(backendTextures[1]);
|
||||
gr->deleteBackendTexture(backendTextures[2]);
|
||||
context->flush(flushInfo);
|
||||
context->submit(true);
|
||||
context->deleteBackendTexture(backendTextures[0]);
|
||||
context->deleteBackendTexture(backendTextures[1]);
|
||||
context->deleteBackendTexture(backendTextures[2]);
|
||||
}};
|
||||
|
||||
return SkImage::MakeFromYUVATextures(gr, yuvCS, backendTextures, indices, size,
|
||||
return SkImage::MakeFromYUVATextures(context, yuvCS, backendTextures, indices, size,
|
||||
kTopLeft_GrSurfaceOrigin, SkColorSpace::MakeSRGB());
|
||||
}
|
||||
|
||||
// Draws a grid of rescales. The columns are none, low, and high filter quality. The rows are
|
||||
// rescale in src gamma and rescale in linear gamma.
|
||||
static skiagm::DrawResult do_rescale_grid(SkCanvas* canvas, SkSurface* surface,
|
||||
const SkIRect& srcRect, SkISize newSize, bool doYUV420,
|
||||
SkString* errorMsg, int pad = 0) {
|
||||
template <typename Src>
|
||||
static skiagm::DrawResult do_rescale_grid(SkCanvas* canvas,
|
||||
Src* src,
|
||||
GrContext* context,
|
||||
const SkIRect& srcRect,
|
||||
SkISize newSize,
|
||||
bool doYUV420,
|
||||
SkString* errorMsg,
|
||||
int pad = 0) {
|
||||
if (doYUV420) {
|
||||
if (!canvas->getGrContext() || !canvas->getGrContext()->priv().asDirectContext()) {
|
||||
errorMsg->printf("YUV420 only supported on direct GPU for now.");
|
||||
@ -134,13 +149,13 @@ static skiagm::DrawResult do_rescale_grid(SkCanvas* canvas, SkSurface* surface,
|
||||
|
||||
SkYUVColorSpace yuvColorSpace = kRec601_SkYUVColorSpace;
|
||||
canvas->save();
|
||||
for (auto gamma : {SkSurface::RescaleGamma::kSrc, SkSurface::RescaleGamma::kLinear}) {
|
||||
for (auto gamma : {SkImage::RescaleGamma::kSrc, SkImage::RescaleGamma::kLinear}) {
|
||||
canvas->save();
|
||||
for (auto quality : {kNone_SkFilterQuality, kLow_SkFilterQuality, kHigh_SkFilterQuality}) {
|
||||
SkScopeExit cleanup;
|
||||
sk_sp<SkImage> result;
|
||||
if (doYUV420) {
|
||||
result = do_read_and_scale_yuv(surface, yuvColorSpace, srcRect, newSize, gamma,
|
||||
result = do_read_and_scale_yuv(src, context, yuvColorSpace, srcRect, newSize, gamma,
|
||||
quality, &cleanup);
|
||||
if (!result) {
|
||||
errorMsg->printf("YUV420 async call failed. Allowed for now.");
|
||||
@ -149,7 +164,7 @@ static skiagm::DrawResult do_rescale_grid(SkCanvas* canvas, SkSurface* surface,
|
||||
int nextCS = static_cast<int>(yuvColorSpace + 1) % (kLastEnum_SkYUVColorSpace + 1);
|
||||
yuvColorSpace = static_cast<SkYUVColorSpace>(nextCS);
|
||||
} else {
|
||||
result = do_read_and_scale(surface, srcRect, ii, gamma, quality);
|
||||
result = do_read_and_scale(src, context, srcRect, ii, gamma, quality);
|
||||
if (!result) {
|
||||
errorMsg->printf("async read call failed.");
|
||||
return skiagm::DrawResult::kFail;
|
||||
@ -165,9 +180,13 @@ static skiagm::DrawResult do_rescale_grid(SkCanvas* canvas, SkSurface* surface,
|
||||
return skiagm::DrawResult::kOk;
|
||||
}
|
||||
|
||||
static skiagm::DrawResult do_rescale_image_grid(SkCanvas* canvas, const char* imageFile,
|
||||
const SkIRect& srcRect, SkISize newSize,
|
||||
bool doYUV420, SkString* errorMsg) {
|
||||
static skiagm::DrawResult do_rescale_image_grid(SkCanvas* canvas,
|
||||
const char* imageFile,
|
||||
const SkIRect& srcRect,
|
||||
SkISize newSize,
|
||||
bool doSurface,
|
||||
bool doYUV420,
|
||||
SkString* errorMsg) {
|
||||
auto image = GetResourceAsImage(imageFile);
|
||||
if (!image) {
|
||||
errorMsg->printf("Could not load image file %s.", imageFile);
|
||||
@ -177,54 +196,89 @@ static skiagm::DrawResult do_rescale_image_grid(SkCanvas* canvas, const char* im
|
||||
*errorMsg = "Not supported on recording/vector backends.";
|
||||
return skiagm::DrawResult::kSkip;
|
||||
}
|
||||
// Turn the image into a surface in order to call the read and rescale API
|
||||
auto surfInfo = image->imageInfo().makeDimensions(image->dimensions());
|
||||
auto surface = canvas->makeSurface(surfInfo);
|
||||
if (!surface && surfInfo.colorType() == kBGRA_8888_SkColorType) {
|
||||
surfInfo = surfInfo.makeColorType(kRGBA_8888_SkColorType);
|
||||
surface = canvas->makeSurface(surfInfo);
|
||||
}
|
||||
if (!surface) {
|
||||
*errorMsg = "Could not create surface for image.";
|
||||
// When testing abandoned GrContext we expect surface creation to fail.
|
||||
if (canvas->getGrContext() && canvas->getGrContext()->abandoned()) {
|
||||
return skiagm::DrawResult::kSkip;
|
||||
if (doSurface) {
|
||||
// Turn the image into a surface in order to call the read and rescale API
|
||||
auto surfInfo = image->imageInfo().makeDimensions(image->dimensions());
|
||||
auto surface = canvas->makeSurface(surfInfo);
|
||||
if (!surface && surfInfo.colorType() == kBGRA_8888_SkColorType) {
|
||||
surfInfo = surfInfo.makeColorType(kRGBA_8888_SkColorType);
|
||||
surface = canvas->makeSurface(surfInfo);
|
||||
}
|
||||
if (!surface) {
|
||||
*errorMsg = "Could not create surface for image.";
|
||||
// When testing abandoned GrContext we expect surface creation to fail.
|
||||
if (canvas->getGrContext() && canvas->getGrContext()->abandoned()) {
|
||||
return skiagm::DrawResult::kSkip;
|
||||
}
|
||||
return skiagm::DrawResult::kFail;
|
||||
}
|
||||
SkPaint paint;
|
||||
paint.setBlendMode(SkBlendMode::kSrc);
|
||||
surface->getCanvas()->drawImage(image, 0, 0, &paint);
|
||||
return do_rescale_grid(canvas, surface.get(), canvas->getGrContext(), srcRect, newSize,
|
||||
doYUV420, errorMsg);
|
||||
} else if (auto ctx = canvas->getGrContext()) {
|
||||
image = image->makeTextureImage(ctx);
|
||||
if (!image) {
|
||||
*errorMsg = "Could not create image.";
|
||||
// When testing abandoned GrContext we expect surface creation to fail.
|
||||
if (canvas->getGrContext() && canvas->getGrContext()->abandoned()) {
|
||||
return skiagm::DrawResult::kSkip;
|
||||
}
|
||||
return skiagm::DrawResult::kFail;
|
||||
}
|
||||
return skiagm::DrawResult::kFail;
|
||||
}
|
||||
SkPaint paint;
|
||||
paint.setBlendMode(SkBlendMode::kSrc);
|
||||
surface->getCanvas()->drawImage(image, 0, 0, &paint);
|
||||
return do_rescale_grid(canvas, surface.get(), srcRect, newSize, doYUV420, errorMsg);
|
||||
return do_rescale_grid(canvas, image.get(), canvas->getGrContext(), srcRect, newSize, doYUV420,
|
||||
errorMsg);
|
||||
}
|
||||
|
||||
#define DEF_RESCALE_AND_READ_GM(IMAGE_FILE, TAG, SRC_RECT, W, H) \
|
||||
DEF_SIMPLE_GM_CAN_FAIL(async_rescale_and_read_##TAG, canvas, errorMsg, 3 * W, 2 * H) { \
|
||||
ToolUtils::draw_checkerboard(canvas, SK_ColorDKGRAY, SK_ColorLTGRAY, 25); \
|
||||
return do_rescale_image_grid(canvas, #IMAGE_FILE, SRC_RECT, {W, H}, false, errorMsg); \
|
||||
#define DEF_RESCALE_AND_READ_SURF_GM(IMAGE_FILE, TAG, SRC_RECT, W, H) \
|
||||
DEF_SIMPLE_GM_CAN_FAIL(async_rescale_and_read_##TAG, canvas, errorMsg, 3 * W, 2 * H) { \
|
||||
ToolUtils::draw_checkerboard(canvas, SK_ColorDKGRAY, SK_ColorLTGRAY, 25); \
|
||||
return do_rescale_image_grid(canvas, #IMAGE_FILE, SRC_RECT, {W, H}, true, false, \
|
||||
errorMsg); \
|
||||
}
|
||||
|
||||
#define DEF_RESCALE_AND_READ_YUV_GM(IMAGE_FILE, TAG, SRC_RECT, W, H) \
|
||||
DEF_SIMPLE_GM_CAN_FAIL(async_rescale_and_read_yuv420_##TAG, canvas, errorMsg, 3 * W, 2 * H) { \
|
||||
ToolUtils::draw_checkerboard(canvas, SK_ColorDKGRAY, SK_ColorLTGRAY, 25); \
|
||||
return do_rescale_image_grid(canvas, #IMAGE_FILE, SRC_RECT, {W, H}, true, errorMsg); \
|
||||
#define DEF_RESCALE_AND_READ_YUV_SURF_GM(IMAGE_FILE, TAG, SRC_RECT, W, H) \
|
||||
DEF_SIMPLE_GM_CAN_FAIL(async_rescale_and_read_yuv420_##TAG, canvas, errorMsg, 3 * W, 2 * H) { \
|
||||
ToolUtils::draw_checkerboard(canvas, SK_ColorDKGRAY, SK_ColorLTGRAY, 25); \
|
||||
return do_rescale_image_grid(canvas, #IMAGE_FILE, SRC_RECT, {W, H}, true, true, errorMsg); \
|
||||
}
|
||||
|
||||
DEF_RESCALE_AND_READ_YUV_GM(images/yellow_rose.webp, rose, SkIRect::MakeXYWH(50, 5, 200, 150),
|
||||
410, 376)
|
||||
#define DEF_RESCALE_AND_READ_IMG_GM(IMAGE_FILE, TAG, SRC_RECT, W, H) \
|
||||
DEF_SIMPLE_GM_CAN_FAIL(async_rescale_and_read_##TAG, canvas, errorMsg, 3 * W, 2 * H) { \
|
||||
ToolUtils::draw_checkerboard(canvas, SK_ColorDKGRAY, SK_ColorLTGRAY, 25); \
|
||||
return do_rescale_image_grid(canvas, #IMAGE_FILE, SRC_RECT, {W, H}, false, false, \
|
||||
errorMsg); \
|
||||
}
|
||||
|
||||
DEF_RESCALE_AND_READ_GM(images/yellow_rose.webp, rose, SkIRect::MakeXYWH(100, 20, 100, 100),
|
||||
410, 410)
|
||||
#define DEF_RESCALE_AND_READ_YUV_IMG_GM(IMAGE_FILE, TAG, SRC_RECT, W, H) \
|
||||
DEF_SIMPLE_GM_CAN_FAIL(async_rescale_and_read_yuv420_##TAG, canvas, errorMsg, 3 * W, 2 * H) { \
|
||||
ToolUtils::draw_checkerboard(canvas, SK_ColorDKGRAY, SK_ColorLTGRAY, 25); \
|
||||
return do_rescale_image_grid(canvas, #IMAGE_FILE, SRC_RECT, {W, H}, true, true, errorMsg); \
|
||||
}
|
||||
|
||||
DEF_RESCALE_AND_READ_GM(images/dog.jpg, dog_down, SkIRect::MakeXYWH(0, 10, 180, 150), 45, 45)
|
||||
DEF_RESCALE_AND_READ_GM(images/dog.jpg, dog_up, SkIRect::MakeWH(180, 180), 800, 400)
|
||||
DEF_RESCALE_AND_READ_YUV_SURF_GM(
|
||||
images/yellow_rose.webp, rose, SkIRect::MakeXYWH(50, 5, 200, 150), 410, 376)
|
||||
|
||||
DEF_RESCALE_AND_READ_GM(images/text.png, text_down, SkIRect::MakeWH(637, 105), (int)(0.7 * 637),
|
||||
(int)(0.7 * 105))
|
||||
DEF_RESCALE_AND_READ_GM(images/text.png, text_up, SkIRect::MakeWH(637, 105), (int)(1.2 * 637),
|
||||
(int)(1.2 * 105))
|
||||
DEF_RESCALE_AND_READ_GM(images/text.png, text_up_large, SkIRect::MakeXYWH(300, 0, 300, 105),
|
||||
(int)(2.4 * 300), (int)(2.4 * 105))
|
||||
DEF_RESCALE_AND_READ_YUV_IMG_GM(
|
||||
images/yellow_rose.webp, rose_down, SkIRect::MakeXYWH(50, 5, 200, 150), 106, 60)
|
||||
|
||||
DEF_RESCALE_AND_READ_SURF_GM(
|
||||
images/yellow_rose.webp, rose, SkIRect::MakeXYWH(100, 20, 100, 100), 410, 410)
|
||||
|
||||
DEF_RESCALE_AND_READ_SURF_GM(images/dog.jpg, dog_down, SkIRect::MakeXYWH(0, 10, 180, 150), 45, 45)
|
||||
DEF_RESCALE_AND_READ_IMG_GM(images/dog.jpg, dog_up, SkIRect::MakeWH(180, 180), 800, 400)
|
||||
|
||||
DEF_RESCALE_AND_READ_IMG_GM(
|
||||
images/text.png, text_down, SkIRect::MakeWH(637, 105), (int)(0.7 * 637), (int)(0.7 * 105))
|
||||
DEF_RESCALE_AND_READ_SURF_GM(
|
||||
images/text.png, text_up, SkIRect::MakeWH(637, 105), (int)(1.2 * 637), (int)(1.2 * 105))
|
||||
DEF_RESCALE_AND_READ_IMG_GM(images/text.png,
|
||||
text_up_large,
|
||||
SkIRect::MakeXYWH(300, 0, 300, 105),
|
||||
(int)(2.4 * 300),
|
||||
(int)(2.4 * 105))
|
||||
|
||||
// Exercises non-scaling YUV420. Reads from the original canvas's surface in order to
|
||||
// exercise case where source surface is not a texture (in glbert config).
|
||||
@ -244,8 +298,8 @@ DEF_SIMPLE_GM_CAN_FAIL(async_yuv_no_scale, canvas, errorMsg, 400, 300) {
|
||||
|
||||
SkScopeExit scopeExit;
|
||||
auto yuvImage = do_read_and_scale_yuv(
|
||||
surface, kRec601_SkYUVColorSpace, SkIRect::MakeWH(400, 300), {400, 300},
|
||||
SkSurface::RescaleGamma::kSrc, kNone_SkFilterQuality, &scopeExit);
|
||||
surface, surface->getContext(), kRec601_SkYUVColorSpace, SkIRect::MakeWH(400, 300),
|
||||
{400, 300}, SkImage::RescaleGamma::kSrc, kNone_SkFilterQuality, &scopeExit);
|
||||
|
||||
canvas->clear(SK_ColorWHITE);
|
||||
canvas->drawImage(yuvImage.get(), 0, 0);
|
||||
@ -283,13 +337,17 @@ DEF_SIMPLE_GM_CAN_FAIL(async_rescale_and_read_no_bleed, canvas, errorMsg, 60, 60
|
||||
canvas->translate(kPad, kPad);
|
||||
skiagm::DrawResult result;
|
||||
SkISize downSize = {static_cast<int>(kInner/2), static_cast<int>(kInner / 2)};
|
||||
result = do_rescale_grid(canvas, surface.get(), srcRect, downSize, false, errorMsg, kPad);
|
||||
GrContext* context = canvas->getGrContext();
|
||||
result = do_rescale_grid(canvas, surface.get(), context, srcRect, downSize, false, errorMsg,
|
||||
kPad);
|
||||
|
||||
if (result != skiagm::DrawResult::kOk) {
|
||||
return result;
|
||||
}
|
||||
canvas->translate(0, 4 * downSize.height());
|
||||
SkISize upSize = {static_cast<int>(kInner * 3.5), static_cast<int>(kInner * 4.6)};
|
||||
result = do_rescale_grid(canvas, surface.get(), srcRect, upSize, false, errorMsg, kPad);
|
||||
result =
|
||||
do_rescale_grid(canvas, surface.get(), context, srcRect, upSize, false, errorMsg, kPad);
|
||||
if (result != skiagm::DrawResult::kOk) {
|
||||
return result;
|
||||
}
|
||||
|
@ -418,6 +418,8 @@ skia_core_sources = [
|
||||
"$_src/image/SkImage_Lazy.cpp",
|
||||
"$_src/image/SkImage_Lazy.h",
|
||||
"$_src/image/SkImage_Raster.cpp",
|
||||
"$_src/image/SkRescaleAndReadPixels.cpp",
|
||||
"$_src/image/SkRescaleAndReadPixels.h",
|
||||
"$_src/image/SkSurface.cpp",
|
||||
"$_src/image/SkSurface_Base.h",
|
||||
|
||||
|
@ -958,6 +958,108 @@ public:
|
||||
bool readPixels(const SkPixmap& dst, int srcX, int srcY,
|
||||
CachingHint cachingHint = kAllow_CachingHint) const;
|
||||
|
||||
/** The result from asyncRescaleAndReadPixels() or asyncRescaleAndReadPixelsYUV420(). */
|
||||
class AsyncReadResult {
|
||||
public:
|
||||
AsyncReadResult(const AsyncReadResult&) = delete;
|
||||
AsyncReadResult(AsyncReadResult&&) = delete;
|
||||
AsyncReadResult& operator=(const AsyncReadResult&) = delete;
|
||||
AsyncReadResult& operator=(AsyncReadResult&&) = delete;
|
||||
|
||||
virtual ~AsyncReadResult() = default;
|
||||
virtual int count() const = 0;
|
||||
virtual const void* data(int i) const = 0;
|
||||
virtual size_t rowBytes(int i) const = 0;
|
||||
|
||||
protected:
|
||||
AsyncReadResult() = default;
|
||||
};
|
||||
|
||||
/** Client-provided context that is passed to client-provided ReadPixelsContext. */
|
||||
using ReadPixelsContext = void*;
|
||||
|
||||
/** Client-provided callback to asyncRescaleAndReadPixels() or
|
||||
asyncRescaleAndReadPixelsYUV420() that is called when read result is ready or on failure.
|
||||
*/
|
||||
using ReadPixelsCallback = void(ReadPixelsContext, std::unique_ptr<const AsyncReadResult>);
|
||||
|
||||
enum class RescaleGamma : bool { kSrc, kLinear };
|
||||
|
||||
/** Makes image pixel data available to caller, possibly asynchronously. It can also rescale
|
||||
the image pixels.
|
||||
|
||||
Currently asynchronous reads are only supported on the GPU backend and only when the
|
||||
underlying 3D API supports transfer buffers and CPU/GPU synchronization primitives. In all
|
||||
other cases this operates synchronously.
|
||||
|
||||
Data is read from the source sub-rectangle, is optionally converted to a linear gamma, is
|
||||
rescaled to the size indicated by 'info', is then converted to the color space, color type,
|
||||
and alpha type of 'info'. A 'srcRect' that is not contained by the bounds of the image
|
||||
causes failure.
|
||||
|
||||
When the pixel data is ready the caller's ReadPixelsCallback is called with a
|
||||
AsyncReadResult containing pixel data in the requested color type, alpha type, and color
|
||||
space. The AsyncReadResult will have count() == 1. Upon failure the callback is called with
|
||||
nullptr for AsyncReadResult. For a GPU image this flushes work but a submit must occur to
|
||||
guarantee a finite time before the callback is called.
|
||||
|
||||
The data is valid for the lifetime of AsyncReadResult with the exception that if the SkImage
|
||||
is GPU-backed the data is immediately invalidated if the GrContext is abandoned or
|
||||
destroyed.
|
||||
|
||||
@param info info of the requested pixels
|
||||
@param srcRect subrectangle of image to read
|
||||
@param rescaleGamma controls whether rescaling is done in the image's gamma or whether
|
||||
the source data is transformed to a linear gamma before rescaling.
|
||||
@param rescaleQuality controls the quality (and cost) of the rescaling
|
||||
@param callback function to call with result of the read
|
||||
@param context passed to callback
|
||||
*/
|
||||
void asyncRescaleAndReadPixels(const SkImageInfo& info,
|
||||
const SkIRect& srcRect,
|
||||
RescaleGamma rescaleGamma,
|
||||
SkFilterQuality rescaleQuality,
|
||||
ReadPixelsCallback callback,
|
||||
ReadPixelsContext context);
|
||||
|
||||
/**
|
||||
Similar to asyncRescaleAndReadPixels but performs an additional conversion to YUV. The
|
||||
RGB->YUV conversion is controlled by 'yuvColorSpace'. The YUV data is returned as three
|
||||
planes ordered y, u, v. The u and v planes are half the width and height of the resized
|
||||
rectangle. The y, u, and v values are single bytes. Currently this fails if 'dstSize'
|
||||
width and height are not even. A 'srcRect' that is not contained by the bounds of the
|
||||
image causes failure.
|
||||
|
||||
When the pixel data is ready the caller's ReadPixelsCallback is called with a
|
||||
AsyncReadResult containing the planar data. The AsyncReadResult will have count() == 3.
|
||||
Upon failure the callback is called with nullptr for AsyncReadResult. For a GPU image this
|
||||
flushes work but a submit must occur to guarantee a finite time before the callback is
|
||||
called.
|
||||
|
||||
The data is valid for the lifetime of AsyncReadResult with the exception that if the SkImage
|
||||
is GPU-backed the data is immediately invalidated if the GrContext is abandoned or
|
||||
destroyed.
|
||||
|
||||
@param yuvColorSpace The transformation from RGB to YUV. Applied to the resized image
|
||||
after it is converted to dstColorSpace.
|
||||
@param dstColorSpace The color space to convert the resized image to, after rescaling.
|
||||
@param srcRect The portion of the image to rescale and convert to YUV planes.
|
||||
@param dstSize The size to rescale srcRect to
|
||||
@param rescaleGamma controls whether rescaling is done in the image's gamma or whether
|
||||
the source data is transformed to a linear gamma before rescaling.
|
||||
@param rescaleQuality controls the quality (and cost) of the rescaling
|
||||
@param callback function to call with the planar read result
|
||||
@param context passed to callback
|
||||
*/
|
||||
void asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,
|
||||
sk_sp<SkColorSpace> dstColorSpace,
|
||||
const SkIRect& srcRect,
|
||||
const SkISize& dstSize,
|
||||
RescaleGamma rescaleGamma,
|
||||
SkFilterQuality rescaleQuality,
|
||||
ReadPixelsCallback callback,
|
||||
ReadPixelsContext context);
|
||||
|
||||
/** Copies SkImage to dst, scaling pixels to fit dst.width() and dst.height(), and
|
||||
converting pixels to match dst.colorType() and dst.alphaType(). Returns true if
|
||||
pixels are copied. Returns false if dst.addr() is nullptr, or dst.rowBytes() is
|
||||
|
@ -769,22 +769,7 @@ public:
|
||||
*/
|
||||
bool readPixels(const SkBitmap& dst, int srcX, int srcY);
|
||||
|
||||
/** The result from asyncRescaleAndReadPixels() or asyncRescaleAndReadPixelsYUV420(). */
|
||||
class AsyncReadResult {
|
||||
public:
|
||||
AsyncReadResult(const AsyncReadResult&) = delete;
|
||||
AsyncReadResult(AsyncReadResult&&) = delete;
|
||||
AsyncReadResult& operator=(const AsyncReadResult&) = delete;
|
||||
AsyncReadResult& operator=(AsyncReadResult&&) = delete;
|
||||
|
||||
virtual ~AsyncReadResult() = default;
|
||||
virtual int count() const = 0;
|
||||
virtual const void* data(int i) const = 0;
|
||||
virtual size_t rowBytes(int i) const = 0;
|
||||
|
||||
protected:
|
||||
AsyncReadResult() = default;
|
||||
};
|
||||
using AsyncReadResult = SkImage::AsyncReadResult;
|
||||
|
||||
/** Client-provided context that is passed to client-provided ReadPixelsContext. */
|
||||
using ReadPixelsContext = void*;
|
||||
@ -797,7 +782,7 @@ public:
|
||||
/** Controls the gamma that rescaling occurs in for asyncRescaleAndReadPixels() and
|
||||
asyncRescaleAndReadPixelsYUV420().
|
||||
*/
|
||||
enum RescaleGamma : bool { kSrc, kLinear };
|
||||
using RescaleGamma = SkImage::RescaleGamma;
|
||||
|
||||
/** Makes surface pixel data available to caller, possibly asynchronously. It can also rescale
|
||||
the surface pixels.
|
||||
@ -829,9 +814,12 @@ public:
|
||||
@param callback function to call with result of the read
|
||||
@param context passed to callback
|
||||
*/
|
||||
void asyncRescaleAndReadPixels(const SkImageInfo& info, const SkIRect& srcRect,
|
||||
RescaleGamma rescaleGamma, SkFilterQuality rescaleQuality,
|
||||
ReadPixelsCallback callback, ReadPixelsContext context);
|
||||
void asyncRescaleAndReadPixels(const SkImageInfo& info,
|
||||
const SkIRect& srcRect,
|
||||
RescaleGamma rescaleGamma,
|
||||
SkFilterQuality rescaleQuality,
|
||||
ReadPixelsCallback callback,
|
||||
ReadPixelsContext context);
|
||||
|
||||
/**
|
||||
Similar to asyncRescaleAndReadPixels but performs an additional conversion to YUV. The
|
||||
@ -869,7 +857,7 @@ public:
|
||||
RescaleGamma rescaleGamma,
|
||||
SkFilterQuality rescaleQuality,
|
||||
ReadPixelsCallback callback,
|
||||
ReadPixelsContext);
|
||||
ReadPixelsContext context);
|
||||
|
||||
/** Copies SkRect of pixels from the src SkPixmap to the SkSurface.
|
||||
|
||||
|
@ -956,7 +956,7 @@ func (b *taskBuilder) dmFlags(internalHardwareLabel string) {
|
||||
match = append(match, "~WritePixelsNonTextureMSAA_Gpu")
|
||||
}
|
||||
|
||||
if b.extraConfig("Direct3D") {
|
||||
if b.extraConfig("Direct3D") {
|
||||
// skia:9935
|
||||
match = append(match, "~^ColorTypeBackendAllocationTest$")
|
||||
match = append(match, "~^CompressedBackendAllocationTest$")
|
||||
@ -971,10 +971,13 @@ func (b *taskBuilder) dmFlags(internalHardwareLabel string) {
|
||||
match = append(match, "~^TextureIdleStateTest$")
|
||||
match = append(match, "~^TextureProxyTest$")
|
||||
}
|
||||
|
||||
if b.extraConfig("Direct3D") && b.gpu("RadeonHD7770") && b.matchOs("Win") {
|
||||
if b.extraConfig("Direct3D") && b.matchOs("Win") {
|
||||
// skia:9935
|
||||
match = append(match, "~^AsyncReadPixels$")
|
||||
match = append(match, "~^ImageAsyncReadPixels$")
|
||||
}
|
||||
if b.extraConfig("Direct3D") && b.gpu("RadeonHD7770") && b.matchOs("Win") {
|
||||
// skia:9935
|
||||
match = append(match, "~^SurfaceAsyncReadPixels$")
|
||||
match = append(match, "~^MorphologyFilterRadiusWithMirrorCTM_Gpu$")
|
||||
match = append(match, "~^ReadPixels_Gpu$")
|
||||
match = append(match, "~^ReadPixels_Texture$")
|
||||
|
@ -49064,7 +49064,7 @@
|
||||
"skia/infra/bots/run_recipe.py",
|
||||
"${ISOLATED_OUTDIR}",
|
||||
"test",
|
||||
"{\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"buildbucket_build_id\":\"<(BUILDBUCKET_BUILD_ID)\",\"buildername\":\"Test-Win10-Clang-ShuttleA-GPU-RadeonHD7770-x86_64-Debug-All-Direct3D\",\"dm_flags\":\"[\\\"dm\\\",\\\"--nameByHash\\\",\\\"--key\\\",\\\"arch\\\",\\\"x86_64\\\",\\\"compiler\\\",\\\"Clang\\\",\\\"configuration\\\",\\\"Debug\\\",\\\"cpu_or_gpu\\\",\\\"GPU\\\",\\\"cpu_or_gpu_value\\\",\\\"RadeonHD7770\\\",\\\"extra_config\\\",\\\"Direct3D\\\",\\\"model\\\",\\\"ShuttleA\\\",\\\"os\\\",\\\"Win10\\\",\\\"style\\\",\\\"default\\\",\\\"--randomProcessorTest\\\",\\\"--nocpu\\\",\\\"--config\\\",\\\"d3d\\\",\\\"--src\\\",\\\"tests\\\",\\\"gm\\\",\\\"image\\\",\\\"colorImage\\\",\\\"svg\\\",\\\"--blacklist\\\",\\\"_\\\",\\\"svg\\\",\\\"_\\\",\\\"svgparse_\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"pal8os2v2.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"pal8os2v2-16.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"rgba32abf.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"rgb24prof.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"rgb24lprof.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"8bpp-pixeldata-cropped.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"4bpp-pixeldata-cropped.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"32bpp-pixeldata-cropped.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"24bpp-pixeldata-cropped.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"testimgari.jpg\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"rle8-height-negative.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"rle4-height-negative.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"error\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\"interlaced1.png\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\"interlaced2.png\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\"interlaced3.png\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".arw\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".cr2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".dng\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".nef\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".nrw\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".orf\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".raf\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".rw2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".pef\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".srw\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".ARW\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".CR2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".DNG\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".NEF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".NRW\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".ORF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".RAF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".RW2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".PEF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".SRW\\\",\\\"--match\\\",\\\"~^ColorTypeBackendAllocationTest$\\\",\\\"~^CompressedBackendAllocationTest$\\\",\\\"~^DDLSkSurfaceFlush$\\\",\\\"~^GrBackendTextureImageMipMappedTest$\\\",\\\"~^GrMeshTest$\\\",\\\"~^GrSurfaceRenderability$\\\",\\\"~^GrTextureMipMapInvalidationTest$\\\",\\\"~^PremulAlphaRoundTrip_Gpu$\\\",\\\"~^ReplaceSurfaceBackendTexture$\\\",\\\"~^SkImage_makeTextureImage$\\\",\\\"~^TextureIdleStateTest$\\\",\\\"~^TextureProxyTest$\\\",\\\"~^AsyncReadPixels$\\\",\\\"~^MorphologyFilterRadiusWithMirrorCTM_Gpu$\\\",\\\"~^ReadPixels_Gpu$\\\",\\\"~^ReadPixels_Texture$\\\",\\\"--nonativeFonts\\\",\\\"--verbose\\\"]\",\"dm_properties\":\"{\\\"buildbucket_build_id\\\":\\\"<(BUILDBUCKET_BUILD_ID)\\\",\\\"builder\\\":\\\"Test-Win10-Clang-ShuttleA-GPU-RadeonHD7770-x86_64-Debug-All-Direct3D\\\",\\\"gitHash\\\":\\\"<(REVISION)\\\",\\\"issue\\\":\\\"<(ISSUE)\\\",\\\"patch_storage\\\":\\\"<(PATCH_STORAGE)\\\",\\\"patchset\\\":\\\"<(PATCHSET)\\\",\\\"swarming_bot_id\\\":\\\"${SWARMING_BOT_ID}\\\",\\\"swarming_task_id\\\":\\\"${SWARMING_TASK_ID}\\\",\\\"task_id\\\":\\\"<(TASK_ID)\\\"}\",\"do_upload\":\"true\",\"gold_hashes_url\":\"https://storage.googleapis.com/skia-infra-gm/hash_files/gold-prod-hashes.txt\",\"images\":\"true\",\"patch_issue\":\"<(ISSUE_INT)\",\"patch_ref\":\"<(PATCH_REF)\",\"patch_repo\":\"<(PATCH_REPO)\",\"patch_set\":\"<(PATCHSET_INT)\",\"patch_storage\":\"<(PATCH_STORAGE)\",\"repository\":\"<(REPO)\",\"resources\":\"true\",\"revision\":\"<(REVISION)\",\"skps\":\"true\",\"svgs\":\"true\",\"swarm_out_dir\":\"test\",\"task_id\":\"<(TASK_ID)\"}",
|
||||
"{\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"buildbucket_build_id\":\"<(BUILDBUCKET_BUILD_ID)\",\"buildername\":\"Test-Win10-Clang-ShuttleA-GPU-RadeonHD7770-x86_64-Debug-All-Direct3D\",\"dm_flags\":\"[\\\"dm\\\",\\\"--nameByHash\\\",\\\"--key\\\",\\\"arch\\\",\\\"x86_64\\\",\\\"compiler\\\",\\\"Clang\\\",\\\"configuration\\\",\\\"Debug\\\",\\\"cpu_or_gpu\\\",\\\"GPU\\\",\\\"cpu_or_gpu_value\\\",\\\"RadeonHD7770\\\",\\\"extra_config\\\",\\\"Direct3D\\\",\\\"model\\\",\\\"ShuttleA\\\",\\\"os\\\",\\\"Win10\\\",\\\"style\\\",\\\"default\\\",\\\"--randomProcessorTest\\\",\\\"--nocpu\\\",\\\"--config\\\",\\\"d3d\\\",\\\"--src\\\",\\\"tests\\\",\\\"gm\\\",\\\"image\\\",\\\"colorImage\\\",\\\"svg\\\",\\\"--blacklist\\\",\\\"_\\\",\\\"svg\\\",\\\"_\\\",\\\"svgparse_\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"pal8os2v2.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"pal8os2v2-16.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"rgba32abf.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"rgb24prof.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"rgb24lprof.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"8bpp-pixeldata-cropped.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"4bpp-pixeldata-cropped.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"32bpp-pixeldata-cropped.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"24bpp-pixeldata-cropped.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"testimgari.jpg\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"rle8-height-negative.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"rle4-height-negative.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"error\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\"interlaced1.png\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\"interlaced2.png\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\"interlaced3.png\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".arw\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".cr2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".dng\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".nef\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".nrw\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".orf\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".raf\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".rw2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".pef\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".srw\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".ARW\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".CR2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".DNG\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".NEF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".NRW\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".ORF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".RAF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".RW2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".PEF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".SRW\\\",\\\"--match\\\",\\\"~^ColorTypeBackendAllocationTest$\\\",\\\"~^CompressedBackendAllocationTest$\\\",\\\"~^DDLSkSurfaceFlush$\\\",\\\"~^GrBackendTextureImageMipMappedTest$\\\",\\\"~^GrMeshTest$\\\",\\\"~^GrSurfaceRenderability$\\\",\\\"~^GrTextureMipMapInvalidationTest$\\\",\\\"~^PremulAlphaRoundTrip_Gpu$\\\",\\\"~^ReplaceSurfaceBackendTexture$\\\",\\\"~^SkImage_makeTextureImage$\\\",\\\"~^TextureIdleStateTest$\\\",\\\"~^TextureProxyTest$\\\",\\\"~^ImageAsyncReadPixels$\\\",\\\"~^SurfaceAsyncReadPixels$\\\",\\\"~^MorphologyFilterRadiusWithMirrorCTM_Gpu$\\\",\\\"~^ReadPixels_Gpu$\\\",\\\"~^ReadPixels_Texture$\\\",\\\"--nonativeFonts\\\",\\\"--verbose\\\"]\",\"dm_properties\":\"{\\\"buildbucket_build_id\\\":\\\"<(BUILDBUCKET_BUILD_ID)\\\",\\\"builder\\\":\\\"Test-Win10-Clang-ShuttleA-GPU-RadeonHD7770-x86_64-Debug-All-Direct3D\\\",\\\"gitHash\\\":\\\"<(REVISION)\\\",\\\"issue\\\":\\\"<(ISSUE)\\\",\\\"patch_storage\\\":\\\"<(PATCH_STORAGE)\\\",\\\"patchset\\\":\\\"<(PATCHSET)\\\",\\\"swarming_bot_id\\\":\\\"${SWARMING_BOT_ID}\\\",\\\"swarming_task_id\\\":\\\"${SWARMING_TASK_ID}\\\",\\\"task_id\\\":\\\"<(TASK_ID)\\\"}\",\"do_upload\":\"true\",\"gold_hashes_url\":\"https://storage.googleapis.com/skia-infra-gm/hash_files/gold-prod-hashes.txt\",\"images\":\"true\",\"patch_issue\":\"<(ISSUE_INT)\",\"patch_ref\":\"<(PATCH_REF)\",\"patch_repo\":\"<(PATCH_REPO)\",\"patch_set\":\"<(PATCHSET_INT)\",\"patch_storage\":\"<(PATCH_STORAGE)\",\"repository\":\"<(REPO)\",\"resources\":\"true\",\"revision\":\"<(REVISION)\",\"skps\":\"true\",\"svgs\":\"true\",\"swarm_out_dir\":\"test\",\"task_id\":\"<(TASK_ID)\"}",
|
||||
"skia"
|
||||
],
|
||||
"dependencies": [
|
||||
@ -49396,7 +49396,7 @@
|
||||
"skia/infra/bots/run_recipe.py",
|
||||
"${ISOLATED_OUTDIR}",
|
||||
"test",
|
||||
"{\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"buildbucket_build_id\":\"<(BUILDBUCKET_BUILD_ID)\",\"buildername\":\"Test-Win10-Clang-ShuttleA-GPU-RadeonHD7770-x86_64-Release-All-Direct3D\",\"dm_flags\":\"[\\\"dm\\\",\\\"--nameByHash\\\",\\\"--key\\\",\\\"arch\\\",\\\"x86_64\\\",\\\"compiler\\\",\\\"Clang\\\",\\\"configuration\\\",\\\"Release\\\",\\\"cpu_or_gpu\\\",\\\"GPU\\\",\\\"cpu_or_gpu_value\\\",\\\"RadeonHD7770\\\",\\\"extra_config\\\",\\\"Direct3D\\\",\\\"model\\\",\\\"ShuttleA\\\",\\\"os\\\",\\\"Win10\\\",\\\"style\\\",\\\"default\\\",\\\"--randomProcessorTest\\\",\\\"--nocpu\\\",\\\"--config\\\",\\\"d3d\\\",\\\"--src\\\",\\\"tests\\\",\\\"gm\\\",\\\"image\\\",\\\"colorImage\\\",\\\"svg\\\",\\\"--blacklist\\\",\\\"_\\\",\\\"svg\\\",\\\"_\\\",\\\"svgparse_\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"pal8os2v2.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"pal8os2v2-16.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"rgba32abf.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"rgb24prof.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"rgb24lprof.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"8bpp-pixeldata-cropped.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"4bpp-pixeldata-cropped.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"32bpp-pixeldata-cropped.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"24bpp-pixeldata-cropped.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"testimgari.jpg\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"rle8-height-negative.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"rle4-height-negative.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"error\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\"interlaced1.png\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\"interlaced2.png\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\"interlaced3.png\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".arw\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".cr2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".dng\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".nef\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".nrw\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".orf\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".raf\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".rw2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".pef\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".srw\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".ARW\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".CR2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".DNG\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".NEF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".NRW\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".ORF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".RAF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".RW2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".PEF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".SRW\\\",\\\"--match\\\",\\\"~^ColorTypeBackendAllocationTest$\\\",\\\"~^CompressedBackendAllocationTest$\\\",\\\"~^DDLSkSurfaceFlush$\\\",\\\"~^GrBackendTextureImageMipMappedTest$\\\",\\\"~^GrMeshTest$\\\",\\\"~^GrSurfaceRenderability$\\\",\\\"~^GrTextureMipMapInvalidationTest$\\\",\\\"~^PremulAlphaRoundTrip_Gpu$\\\",\\\"~^ReplaceSurfaceBackendTexture$\\\",\\\"~^SkImage_makeTextureImage$\\\",\\\"~^TextureIdleStateTest$\\\",\\\"~^TextureProxyTest$\\\",\\\"~^AsyncReadPixels$\\\",\\\"~^MorphologyFilterRadiusWithMirrorCTM_Gpu$\\\",\\\"~^ReadPixels_Gpu$\\\",\\\"~^ReadPixels_Texture$\\\",\\\"--nonativeFonts\\\",\\\"--verbose\\\"]\",\"dm_properties\":\"{\\\"buildbucket_build_id\\\":\\\"<(BUILDBUCKET_BUILD_ID)\\\",\\\"builder\\\":\\\"Test-Win10-Clang-ShuttleA-GPU-RadeonHD7770-x86_64-Release-All-Direct3D\\\",\\\"gitHash\\\":\\\"<(REVISION)\\\",\\\"issue\\\":\\\"<(ISSUE)\\\",\\\"patch_storage\\\":\\\"<(PATCH_STORAGE)\\\",\\\"patchset\\\":\\\"<(PATCHSET)\\\",\\\"swarming_bot_id\\\":\\\"${SWARMING_BOT_ID}\\\",\\\"swarming_task_id\\\":\\\"${SWARMING_TASK_ID}\\\",\\\"task_id\\\":\\\"<(TASK_ID)\\\"}\",\"do_upload\":\"true\",\"gold_hashes_url\":\"https://storage.googleapis.com/skia-infra-gm/hash_files/gold-prod-hashes.txt\",\"images\":\"true\",\"patch_issue\":\"<(ISSUE_INT)\",\"patch_ref\":\"<(PATCH_REF)\",\"patch_repo\":\"<(PATCH_REPO)\",\"patch_set\":\"<(PATCHSET_INT)\",\"patch_storage\":\"<(PATCH_STORAGE)\",\"repository\":\"<(REPO)\",\"resources\":\"true\",\"revision\":\"<(REVISION)\",\"skps\":\"true\",\"svgs\":\"true\",\"swarm_out_dir\":\"test\",\"task_id\":\"<(TASK_ID)\"}",
|
||||
"{\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"buildbucket_build_id\":\"<(BUILDBUCKET_BUILD_ID)\",\"buildername\":\"Test-Win10-Clang-ShuttleA-GPU-RadeonHD7770-x86_64-Release-All-Direct3D\",\"dm_flags\":\"[\\\"dm\\\",\\\"--nameByHash\\\",\\\"--key\\\",\\\"arch\\\",\\\"x86_64\\\",\\\"compiler\\\",\\\"Clang\\\",\\\"configuration\\\",\\\"Release\\\",\\\"cpu_or_gpu\\\",\\\"GPU\\\",\\\"cpu_or_gpu_value\\\",\\\"RadeonHD7770\\\",\\\"extra_config\\\",\\\"Direct3D\\\",\\\"model\\\",\\\"ShuttleA\\\",\\\"os\\\",\\\"Win10\\\",\\\"style\\\",\\\"default\\\",\\\"--randomProcessorTest\\\",\\\"--nocpu\\\",\\\"--config\\\",\\\"d3d\\\",\\\"--src\\\",\\\"tests\\\",\\\"gm\\\",\\\"image\\\",\\\"colorImage\\\",\\\"svg\\\",\\\"--blacklist\\\",\\\"_\\\",\\\"svg\\\",\\\"_\\\",\\\"svgparse_\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"pal8os2v2.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"pal8os2v2-16.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"rgba32abf.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"rgb24prof.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"rgb24lprof.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"8bpp-pixeldata-cropped.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"4bpp-pixeldata-cropped.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"32bpp-pixeldata-cropped.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"24bpp-pixeldata-cropped.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"testimgari.jpg\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"rle8-height-negative.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"rle4-height-negative.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"error\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\"interlaced1.png\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\"interlaced2.png\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\"interlaced3.png\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".arw\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".cr2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".dng\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".nef\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".nrw\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".orf\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".raf\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".rw2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".pef\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".srw\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".ARW\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".CR2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".DNG\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".NEF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".NRW\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".ORF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".RAF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".RW2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".PEF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".SRW\\\",\\\"--match\\\",\\\"~^ColorTypeBackendAllocationTest$\\\",\\\"~^CompressedBackendAllocationTest$\\\",\\\"~^DDLSkSurfaceFlush$\\\",\\\"~^GrBackendTextureImageMipMappedTest$\\\",\\\"~^GrMeshTest$\\\",\\\"~^GrSurfaceRenderability$\\\",\\\"~^GrTextureMipMapInvalidationTest$\\\",\\\"~^PremulAlphaRoundTrip_Gpu$\\\",\\\"~^ReplaceSurfaceBackendTexture$\\\",\\\"~^SkImage_makeTextureImage$\\\",\\\"~^TextureIdleStateTest$\\\",\\\"~^TextureProxyTest$\\\",\\\"~^ImageAsyncReadPixels$\\\",\\\"~^SurfaceAsyncReadPixels$\\\",\\\"~^MorphologyFilterRadiusWithMirrorCTM_Gpu$\\\",\\\"~^ReadPixels_Gpu$\\\",\\\"~^ReadPixels_Texture$\\\",\\\"--nonativeFonts\\\",\\\"--verbose\\\"]\",\"dm_properties\":\"{\\\"buildbucket_build_id\\\":\\\"<(BUILDBUCKET_BUILD_ID)\\\",\\\"builder\\\":\\\"Test-Win10-Clang-ShuttleA-GPU-RadeonHD7770-x86_64-Release-All-Direct3D\\\",\\\"gitHash\\\":\\\"<(REVISION)\\\",\\\"issue\\\":\\\"<(ISSUE)\\\",\\\"patch_storage\\\":\\\"<(PATCH_STORAGE)\\\",\\\"patchset\\\":\\\"<(PATCHSET)\\\",\\\"swarming_bot_id\\\":\\\"${SWARMING_BOT_ID}\\\",\\\"swarming_task_id\\\":\\\"${SWARMING_TASK_ID}\\\",\\\"task_id\\\":\\\"<(TASK_ID)\\\"}\",\"do_upload\":\"true\",\"gold_hashes_url\":\"https://storage.googleapis.com/skia-infra-gm/hash_files/gold-prod-hashes.txt\",\"images\":\"true\",\"patch_issue\":\"<(ISSUE_INT)\",\"patch_ref\":\"<(PATCH_REF)\",\"patch_repo\":\"<(PATCH_REPO)\",\"patch_set\":\"<(PATCHSET_INT)\",\"patch_storage\":\"<(PATCH_STORAGE)\",\"repository\":\"<(REPO)\",\"resources\":\"true\",\"revision\":\"<(REVISION)\",\"skps\":\"true\",\"svgs\":\"true\",\"swarm_out_dir\":\"test\",\"task_id\":\"<(TASK_ID)\"}",
|
||||
"skia"
|
||||
],
|
||||
"dependencies": [
|
||||
@ -50143,7 +50143,7 @@
|
||||
"skia/infra/bots/run_recipe.py",
|
||||
"${ISOLATED_OUTDIR}",
|
||||
"test",
|
||||
"{\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"buildbucket_build_id\":\"<(BUILDBUCKET_BUILD_ID)\",\"buildername\":\"Test-Win10-MSVC-Golo-GPU-QuadroP400-x86_64-Debug-All-Direct3D\",\"dm_flags\":\"[\\\"dm\\\",\\\"--nameByHash\\\",\\\"--key\\\",\\\"arch\\\",\\\"x86_64\\\",\\\"compiler\\\",\\\"MSVC\\\",\\\"configuration\\\",\\\"Debug\\\",\\\"cpu_or_gpu\\\",\\\"GPU\\\",\\\"cpu_or_gpu_value\\\",\\\"QuadroP400\\\",\\\"extra_config\\\",\\\"Direct3D\\\",\\\"model\\\",\\\"Golo\\\",\\\"os\\\",\\\"Win10\\\",\\\"style\\\",\\\"default\\\",\\\"--randomProcessorTest\\\",\\\"--nocpu\\\",\\\"--config\\\",\\\"d3d\\\",\\\"--src\\\",\\\"tests\\\",\\\"gm\\\",\\\"image\\\",\\\"colorImage\\\",\\\"svg\\\",\\\"--blacklist\\\",\\\"_\\\",\\\"svg\\\",\\\"_\\\",\\\"svgparse_\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"pal8os2v2.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"pal8os2v2-16.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"rgba32abf.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"rgb24prof.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"rgb24lprof.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"8bpp-pixeldata-cropped.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"4bpp-pixeldata-cropped.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"32bpp-pixeldata-cropped.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"24bpp-pixeldata-cropped.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"testimgari.jpg\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"rle8-height-negative.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"rle4-height-negative.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"error\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\"interlaced1.png\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\"interlaced2.png\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\"interlaced3.png\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".arw\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".cr2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".dng\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".nef\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".nrw\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".orf\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".raf\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".rw2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".pef\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".srw\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".ARW\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".CR2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".DNG\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".NEF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".NRW\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".ORF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".RAF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".RW2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".PEF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".SRW\\\",\\\"--match\\\",\\\"~^ColorTypeBackendAllocationTest$\\\",\\\"~^CompressedBackendAllocationTest$\\\",\\\"~^DDLSkSurfaceFlush$\\\",\\\"~^GrBackendTextureImageMipMappedTest$\\\",\\\"~^GrMeshTest$\\\",\\\"~^GrSurfaceRenderability$\\\",\\\"~^GrTextureMipMapInvalidationTest$\\\",\\\"~^PremulAlphaRoundTrip_Gpu$\\\",\\\"~^ReplaceSurfaceBackendTexture$\\\",\\\"~^SkImage_makeTextureImage$\\\",\\\"~^TextureIdleStateTest$\\\",\\\"~^TextureProxyTest$\\\",\\\"--nonativeFonts\\\",\\\"--verbose\\\"]\",\"dm_properties\":\"{\\\"buildbucket_build_id\\\":\\\"<(BUILDBUCKET_BUILD_ID)\\\",\\\"builder\\\":\\\"Test-Win10-MSVC-Golo-GPU-QuadroP400-x86_64-Debug-All-Direct3D\\\",\\\"gitHash\\\":\\\"<(REVISION)\\\",\\\"issue\\\":\\\"<(ISSUE)\\\",\\\"patch_storage\\\":\\\"<(PATCH_STORAGE)\\\",\\\"patchset\\\":\\\"<(PATCHSET)\\\",\\\"swarming_bot_id\\\":\\\"${SWARMING_BOT_ID}\\\",\\\"swarming_task_id\\\":\\\"${SWARMING_TASK_ID}\\\",\\\"task_id\\\":\\\"<(TASK_ID)\\\"}\",\"do_upload\":\"true\",\"gold_hashes_url\":\"https://storage.googleapis.com/skia-infra-gm/hash_files/gold-prod-hashes.txt\",\"images\":\"true\",\"patch_issue\":\"<(ISSUE_INT)\",\"patch_ref\":\"<(PATCH_REF)\",\"patch_repo\":\"<(PATCH_REPO)\",\"patch_set\":\"<(PATCHSET_INT)\",\"patch_storage\":\"<(PATCH_STORAGE)\",\"repository\":\"<(REPO)\",\"resources\":\"true\",\"revision\":\"<(REVISION)\",\"skps\":\"true\",\"svgs\":\"true\",\"swarm_out_dir\":\"test\",\"task_id\":\"<(TASK_ID)\"}",
|
||||
"{\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"buildbucket_build_id\":\"<(BUILDBUCKET_BUILD_ID)\",\"buildername\":\"Test-Win10-MSVC-Golo-GPU-QuadroP400-x86_64-Debug-All-Direct3D\",\"dm_flags\":\"[\\\"dm\\\",\\\"--nameByHash\\\",\\\"--key\\\",\\\"arch\\\",\\\"x86_64\\\",\\\"compiler\\\",\\\"MSVC\\\",\\\"configuration\\\",\\\"Debug\\\",\\\"cpu_or_gpu\\\",\\\"GPU\\\",\\\"cpu_or_gpu_value\\\",\\\"QuadroP400\\\",\\\"extra_config\\\",\\\"Direct3D\\\",\\\"model\\\",\\\"Golo\\\",\\\"os\\\",\\\"Win10\\\",\\\"style\\\",\\\"default\\\",\\\"--randomProcessorTest\\\",\\\"--nocpu\\\",\\\"--config\\\",\\\"d3d\\\",\\\"--src\\\",\\\"tests\\\",\\\"gm\\\",\\\"image\\\",\\\"colorImage\\\",\\\"svg\\\",\\\"--blacklist\\\",\\\"_\\\",\\\"svg\\\",\\\"_\\\",\\\"svgparse_\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"pal8os2v2.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"pal8os2v2-16.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"rgba32abf.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"rgb24prof.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"rgb24lprof.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"8bpp-pixeldata-cropped.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"4bpp-pixeldata-cropped.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"32bpp-pixeldata-cropped.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"24bpp-pixeldata-cropped.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"testimgari.jpg\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"rle8-height-negative.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"rle4-height-negative.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"error\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\"interlaced1.png\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\"interlaced2.png\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\"interlaced3.png\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".arw\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".cr2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".dng\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".nef\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".nrw\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".orf\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".raf\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".rw2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".pef\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".srw\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".ARW\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".CR2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".DNG\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".NEF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".NRW\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".ORF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".RAF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".RW2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".PEF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".SRW\\\",\\\"--match\\\",\\\"~^ColorTypeBackendAllocationTest$\\\",\\\"~^CompressedBackendAllocationTest$\\\",\\\"~^DDLSkSurfaceFlush$\\\",\\\"~^GrBackendTextureImageMipMappedTest$\\\",\\\"~^GrMeshTest$\\\",\\\"~^GrSurfaceRenderability$\\\",\\\"~^GrTextureMipMapInvalidationTest$\\\",\\\"~^PremulAlphaRoundTrip_Gpu$\\\",\\\"~^ReplaceSurfaceBackendTexture$\\\",\\\"~^SkImage_makeTextureImage$\\\",\\\"~^TextureIdleStateTest$\\\",\\\"~^TextureProxyTest$\\\",\\\"~^ImageAsyncReadPixels$\\\",\\\"--nonativeFonts\\\",\\\"--verbose\\\"]\",\"dm_properties\":\"{\\\"buildbucket_build_id\\\":\\\"<(BUILDBUCKET_BUILD_ID)\\\",\\\"builder\\\":\\\"Test-Win10-MSVC-Golo-GPU-QuadroP400-x86_64-Debug-All-Direct3D\\\",\\\"gitHash\\\":\\\"<(REVISION)\\\",\\\"issue\\\":\\\"<(ISSUE)\\\",\\\"patch_storage\\\":\\\"<(PATCH_STORAGE)\\\",\\\"patchset\\\":\\\"<(PATCHSET)\\\",\\\"swarming_bot_id\\\":\\\"${SWARMING_BOT_ID}\\\",\\\"swarming_task_id\\\":\\\"${SWARMING_TASK_ID}\\\",\\\"task_id\\\":\\\"<(TASK_ID)\\\"}\",\"do_upload\":\"true\",\"gold_hashes_url\":\"https://storage.googleapis.com/skia-infra-gm/hash_files/gold-prod-hashes.txt\",\"images\":\"true\",\"patch_issue\":\"<(ISSUE_INT)\",\"patch_ref\":\"<(PATCH_REF)\",\"patch_repo\":\"<(PATCH_REPO)\",\"patch_set\":\"<(PATCHSET_INT)\",\"patch_storage\":\"<(PATCH_STORAGE)\",\"repository\":\"<(REPO)\",\"resources\":\"true\",\"revision\":\"<(REVISION)\",\"skps\":\"true\",\"svgs\":\"true\",\"swarm_out_dir\":\"test\",\"task_id\":\"<(TASK_ID)\"}",
|
||||
"skia"
|
||||
],
|
||||
"dependencies": [
|
||||
@ -50392,7 +50392,7 @@
|
||||
"skia/infra/bots/run_recipe.py",
|
||||
"${ISOLATED_OUTDIR}",
|
||||
"test",
|
||||
"{\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"buildbucket_build_id\":\"<(BUILDBUCKET_BUILD_ID)\",\"buildername\":\"Test-Win10-MSVC-Golo-GPU-QuadroP400-x86_64-Release-All-Direct3D\",\"dm_flags\":\"[\\\"dm\\\",\\\"--nameByHash\\\",\\\"--key\\\",\\\"arch\\\",\\\"x86_64\\\",\\\"compiler\\\",\\\"MSVC\\\",\\\"configuration\\\",\\\"Release\\\",\\\"cpu_or_gpu\\\",\\\"GPU\\\",\\\"cpu_or_gpu_value\\\",\\\"QuadroP400\\\",\\\"extra_config\\\",\\\"Direct3D\\\",\\\"model\\\",\\\"Golo\\\",\\\"os\\\",\\\"Win10\\\",\\\"style\\\",\\\"default\\\",\\\"--randomProcessorTest\\\",\\\"--nocpu\\\",\\\"--config\\\",\\\"d3d\\\",\\\"--src\\\",\\\"tests\\\",\\\"gm\\\",\\\"image\\\",\\\"colorImage\\\",\\\"svg\\\",\\\"--blacklist\\\",\\\"_\\\",\\\"svg\\\",\\\"_\\\",\\\"svgparse_\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"pal8os2v2.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"pal8os2v2-16.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"rgba32abf.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"rgb24prof.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"rgb24lprof.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"8bpp-pixeldata-cropped.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"4bpp-pixeldata-cropped.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"32bpp-pixeldata-cropped.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"24bpp-pixeldata-cropped.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"testimgari.jpg\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"rle8-height-negative.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"rle4-height-negative.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"error\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\"interlaced1.png\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\"interlaced2.png\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\"interlaced3.png\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".arw\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".cr2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".dng\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".nef\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".nrw\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".orf\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".raf\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".rw2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".pef\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".srw\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".ARW\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".CR2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".DNG\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".NEF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".NRW\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".ORF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".RAF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".RW2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".PEF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".SRW\\\",\\\"--match\\\",\\\"~^ColorTypeBackendAllocationTest$\\\",\\\"~^CompressedBackendAllocationTest$\\\",\\\"~^DDLSkSurfaceFlush$\\\",\\\"~^GrBackendTextureImageMipMappedTest$\\\",\\\"~^GrMeshTest$\\\",\\\"~^GrSurfaceRenderability$\\\",\\\"~^GrTextureMipMapInvalidationTest$\\\",\\\"~^PremulAlphaRoundTrip_Gpu$\\\",\\\"~^ReplaceSurfaceBackendTexture$\\\",\\\"~^SkImage_makeTextureImage$\\\",\\\"~^TextureIdleStateTest$\\\",\\\"~^TextureProxyTest$\\\",\\\"--nonativeFonts\\\",\\\"--verbose\\\"]\",\"dm_properties\":\"{\\\"buildbucket_build_id\\\":\\\"<(BUILDBUCKET_BUILD_ID)\\\",\\\"builder\\\":\\\"Test-Win10-MSVC-Golo-GPU-QuadroP400-x86_64-Release-All-Direct3D\\\",\\\"gitHash\\\":\\\"<(REVISION)\\\",\\\"issue\\\":\\\"<(ISSUE)\\\",\\\"patch_storage\\\":\\\"<(PATCH_STORAGE)\\\",\\\"patchset\\\":\\\"<(PATCHSET)\\\",\\\"swarming_bot_id\\\":\\\"${SWARMING_BOT_ID}\\\",\\\"swarming_task_id\\\":\\\"${SWARMING_TASK_ID}\\\",\\\"task_id\\\":\\\"<(TASK_ID)\\\"}\",\"do_upload\":\"true\",\"gold_hashes_url\":\"https://storage.googleapis.com/skia-infra-gm/hash_files/gold-prod-hashes.txt\",\"images\":\"true\",\"patch_issue\":\"<(ISSUE_INT)\",\"patch_ref\":\"<(PATCH_REF)\",\"patch_repo\":\"<(PATCH_REPO)\",\"patch_set\":\"<(PATCHSET_INT)\",\"patch_storage\":\"<(PATCH_STORAGE)\",\"repository\":\"<(REPO)\",\"resources\":\"true\",\"revision\":\"<(REVISION)\",\"skps\":\"true\",\"svgs\":\"true\",\"swarm_out_dir\":\"test\",\"task_id\":\"<(TASK_ID)\"}",
|
||||
"{\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"buildbucket_build_id\":\"<(BUILDBUCKET_BUILD_ID)\",\"buildername\":\"Test-Win10-MSVC-Golo-GPU-QuadroP400-x86_64-Release-All-Direct3D\",\"dm_flags\":\"[\\\"dm\\\",\\\"--nameByHash\\\",\\\"--key\\\",\\\"arch\\\",\\\"x86_64\\\",\\\"compiler\\\",\\\"MSVC\\\",\\\"configuration\\\",\\\"Release\\\",\\\"cpu_or_gpu\\\",\\\"GPU\\\",\\\"cpu_or_gpu_value\\\",\\\"QuadroP400\\\",\\\"extra_config\\\",\\\"Direct3D\\\",\\\"model\\\",\\\"Golo\\\",\\\"os\\\",\\\"Win10\\\",\\\"style\\\",\\\"default\\\",\\\"--randomProcessorTest\\\",\\\"--nocpu\\\",\\\"--config\\\",\\\"d3d\\\",\\\"--src\\\",\\\"tests\\\",\\\"gm\\\",\\\"image\\\",\\\"colorImage\\\",\\\"svg\\\",\\\"--blacklist\\\",\\\"_\\\",\\\"svg\\\",\\\"_\\\",\\\"svgparse_\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"pal8os2v2.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"pal8os2v2-16.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"rgba32abf.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"rgb24prof.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"rgb24lprof.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"8bpp-pixeldata-cropped.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"4bpp-pixeldata-cropped.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"32bpp-pixeldata-cropped.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"24bpp-pixeldata-cropped.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"testimgari.jpg\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"rle8-height-negative.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"rle4-height-negative.bmp\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"error\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\"interlaced1.png\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\"interlaced2.png\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\"interlaced3.png\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".arw\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".cr2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".dng\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".nef\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".nrw\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".orf\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".raf\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".rw2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".pef\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".srw\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".ARW\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".CR2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".DNG\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".NEF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".NRW\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".ORF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".RAF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".RW2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".PEF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".SRW\\\",\\\"--match\\\",\\\"~^ColorTypeBackendAllocationTest$\\\",\\\"~^CompressedBackendAllocationTest$\\\",\\\"~^DDLSkSurfaceFlush$\\\",\\\"~^GrBackendTextureImageMipMappedTest$\\\",\\\"~^GrMeshTest$\\\",\\\"~^GrSurfaceRenderability$\\\",\\\"~^GrTextureMipMapInvalidationTest$\\\",\\\"~^PremulAlphaRoundTrip_Gpu$\\\",\\\"~^ReplaceSurfaceBackendTexture$\\\",\\\"~^SkImage_makeTextureImage$\\\",\\\"~^TextureIdleStateTest$\\\",\\\"~^TextureProxyTest$\\\",\\\"~^ImageAsyncReadPixels$\\\",\\\"--nonativeFonts\\\",\\\"--verbose\\\"]\",\"dm_properties\":\"{\\\"buildbucket_build_id\\\":\\\"<(BUILDBUCKET_BUILD_ID)\\\",\\\"builder\\\":\\\"Test-Win10-MSVC-Golo-GPU-QuadroP400-x86_64-Release-All-Direct3D\\\",\\\"gitHash\\\":\\\"<(REVISION)\\\",\\\"issue\\\":\\\"<(ISSUE)\\\",\\\"patch_storage\\\":\\\"<(PATCH_STORAGE)\\\",\\\"patchset\\\":\\\"<(PATCHSET)\\\",\\\"swarming_bot_id\\\":\\\"${SWARMING_BOT_ID}\\\",\\\"swarming_task_id\\\":\\\"${SWARMING_TASK_ID}\\\",\\\"task_id\\\":\\\"<(TASK_ID)\\\"}\",\"do_upload\":\"true\",\"gold_hashes_url\":\"https://storage.googleapis.com/skia-infra-gm/hash_files/gold-prod-hashes.txt\",\"images\":\"true\",\"patch_issue\":\"<(ISSUE_INT)\",\"patch_ref\":\"<(PATCH_REF)\",\"patch_repo\":\"<(PATCH_REPO)\",\"patch_set\":\"<(PATCHSET_INT)\",\"patch_storage\":\"<(PATCH_STORAGE)\",\"repository\":\"<(REPO)\",\"resources\":\"true\",\"revision\":\"<(REVISION)\",\"skps\":\"true\",\"svgs\":\"true\",\"swarm_out_dir\":\"test\",\"task_id\":\"<(TASK_ID)\"}",
|
||||
"skia"
|
||||
],
|
||||
"dependencies": [
|
||||
|
@ -23,12 +23,10 @@
|
||||
#include "src/core/SkMatrixProvider.h"
|
||||
#include "src/core/SkRRectPriv.h"
|
||||
#include "src/core/SkSurfacePriv.h"
|
||||
#include "src/core/SkYUVMath.h"
|
||||
#include "src/gpu/GrAppliedClip.h"
|
||||
#include "src/gpu/GrAuditTrail.h"
|
||||
#include "src/gpu/GrBlurUtils.h"
|
||||
#include "src/gpu/GrCaps.h"
|
||||
#include "src/gpu/GrClientMappedBufferManager.h"
|
||||
#include "src/gpu/GrClip.h"
|
||||
#include "src/gpu/GrColor.h"
|
||||
#include "src/gpu/GrContextPriv.h"
|
||||
@ -50,7 +48,6 @@
|
||||
#include "src/gpu/SkGr.h"
|
||||
#include "src/gpu/effects/GrBicubicEffect.h"
|
||||
#include "src/gpu/effects/GrRRectEffect.h"
|
||||
#include "src/gpu/effects/generated/GrColorMatrixFragmentProcessor.h"
|
||||
#include "src/gpu/geometry/GrQuad.h"
|
||||
#include "src/gpu/geometry/GrQuadUtils.h"
|
||||
#include "src/gpu/geometry/GrStyledShape.h"
|
||||
@ -1716,526 +1713,6 @@ void GrRenderTargetContext::drawDrawable(std::unique_ptr<SkDrawable::GpuDrawHand
|
||||
this->addOp(std::move(op));
|
||||
}
|
||||
|
||||
void GrRenderTargetContext::asyncRescaleAndReadPixels(
|
||||
const SkImageInfo& info, const SkIRect& srcRect, SkSurface::RescaleGamma rescaleGamma,
|
||||
SkFilterQuality rescaleQuality, ReadPixelsCallback callback, ReadPixelsContext context) {
|
||||
auto direct = fContext->priv().asDirectContext();
|
||||
if (!direct) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
if (this->asRenderTargetProxy()->wrapsVkSecondaryCB()) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
if (this->asRenderTargetProxy()->framebufferOnly()) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
auto dstCT = SkColorTypeToGrColorType(info.colorType());
|
||||
if (dstCT == GrColorType::kUnknown) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
bool needsRescale = srcRect.width() != info.width() || srcRect.height() != info.height();
|
||||
auto colorTypeOfFinalContext = this->colorInfo().colorType();
|
||||
auto backendFormatOfFinalContext = this->asSurfaceProxy()->backendFormat();
|
||||
if (needsRescale) {
|
||||
colorTypeOfFinalContext = dstCT;
|
||||
backendFormatOfFinalContext = this->caps()->getDefaultBackendFormat(dstCT,
|
||||
GrRenderable::kYes);
|
||||
}
|
||||
auto readInfo = this->caps()->supportedReadPixelsColorType(colorTypeOfFinalContext,
|
||||
backendFormatOfFinalContext, dstCT);
|
||||
// Fail if we can't read from the source surface's color type.
|
||||
if (readInfo.fColorType == GrColorType::kUnknown) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
// Fail if read color type does not have all of dstCT's color channels and those missing color
|
||||
// channels are in the src.
|
||||
uint32_t dstChannels = GrColorTypeChannelFlags(dstCT);
|
||||
uint32_t legalReadChannels = GrColorTypeChannelFlags(readInfo.fColorType);
|
||||
uint32_t srcChannels = GrColorTypeChannelFlags(this->colorInfo().colorType());
|
||||
if ((~legalReadChannels & dstChannels) & srcChannels) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_ptr<GrRenderTargetContext> tempRTC;
|
||||
int x = srcRect.fLeft;
|
||||
int y = srcRect.fTop;
|
||||
if (needsRescale) {
|
||||
tempRTC = this->rescale(info, kTopLeft_GrSurfaceOrigin, srcRect, rescaleGamma,
|
||||
rescaleQuality);
|
||||
if (!tempRTC) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
SkASSERT(SkColorSpace::Equals(tempRTC->colorInfo().colorSpace(), info.colorSpace()));
|
||||
SkASSERT(tempRTC->origin() == kTopLeft_GrSurfaceOrigin);
|
||||
x = y = 0;
|
||||
} else {
|
||||
sk_sp<GrColorSpaceXform> xform = GrColorSpaceXform::Make(this->colorInfo().colorSpace(),
|
||||
this->colorInfo().alphaType(),
|
||||
info.colorSpace(),
|
||||
info.alphaType());
|
||||
// Insert a draw to a temporary surface if we need to do a y-flip or color space conversion.
|
||||
if (this->origin() == kBottomLeft_GrSurfaceOrigin || xform) {
|
||||
// We flip or color convert by drawing and we don't currently support drawing to
|
||||
// kPremul.
|
||||
if (info.alphaType() == kUnpremul_SkAlphaType) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
GrSurfaceProxyView texProxyView = this->readSurfaceView();
|
||||
SkRect srcRectToDraw = SkRect::Make(srcRect);
|
||||
// If the src is not texturable first try to make a copy to a texture.
|
||||
if (!texProxyView.asTextureProxy()) {
|
||||
texProxyView =
|
||||
GrSurfaceProxyView::Copy(fContext, texProxyView, GrMipMapped::kNo, srcRect,
|
||||
SkBackingFit::kApprox, SkBudgeted::kNo);
|
||||
if (!texProxyView) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
SkASSERT(texProxyView.asTextureProxy());
|
||||
srcRectToDraw = SkRect::MakeWH(srcRect.width(), srcRect.height());
|
||||
}
|
||||
tempRTC = GrRenderTargetContext::Make(
|
||||
direct, this->colorInfo().colorType(), info.refColorSpace(),
|
||||
SkBackingFit::kApprox, srcRect.size(), 1, GrMipMapped::kNo, GrProtected::kNo,
|
||||
kTopLeft_GrSurfaceOrigin);
|
||||
if (!tempRTC) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
tempRTC->drawTexture(nullptr, std::move(texProxyView), this->colorInfo().alphaType(),
|
||||
GrSamplerState::Filter::kNearest, SkBlendMode::kSrc,
|
||||
SK_PMColor4fWHITE, srcRectToDraw,
|
||||
SkRect::MakeWH(srcRect.width(), srcRect.height()), GrAA::kNo,
|
||||
GrQuadAAFlags::kNone, SkCanvas::kFast_SrcRectConstraint,
|
||||
SkMatrix::I(), std::move(xform));
|
||||
x = y = 0;
|
||||
}
|
||||
}
|
||||
auto rtc = tempRTC ? tempRTC.get() : this;
|
||||
return rtc->asyncReadPixels(SkIRect::MakeXYWH(x, y, info.width(), info.height()),
|
||||
info.colorType(), callback, context);
|
||||
}
|
||||
|
||||
class GrRenderTargetContext::AsyncReadResult : public SkSurface::AsyncReadResult {
|
||||
public:
|
||||
AsyncReadResult(uint32_t inboxID) : fInboxID(inboxID) {}
|
||||
~AsyncReadResult() override {
|
||||
for (int i = 0; i < fPlanes.count(); ++i) {
|
||||
if (!fPlanes[i].fMappedBuffer) {
|
||||
delete[] static_cast<const char*>(fPlanes[i].fData);
|
||||
} else {
|
||||
GrClientMappedBufferManager::BufferFinishedMessageBus::Post(
|
||||
{std::move(fPlanes[i].fMappedBuffer), fInboxID});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int count() const override { return fPlanes.count(); }
|
||||
const void* data(int i) const override { return fPlanes[i].fData; }
|
||||
size_t rowBytes(int i) const override { return fPlanes[i].fRowBytes; }
|
||||
|
||||
bool addTransferResult(const PixelTransferResult& result,
|
||||
SkISize dimensions,
|
||||
size_t rowBytes,
|
||||
GrClientMappedBufferManager* manager) {
|
||||
SkASSERT(!result.fTransferBuffer->isMapped());
|
||||
const void* mappedData = result.fTransferBuffer->map();
|
||||
if (!mappedData) {
|
||||
return false;
|
||||
}
|
||||
if (result.fPixelConverter) {
|
||||
std::unique_ptr<char[]> convertedData(new char[rowBytes * dimensions.height()]);
|
||||
result.fPixelConverter(convertedData.get(), mappedData);
|
||||
this->addCpuPlane(std::move(convertedData), rowBytes);
|
||||
result.fTransferBuffer->unmap();
|
||||
} else {
|
||||
manager->insert(result.fTransferBuffer);
|
||||
this->addMappedPlane(mappedData, rowBytes, std::move(result.fTransferBuffer));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void addCpuPlane(std::unique_ptr<const char[]> data, size_t rowBytes) {
|
||||
SkASSERT(data);
|
||||
SkASSERT(rowBytes > 0);
|
||||
fPlanes.emplace_back(data.release(), rowBytes, nullptr);
|
||||
}
|
||||
|
||||
private:
|
||||
void addMappedPlane(const void* data, size_t rowBytes, sk_sp<GrGpuBuffer> mappedBuffer) {
|
||||
SkASSERT(data);
|
||||
SkASSERT(rowBytes > 0);
|
||||
SkASSERT(mappedBuffer);
|
||||
SkASSERT(mappedBuffer->isMapped());
|
||||
fPlanes.emplace_back(data, rowBytes, std::move(mappedBuffer));
|
||||
}
|
||||
|
||||
struct Plane {
|
||||
Plane(const void* data, size_t rowBytes, sk_sp<GrGpuBuffer> buffer)
|
||||
: fData(data), fRowBytes(rowBytes), fMappedBuffer(std::move(buffer)) {}
|
||||
const void* fData;
|
||||
size_t fRowBytes;
|
||||
// If this is null then fData is heap alloc and must be delete[]ed as const char[].
|
||||
sk_sp<GrGpuBuffer> fMappedBuffer;
|
||||
};
|
||||
SkSTArray<3, Plane> fPlanes;
|
||||
uint32_t fInboxID;
|
||||
};
|
||||
|
||||
void GrRenderTargetContext::asyncReadPixels(const SkIRect& rect, SkColorType colorType,
|
||||
ReadPixelsCallback callback,
|
||||
ReadPixelsContext context) {
|
||||
SkASSERT(rect.fLeft >= 0 && rect.fRight <= this->width());
|
||||
SkASSERT(rect.fTop >= 0 && rect.fBottom <= this->height());
|
||||
|
||||
if (this->asSurfaceProxy()->isProtected() == GrProtected::kYes) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
auto directContext = fContext->priv().asDirectContext();
|
||||
SkASSERT(directContext);
|
||||
auto mappedBufferManager = directContext->priv().clientMappedBufferManager();
|
||||
|
||||
auto transferResult = this->transferPixels(SkColorTypeToGrColorType(colorType), rect);
|
||||
|
||||
if (!transferResult.fTransferBuffer) {
|
||||
auto ii = SkImageInfo::Make(rect.size(), colorType,
|
||||
this->colorInfo().alphaType(),
|
||||
this->colorInfo().refColorSpace());
|
||||
auto result = std::make_unique<AsyncReadResult>(0);
|
||||
std::unique_ptr<char[]> data(new char[ii.computeMinByteSize()]);
|
||||
SkPixmap pm(ii, data.get(), ii.minRowBytes());
|
||||
result->addCpuPlane(std::move(data), pm.rowBytes());
|
||||
|
||||
if (!this->readPixels(ii, pm.writable_addr(), pm.rowBytes(), {rect.fLeft, rect.fTop})) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
callback(context, std::move(result));
|
||||
return;
|
||||
}
|
||||
|
||||
struct FinishContext {
|
||||
ReadPixelsCallback* fClientCallback;
|
||||
ReadPixelsContext fClientContext;
|
||||
SkISize fSize;
|
||||
SkColorType fColorType;
|
||||
GrClientMappedBufferManager* fMappedBufferManager;
|
||||
PixelTransferResult fTransferResult;
|
||||
};
|
||||
// Assumption is that the caller would like to flush. We could take a parameter or require an
|
||||
// explicit flush from the caller. We'd have to have a way to defer attaching the finish
|
||||
// callback to GrGpu until after the next flush that flushes our op list, though.
|
||||
auto* finishContext = new FinishContext{callback,
|
||||
context,
|
||||
rect.size(),
|
||||
colorType,
|
||||
mappedBufferManager,
|
||||
std::move(transferResult)};
|
||||
auto finishCallback = [](GrGpuFinishedContext c) {
|
||||
const auto* context = reinterpret_cast<const FinishContext*>(c);
|
||||
auto result = std::make_unique<AsyncReadResult>(context->fMappedBufferManager->inboxID());
|
||||
size_t rowBytes = context->fSize.width() * SkColorTypeBytesPerPixel(context->fColorType);
|
||||
if (!result->addTransferResult(context->fTransferResult, context->fSize, rowBytes,
|
||||
context->fMappedBufferManager)) {
|
||||
result.reset();
|
||||
}
|
||||
(*context->fClientCallback)(context->fClientContext, std::move(result));
|
||||
delete context;
|
||||
};
|
||||
GrFlushInfo flushInfo;
|
||||
flushInfo.fFinishedContext = finishContext;
|
||||
flushInfo.fFinishedProc = finishCallback;
|
||||
this->flush(SkSurface::BackendSurfaceAccess::kNoAccess, flushInfo, nullptr);
|
||||
}
|
||||
|
||||
void GrRenderTargetContext::asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,
|
||||
sk_sp<SkColorSpace> dstColorSpace,
|
||||
const SkIRect& srcRect,
|
||||
SkISize dstSize,
|
||||
RescaleGamma rescaleGamma,
|
||||
SkFilterQuality rescaleQuality,
|
||||
ReadPixelsCallback callback,
|
||||
ReadPixelsContext context) {
|
||||
SkASSERT(srcRect.fLeft >= 0 && srcRect.fRight <= this->width());
|
||||
SkASSERT(srcRect.fTop >= 0 && srcRect.fBottom <= this->height());
|
||||
SkASSERT(!dstSize.isZero());
|
||||
SkASSERT((dstSize.width() % 2 == 0) && (dstSize.height() % 2 == 0));
|
||||
|
||||
auto direct = fContext->priv().asDirectContext();
|
||||
if (!direct) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
if (this->asRenderTargetProxy()->wrapsVkSecondaryCB()) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
if (this->asRenderTargetProxy()->framebufferOnly()) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
if (this->asSurfaceProxy()->isProtected() == GrProtected::kYes) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
int x = srcRect.fLeft;
|
||||
int y = srcRect.fTop;
|
||||
bool needsRescale = srcRect.size() != dstSize;
|
||||
GrSurfaceProxyView srcView;
|
||||
if (needsRescale) {
|
||||
// We assume the caller wants kPremul. There is no way to indicate a preference.
|
||||
auto info = SkImageInfo::Make(dstSize, kRGBA_8888_SkColorType, kPremul_SkAlphaType,
|
||||
dstColorSpace);
|
||||
// TODO: Incorporate the YUV conversion into last pass of rescaling.
|
||||
auto tempRTC = this->rescale(info, kTopLeft_GrSurfaceOrigin, srcRect, rescaleGamma,
|
||||
rescaleQuality);
|
||||
if (!tempRTC) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
SkASSERT(SkColorSpace::Equals(tempRTC->colorInfo().colorSpace(), info.colorSpace()));
|
||||
SkASSERT(tempRTC->origin() == kTopLeft_GrSurfaceOrigin);
|
||||
x = y = 0;
|
||||
srcView = tempRTC->readSurfaceView();
|
||||
} else {
|
||||
srcView = this->readSurfaceView();
|
||||
if (!srcView.asTextureProxy()) {
|
||||
srcView = GrSurfaceProxyView::Copy(fContext, std::move(srcView), GrMipMapped::kNo,
|
||||
srcRect, SkBackingFit::kApprox, SkBudgeted::kYes);
|
||||
if (!srcView) {
|
||||
// If we can't get a texture copy of the contents then give up.
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
SkASSERT(srcView.asTextureProxy());
|
||||
x = y = 0;
|
||||
}
|
||||
// We assume the caller wants kPremul. There is no way to indicate a preference.
|
||||
sk_sp<GrColorSpaceXform> xform = GrColorSpaceXform::Make(
|
||||
this->colorInfo().colorSpace(), this->colorInfo().alphaType(), dstColorSpace.get(),
|
||||
kPremul_SkAlphaType);
|
||||
if (xform) {
|
||||
SkRect srcRectToDraw = SkRect::MakeXYWH(x, y, srcRect.width(), srcRect.height());
|
||||
auto tempRTC = GrRenderTargetContext::Make(
|
||||
direct, this->colorInfo().colorType(), dstColorSpace, SkBackingFit::kApprox,
|
||||
dstSize, 1, GrMipMapped::kNo, GrProtected::kNo, kTopLeft_GrSurfaceOrigin);
|
||||
if (!tempRTC) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
tempRTC->drawTexture(nullptr, std::move(srcView), this->colorInfo().alphaType(),
|
||||
GrSamplerState::Filter::kNearest, SkBlendMode::kSrc,
|
||||
SK_PMColor4fWHITE, srcRectToDraw, SkRect::Make(srcRect.size()),
|
||||
GrAA::kNo, GrQuadAAFlags::kNone, SkCanvas::kFast_SrcRectConstraint,
|
||||
SkMatrix::I(), std::move(xform));
|
||||
srcView = tempRTC->readSurfaceView();
|
||||
SkASSERT(srcView.asTextureProxy());
|
||||
x = y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
auto yRTC = GrRenderTargetContext::MakeWithFallback(
|
||||
direct, GrColorType::kAlpha_8, dstColorSpace, SkBackingFit::kApprox, dstSize, 1,
|
||||
GrMipMapped::kNo, GrProtected::kNo, kTopLeft_GrSurfaceOrigin);
|
||||
int halfW = dstSize.width()/2;
|
||||
int halfH = dstSize.height()/2;
|
||||
auto uRTC = GrRenderTargetContext::MakeWithFallback(
|
||||
direct, GrColorType::kAlpha_8, dstColorSpace, SkBackingFit::kApprox, {halfW, halfH}, 1,
|
||||
GrMipMapped::kNo, GrProtected::kNo, kTopLeft_GrSurfaceOrigin);
|
||||
auto vRTC = GrRenderTargetContext::MakeWithFallback(
|
||||
direct, GrColorType::kAlpha_8, dstColorSpace, SkBackingFit::kApprox, {halfW, halfH}, 1,
|
||||
GrMipMapped::kNo, GrProtected::kNo, kTopLeft_GrSurfaceOrigin);
|
||||
if (!yRTC || !uRTC || !vRTC) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
float baseM[20];
|
||||
SkColorMatrix_RGB2YUV(yuvColorSpace, baseM);
|
||||
|
||||
// TODO: Use one transfer buffer for all three planes to reduce map/unmap cost?
|
||||
|
||||
auto texMatrix = SkMatrix::Translate(x, y);
|
||||
|
||||
SkRect dstRectY = SkRect::Make(dstSize);
|
||||
SkRect dstRectUV = SkRect::MakeWH(halfW, halfH);
|
||||
|
||||
bool doSynchronousRead = !this->caps()->transferFromSurfaceToBufferSupport();
|
||||
PixelTransferResult yTransfer, uTransfer, vTransfer;
|
||||
|
||||
// This matrix generates (r,g,b,a) = (0, 0, 0, y)
|
||||
float yM[20];
|
||||
std::fill_n(yM, 15, 0.f);
|
||||
std::copy_n(baseM + 0, 5, yM + 15);
|
||||
GrPaint yPaint;
|
||||
auto yTexFP = GrTextureEffect::Make(srcView, this->colorInfo().alphaType(), texMatrix);
|
||||
auto yColFP = GrColorMatrixFragmentProcessor::Make(std::move(yTexFP), yM,
|
||||
/*unpremulInput=*/false,
|
||||
/*clampRGBOutput=*/true,
|
||||
/*premulOutput=*/false);
|
||||
yPaint.addColorFragmentProcessor(std::move(yColFP));
|
||||
yPaint.setPorterDuffXPFactory(SkBlendMode::kSrc);
|
||||
yRTC->fillRectToRect(nullptr, std::move(yPaint), GrAA::kNo, SkMatrix::I(),
|
||||
dstRectY, dstRectY);
|
||||
if (!doSynchronousRead) {
|
||||
yTransfer = yRTC->transferPixels(GrColorType::kAlpha_8,
|
||||
SkIRect::MakeWH(yRTC->width(), yRTC->height()));
|
||||
if (!yTransfer.fTransferBuffer) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
texMatrix.preScale(2.f, 2.f);
|
||||
// This matrix generates (r,g,b,a) = (0, 0, 0, u)
|
||||
float uM[20];
|
||||
std::fill_n(uM, 15, 0.f);
|
||||
std::copy_n(baseM + 5, 5, uM + 15);
|
||||
GrPaint uPaint;
|
||||
auto uTexFP = GrTextureEffect::Make(srcView, this->colorInfo().alphaType(), texMatrix,
|
||||
GrSamplerState::Filter::kBilerp);
|
||||
auto uColFP = GrColorMatrixFragmentProcessor::Make(std::move(uTexFP), uM,
|
||||
/*unpremulInput=*/false,
|
||||
/*clampRGBOutput=*/true,
|
||||
/*premulOutput=*/false);
|
||||
uPaint.addColorFragmentProcessor(std::move(uColFP));
|
||||
uPaint.setPorterDuffXPFactory(SkBlendMode::kSrc);
|
||||
uRTC->fillRectToRect(nullptr, std::move(uPaint), GrAA::kNo, SkMatrix::I(),
|
||||
dstRectUV, dstRectUV);
|
||||
if (!doSynchronousRead) {
|
||||
uTransfer = uRTC->transferPixels(GrColorType::kAlpha_8,
|
||||
SkIRect::MakeWH(uRTC->width(), uRTC->height()));
|
||||
if (!uTransfer.fTransferBuffer) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// This matrix generates (r,g,b,a) = (0, 0, 0, v)
|
||||
float vM[20];
|
||||
std::fill_n(vM, 15, 0.f);
|
||||
std::copy_n(baseM + 10, 5, vM + 15);
|
||||
GrPaint vPaint;
|
||||
auto vTexFP = GrTextureEffect::Make(std::move(srcView), this->colorInfo().alphaType(),
|
||||
texMatrix, GrSamplerState::Filter::kBilerp);
|
||||
auto vColFP = GrColorMatrixFragmentProcessor::Make(std::move(vTexFP), vM,
|
||||
/*unpremulInput=*/false,
|
||||
/*clampRGBOutput=*/true,
|
||||
/*premulOutput=*/false);
|
||||
vPaint.addColorFragmentProcessor(std::move(vColFP));
|
||||
vPaint.setPorterDuffXPFactory(SkBlendMode::kSrc);
|
||||
vRTC->fillRectToRect(nullptr, std::move(vPaint), GrAA::kNo, SkMatrix::I(),
|
||||
dstRectUV, dstRectUV);
|
||||
if (!doSynchronousRead) {
|
||||
vTransfer = vRTC->transferPixels(GrColorType::kAlpha_8,
|
||||
SkIRect::MakeWH(vRTC->width(), vRTC->height()));
|
||||
if (!vTransfer.fTransferBuffer) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (doSynchronousRead) {
|
||||
GrImageInfo yInfo(GrColorType::kAlpha_8, kPremul_SkAlphaType, nullptr, dstSize);
|
||||
GrImageInfo uvInfo = yInfo.makeWH(halfW, halfH);
|
||||
size_t yRB = yInfo.minRowBytes();
|
||||
size_t uvRB = uvInfo.minRowBytes();
|
||||
std::unique_ptr<char[]> y(new char[yRB * yInfo.height()]);
|
||||
std::unique_ptr<char[]> u(new char[uvRB*uvInfo.height()]);
|
||||
std::unique_ptr<char[]> v(new char[uvRB*uvInfo.height()]);
|
||||
if (!yRTC->readPixels(yInfo, y.get(), yRB, {0, 0}, direct) ||
|
||||
!uRTC->readPixels(uvInfo, u.get(), uvRB, {0, 0}, direct) ||
|
||||
!vRTC->readPixels(uvInfo, v.get(), uvRB, {0, 0}, direct)) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
auto result = std::make_unique<AsyncReadResult>(direct->priv().contextID());
|
||||
result->addCpuPlane(std::move(y), yRB );
|
||||
result->addCpuPlane(std::move(u), uvRB);
|
||||
result->addCpuPlane(std::move(v), uvRB);
|
||||
callback(context, std::move(result));
|
||||
return;
|
||||
}
|
||||
|
||||
struct FinishContext {
|
||||
ReadPixelsCallback* fClientCallback;
|
||||
ReadPixelsContext fClientContext;
|
||||
GrClientMappedBufferManager* fMappedBufferManager;
|
||||
SkISize fSize;
|
||||
PixelTransferResult fYTransfer;
|
||||
PixelTransferResult fUTransfer;
|
||||
PixelTransferResult fVTransfer;
|
||||
};
|
||||
// Assumption is that the caller would like to flush. We could take a parameter or require an
|
||||
// explicit flush from the caller. We'd have to have a way to defer attaching the finish
|
||||
// callback to GrGpu until after the next flush that flushes our op list, though.
|
||||
auto* finishContext = new FinishContext{callback,
|
||||
context,
|
||||
direct->priv().clientMappedBufferManager(),
|
||||
dstSize,
|
||||
std::move(yTransfer),
|
||||
std::move(uTransfer),
|
||||
std::move(vTransfer)};
|
||||
auto finishCallback = [](GrGpuFinishedContext c) {
|
||||
const auto* context = reinterpret_cast<const FinishContext*>(c);
|
||||
auto result = std::make_unique<AsyncReadResult>(context->fMappedBufferManager->inboxID());
|
||||
auto manager = context->fMappedBufferManager;
|
||||
size_t rowBytes = SkToSizeT(context->fSize.width());
|
||||
if (!result->addTransferResult(context->fYTransfer, context->fSize, rowBytes, manager)) {
|
||||
(*context->fClientCallback)(context->fClientContext, nullptr);
|
||||
delete context;
|
||||
return;
|
||||
}
|
||||
rowBytes /= 2;
|
||||
SkISize uvSize = {context->fSize.width()/2, context->fSize.height()/2};
|
||||
if (!result->addTransferResult(context->fUTransfer, uvSize, rowBytes, manager)) {
|
||||
(*context->fClientCallback)(context->fClientContext, nullptr);
|
||||
delete context;
|
||||
return;
|
||||
}
|
||||
if (!result->addTransferResult(context->fVTransfer, uvSize, rowBytes, manager)) {
|
||||
(*context->fClientCallback)(context->fClientContext, nullptr);
|
||||
delete context;
|
||||
return;
|
||||
}
|
||||
(*context->fClientCallback)(context->fClientContext, std::move(result));
|
||||
delete context;
|
||||
};
|
||||
GrFlushInfo flushInfo;
|
||||
flushInfo.fFinishedContext = finishContext;
|
||||
flushInfo.fFinishedProc = finishCallback;
|
||||
this->flush(SkSurface::BackendSurfaceAccess::kNoAccess, flushInfo, nullptr);
|
||||
}
|
||||
|
||||
GrSemaphoresSubmitted GrRenderTargetContext::flush(SkSurface::BackendSurfaceAccess access,
|
||||
const GrFlushInfo& info,
|
||||
const GrBackendSurfaceMutableState* newState) {
|
||||
ASSERT_SINGLE_OWNER
|
||||
if (fContext->priv().abandoned()) {
|
||||
if (info.fSubmittedProc) {
|
||||
info.fSubmittedProc(info.fSubmittedContext, false);
|
||||
}
|
||||
if (info.fFinishedProc) {
|
||||
info.fFinishedProc(info.fFinishedContext);
|
||||
}
|
||||
return GrSemaphoresSubmitted::kNo;
|
||||
}
|
||||
SkDEBUGCODE(this->validate();)
|
||||
GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "flush", fContext);
|
||||
|
||||
return this->drawingManager()->flushSurface(this->asSurfaceProxy(), access, info, newState);
|
||||
}
|
||||
|
||||
bool GrRenderTargetContext::waitOnSemaphores(int numSemaphores,
|
||||
const GrBackendSemaphore waitSemaphores[]) {
|
||||
ASSERT_SINGLE_OWNER
|
||||
|
@ -524,31 +524,6 @@ public:
|
||||
*/
|
||||
void drawDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler>, const SkRect& bounds);
|
||||
|
||||
using ReadPixelsCallback = SkSurface::ReadPixelsCallback;
|
||||
using ReadPixelsContext = SkSurface::ReadPixelsContext;
|
||||
using RescaleGamma = SkSurface::RescaleGamma;
|
||||
|
||||
// GPU implementation for SkSurface::asyncRescaleAndReadPixels.
|
||||
void asyncRescaleAndReadPixels(const SkImageInfo& info, const SkIRect& srcRect,
|
||||
RescaleGamma rescaleGamma, SkFilterQuality rescaleQuality,
|
||||
ReadPixelsCallback callback, ReadPixelsContext context);
|
||||
// GPU implementation for SkSurface::asyncRescaleAndReadPixelsYUV420.
|
||||
void asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,
|
||||
sk_sp<SkColorSpace> dstColorSpace,
|
||||
const SkIRect& srcRect,
|
||||
SkISize dstSize,
|
||||
RescaleGamma rescaleGamma,
|
||||
SkFilterQuality rescaleQuality,
|
||||
ReadPixelsCallback callback,
|
||||
ReadPixelsContext context);
|
||||
|
||||
/**
|
||||
* After this returns any pending surface IO will be issued to the backend 3D API and
|
||||
* if the surface has MSAA it will be resolved.
|
||||
*/
|
||||
GrSemaphoresSubmitted flush(SkSurface::BackendSurfaceAccess access, const GrFlushInfo&,
|
||||
const GrBackendSurfaceMutableState*);
|
||||
|
||||
/**
|
||||
* The next time this GrRenderTargetContext is flushed, the gpu will wait on the passed in
|
||||
* semaphores before executing any commands.
|
||||
@ -694,12 +669,6 @@ private:
|
||||
bool SK_WARN_UNUSED_RESULT setupDstProxyView(const GrOp& op,
|
||||
GrXferProcessor::DstProxyView* result);
|
||||
|
||||
class AsyncReadResult;
|
||||
|
||||
// The async read step of asyncRescaleAndReadPixels()
|
||||
void asyncReadPixels(const SkIRect& rect, SkColorType colorType, ReadPixelsCallback callback,
|
||||
ReadPixelsContext context);
|
||||
|
||||
GrOpsTask* getOpsTask();
|
||||
|
||||
SkGlyphRunListPainter* glyphPainter() { return &fGlyphPainter; }
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "include/private/GrRecordingContext.h"
|
||||
#include "src/core/SkAutoPixmapStorage.h"
|
||||
#include "src/core/SkYUVMath.h"
|
||||
#include "src/gpu/GrAuditTrail.h"
|
||||
#include "src/gpu/GrContextPriv.h"
|
||||
#include "src/gpu/GrDataUtils.h"
|
||||
@ -22,6 +23,7 @@
|
||||
#include "src/gpu/GrSurfacePriv.h"
|
||||
#include "src/gpu/SkGr.h"
|
||||
#include "src/gpu/effects/GrBicubicEffect.h"
|
||||
#include "src/gpu/effects/generated/GrColorMatrixFragmentProcessor.h"
|
||||
|
||||
#define ASSERT_SINGLE_OWNER GR_ASSERT_SINGLE_OWNER(this->singleOwner())
|
||||
#define RETURN_FALSE_IF_ABANDONED if (this->fContext->priv().abandoned()) { return false; }
|
||||
@ -474,6 +476,511 @@ bool GrSurfaceContext::writePixels(const GrImageInfo& origSrcInfo, const void* s
|
||||
srcColorType, src, rowBytes);
|
||||
}
|
||||
|
||||
void GrSurfaceContext::asyncRescaleAndReadPixels(const SkImageInfo& info,
|
||||
const SkIRect& srcRect,
|
||||
RescaleGamma rescaleGamma,
|
||||
SkFilterQuality rescaleQuality,
|
||||
ReadPixelsCallback callback,
|
||||
ReadPixelsContext context) {
|
||||
auto direct = fContext->priv().asDirectContext();
|
||||
|
||||
// We implement this by rendering and we don't currently support rendering kUnpremul.
|
||||
if (info.alphaType() == kUnpremul_SkAlphaType) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
if (!direct) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
auto rt = this->asRenderTargetProxy();
|
||||
if (rt && rt->wrapsVkSecondaryCB()) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
if (rt && rt->framebufferOnly()) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
auto dstCT = SkColorTypeToGrColorType(info.colorType());
|
||||
if (dstCT == GrColorType::kUnknown) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
bool needsRescale = srcRect.width() != info.width() || srcRect.height() != info.height();
|
||||
auto colorTypeOfFinalContext = this->colorInfo().colorType();
|
||||
auto backendFormatOfFinalContext = this->asSurfaceProxy()->backendFormat();
|
||||
if (needsRescale) {
|
||||
colorTypeOfFinalContext = dstCT;
|
||||
backendFormatOfFinalContext =
|
||||
this->caps()->getDefaultBackendFormat(dstCT, GrRenderable::kYes);
|
||||
}
|
||||
auto readInfo = this->caps()->supportedReadPixelsColorType(colorTypeOfFinalContext,
|
||||
backendFormatOfFinalContext, dstCT);
|
||||
// Fail if we can't read from the source surface's color type.
|
||||
if (readInfo.fColorType == GrColorType::kUnknown) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
// Fail if read color type does not have all of dstCT's color channels and those missing color
|
||||
// channels are in the src.
|
||||
uint32_t dstChannels = GrColorTypeChannelFlags(dstCT);
|
||||
uint32_t legalReadChannels = GrColorTypeChannelFlags(readInfo.fColorType);
|
||||
uint32_t srcChannels = GrColorTypeChannelFlags(this->colorInfo().colorType());
|
||||
if ((~legalReadChannels & dstChannels) & srcChannels) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_ptr<GrRenderTargetContext> tempRTC;
|
||||
int x = srcRect.fLeft;
|
||||
int y = srcRect.fTop;
|
||||
if (needsRescale) {
|
||||
tempRTC = this->rescale(info, kTopLeft_GrSurfaceOrigin, srcRect, rescaleGamma,
|
||||
rescaleQuality);
|
||||
if (!tempRTC) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
SkASSERT(SkColorSpace::Equals(tempRTC->colorInfo().colorSpace(), info.colorSpace()));
|
||||
SkASSERT(tempRTC->origin() == kTopLeft_GrSurfaceOrigin);
|
||||
x = y = 0;
|
||||
} else {
|
||||
sk_sp<GrColorSpaceXform> xform = GrColorSpaceXform::Make(this->colorInfo().colorSpace(),
|
||||
this->colorInfo().alphaType(),
|
||||
info.colorSpace(),
|
||||
info.alphaType());
|
||||
// Insert a draw to a temporary surface if we need to do a y-flip or color space conversion.
|
||||
if (this->origin() == kBottomLeft_GrSurfaceOrigin || xform) {
|
||||
GrSurfaceProxyView texProxyView = this->readSurfaceView();
|
||||
SkRect srcRectToDraw = SkRect::Make(srcRect);
|
||||
// If the src is not texturable first try to make a copy to a texture.
|
||||
if (!texProxyView.asTextureProxy()) {
|
||||
texProxyView =
|
||||
GrSurfaceProxyView::Copy(fContext, texProxyView, GrMipMapped::kNo, srcRect,
|
||||
SkBackingFit::kApprox, SkBudgeted::kNo);
|
||||
if (!texProxyView) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
SkASSERT(texProxyView.asTextureProxy());
|
||||
srcRectToDraw = SkRect::MakeWH(srcRect.width(), srcRect.height());
|
||||
}
|
||||
tempRTC = GrRenderTargetContext::Make(direct, this->colorInfo().colorType(),
|
||||
info.refColorSpace(), SkBackingFit::kApprox,
|
||||
srcRect.size(), 1, GrMipMapped::kNo,
|
||||
GrProtected::kNo, kTopLeft_GrSurfaceOrigin);
|
||||
if (!tempRTC) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
tempRTC->drawTexture(nullptr, std::move(texProxyView), this->colorInfo().alphaType(),
|
||||
GrSamplerState::Filter::kNearest, SkBlendMode::kSrc,
|
||||
SK_PMColor4fWHITE, srcRectToDraw,
|
||||
SkRect::MakeWH(srcRect.width(), srcRect.height()), GrAA::kNo,
|
||||
GrQuadAAFlags::kNone, SkCanvas::kFast_SrcRectConstraint,
|
||||
SkMatrix::I(), std::move(xform));
|
||||
x = y = 0;
|
||||
}
|
||||
}
|
||||
auto rtc = tempRTC ? tempRTC.get() : this;
|
||||
return rtc->asyncReadPixels(SkIRect::MakeXYWH(x, y, info.width(), info.height()),
|
||||
info.colorType(), callback, context);
|
||||
}
|
||||
|
||||
class GrSurfaceContext::AsyncReadResult : public SkImage::AsyncReadResult {
|
||||
public:
|
||||
AsyncReadResult(uint32_t inboxID) : fInboxID(inboxID) {}
|
||||
~AsyncReadResult() override {
|
||||
for (int i = 0; i < fPlanes.count(); ++i) {
|
||||
if (!fPlanes[i].fMappedBuffer) {
|
||||
delete[] static_cast<const char*>(fPlanes[i].fData);
|
||||
} else {
|
||||
GrClientMappedBufferManager::BufferFinishedMessageBus::Post(
|
||||
{std::move(fPlanes[i].fMappedBuffer), fInboxID});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int count() const override { return fPlanes.count(); }
|
||||
const void* data(int i) const override { return fPlanes[i].fData; }
|
||||
size_t rowBytes(int i) const override { return fPlanes[i].fRowBytes; }
|
||||
|
||||
bool addTransferResult(const PixelTransferResult& result,
|
||||
SkISize dimensions,
|
||||
size_t rowBytes,
|
||||
GrClientMappedBufferManager* manager) {
|
||||
SkASSERT(!result.fTransferBuffer->isMapped());
|
||||
const void* mappedData = result.fTransferBuffer->map();
|
||||
if (!mappedData) {
|
||||
return false;
|
||||
}
|
||||
if (result.fPixelConverter) {
|
||||
std::unique_ptr<char[]> convertedData(new char[rowBytes * dimensions.height()]);
|
||||
result.fPixelConverter(convertedData.get(), mappedData);
|
||||
this->addCpuPlane(std::move(convertedData), rowBytes);
|
||||
result.fTransferBuffer->unmap();
|
||||
} else {
|
||||
manager->insert(result.fTransferBuffer);
|
||||
this->addMappedPlane(mappedData, rowBytes, std::move(result.fTransferBuffer));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void addCpuPlane(std::unique_ptr<const char[]> data, size_t rowBytes) {
|
||||
SkASSERT(data);
|
||||
SkASSERT(rowBytes > 0);
|
||||
fPlanes.emplace_back(data.release(), rowBytes, nullptr);
|
||||
}
|
||||
|
||||
private:
|
||||
void addMappedPlane(const void* data, size_t rowBytes, sk_sp<GrGpuBuffer> mappedBuffer) {
|
||||
SkASSERT(data);
|
||||
SkASSERT(rowBytes > 0);
|
||||
SkASSERT(mappedBuffer);
|
||||
SkASSERT(mappedBuffer->isMapped());
|
||||
fPlanes.emplace_back(data, rowBytes, std::move(mappedBuffer));
|
||||
}
|
||||
|
||||
struct Plane {
|
||||
Plane(const void* data, size_t rowBytes, sk_sp<GrGpuBuffer> buffer)
|
||||
: fData(data), fRowBytes(rowBytes), fMappedBuffer(std::move(buffer)) {}
|
||||
const void* fData;
|
||||
size_t fRowBytes;
|
||||
// If this is null then fData is heap alloc and must be delete[]ed as const char[].
|
||||
sk_sp<GrGpuBuffer> fMappedBuffer;
|
||||
};
|
||||
SkSTArray<3, Plane> fPlanes;
|
||||
uint32_t fInboxID;
|
||||
};
|
||||
|
||||
void GrSurfaceContext::asyncReadPixels(const SkIRect& rect,
|
||||
SkColorType colorType,
|
||||
ReadPixelsCallback callback,
|
||||
ReadPixelsContext context) {
|
||||
SkASSERT(rect.fLeft >= 0 && rect.fRight <= this->width());
|
||||
SkASSERT(rect.fTop >= 0 && rect.fBottom <= this->height());
|
||||
|
||||
if (this->asSurfaceProxy()->isProtected() == GrProtected::kYes) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
auto directContext = fContext->priv().asDirectContext();
|
||||
SkASSERT(directContext);
|
||||
auto mappedBufferManager = directContext->priv().clientMappedBufferManager();
|
||||
|
||||
auto transferResult = this->transferPixels(SkColorTypeToGrColorType(colorType), rect);
|
||||
|
||||
if (!transferResult.fTransferBuffer) {
|
||||
auto ii = SkImageInfo::Make(rect.size(), colorType, this->colorInfo().alphaType(),
|
||||
this->colorInfo().refColorSpace());
|
||||
auto result = std::make_unique<AsyncReadResult>(0);
|
||||
std::unique_ptr<char[]> data(new char[ii.computeMinByteSize()]);
|
||||
SkPixmap pm(ii, data.get(), ii.minRowBytes());
|
||||
result->addCpuPlane(std::move(data), pm.rowBytes());
|
||||
|
||||
if (!this->readPixels(ii, pm.writable_addr(), pm.rowBytes(), {rect.fLeft, rect.fTop})) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
callback(context, std::move(result));
|
||||
return;
|
||||
}
|
||||
|
||||
struct FinishContext {
|
||||
ReadPixelsCallback* fClientCallback;
|
||||
ReadPixelsContext fClientContext;
|
||||
SkISize fSize;
|
||||
SkColorType fColorType;
|
||||
GrClientMappedBufferManager* fMappedBufferManager;
|
||||
PixelTransferResult fTransferResult;
|
||||
};
|
||||
// Assumption is that the caller would like to flush. We could take a parameter or require an
|
||||
// explicit flush from the caller. We'd have to have a way to defer attaching the finish
|
||||
// callback to GrGpu until after the next flush that flushes our op list, though.
|
||||
auto* finishContext = new FinishContext{callback,
|
||||
context,
|
||||
rect.size(),
|
||||
colorType,
|
||||
mappedBufferManager,
|
||||
std::move(transferResult)};
|
||||
auto finishCallback = [](GrGpuFinishedContext c) {
|
||||
const auto* context = reinterpret_cast<const FinishContext*>(c);
|
||||
auto result = std::make_unique<AsyncReadResult>(context->fMappedBufferManager->inboxID());
|
||||
size_t rowBytes = context->fSize.width() * SkColorTypeBytesPerPixel(context->fColorType);
|
||||
if (!result->addTransferResult(context->fTransferResult, context->fSize, rowBytes,
|
||||
context->fMappedBufferManager)) {
|
||||
result.reset();
|
||||
}
|
||||
(*context->fClientCallback)(context->fClientContext, std::move(result));
|
||||
delete context;
|
||||
};
|
||||
GrFlushInfo flushInfo;
|
||||
flushInfo.fFinishedContext = finishContext;
|
||||
flushInfo.fFinishedProc = finishCallback;
|
||||
this->flush(SkSurface::BackendSurfaceAccess::kNoAccess, flushInfo, nullptr);
|
||||
}
|
||||
|
||||
void GrSurfaceContext::asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,
|
||||
sk_sp<SkColorSpace> dstColorSpace,
|
||||
const SkIRect& srcRect,
|
||||
SkISize dstSize,
|
||||
RescaleGamma rescaleGamma,
|
||||
SkFilterQuality rescaleQuality,
|
||||
ReadPixelsCallback callback,
|
||||
ReadPixelsContext context) {
|
||||
SkASSERT(srcRect.fLeft >= 0 && srcRect.fRight <= this->width());
|
||||
SkASSERT(srcRect.fTop >= 0 && srcRect.fBottom <= this->height());
|
||||
SkASSERT(!dstSize.isZero());
|
||||
SkASSERT((dstSize.width() % 2 == 0) && (dstSize.height() % 2 == 0));
|
||||
|
||||
auto direct = fContext->priv().asDirectContext();
|
||||
if (!direct) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
auto rt = this->asRenderTargetProxy();
|
||||
if (rt && rt->wrapsVkSecondaryCB()) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
if (rt && rt->framebufferOnly()) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
if (this->asSurfaceProxy()->isProtected() == GrProtected::kYes) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
int x = srcRect.fLeft;
|
||||
int y = srcRect.fTop;
|
||||
bool needsRescale = srcRect.size() != dstSize;
|
||||
GrSurfaceProxyView srcView;
|
||||
if (needsRescale) {
|
||||
// We assume the caller wants kPremul. There is no way to indicate a preference.
|
||||
auto info = SkImageInfo::Make(dstSize, kRGBA_8888_SkColorType, kPremul_SkAlphaType,
|
||||
dstColorSpace);
|
||||
// TODO: Incorporate the YUV conversion into last pass of rescaling.
|
||||
auto tempRTC = this->rescale(info, kTopLeft_GrSurfaceOrigin, srcRect, rescaleGamma,
|
||||
rescaleQuality);
|
||||
if (!tempRTC) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
SkASSERT(SkColorSpace::Equals(tempRTC->colorInfo().colorSpace(), info.colorSpace()));
|
||||
SkASSERT(tempRTC->origin() == kTopLeft_GrSurfaceOrigin);
|
||||
x = y = 0;
|
||||
srcView = tempRTC->readSurfaceView();
|
||||
} else {
|
||||
srcView = this->readSurfaceView();
|
||||
if (!srcView.asTextureProxy()) {
|
||||
srcView = GrSurfaceProxyView::Copy(fContext, std::move(srcView), GrMipMapped::kNo,
|
||||
srcRect, SkBackingFit::kApprox, SkBudgeted::kYes);
|
||||
if (!srcView) {
|
||||
// If we can't get a texture copy of the contents then give up.
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
SkASSERT(srcView.asTextureProxy());
|
||||
x = y = 0;
|
||||
}
|
||||
// We assume the caller wants kPremul. There is no way to indicate a preference.
|
||||
sk_sp<GrColorSpaceXform> xform = GrColorSpaceXform::Make(
|
||||
this->colorInfo().colorSpace(), this->colorInfo().alphaType(), dstColorSpace.get(),
|
||||
kPremul_SkAlphaType);
|
||||
if (xform) {
|
||||
SkRect srcRectToDraw = SkRect::MakeXYWH(x, y, srcRect.width(), srcRect.height());
|
||||
auto tempRTC = GrRenderTargetContext::Make(
|
||||
direct, this->colorInfo().colorType(), dstColorSpace, SkBackingFit::kApprox,
|
||||
dstSize, 1, GrMipMapped::kNo, GrProtected::kNo, kTopLeft_GrSurfaceOrigin);
|
||||
if (!tempRTC) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
tempRTC->drawTexture(nullptr, std::move(srcView), this->colorInfo().alphaType(),
|
||||
GrSamplerState::Filter::kNearest, SkBlendMode::kSrc,
|
||||
SK_PMColor4fWHITE, srcRectToDraw, SkRect::Make(srcRect.size()),
|
||||
GrAA::kNo, GrQuadAAFlags::kNone, SkCanvas::kFast_SrcRectConstraint,
|
||||
SkMatrix::I(), std::move(xform));
|
||||
srcView = tempRTC->readSurfaceView();
|
||||
SkASSERT(srcView.asTextureProxy());
|
||||
x = y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
auto yRTC = GrRenderTargetContext::MakeWithFallback(
|
||||
direct, GrColorType::kAlpha_8, dstColorSpace, SkBackingFit::kApprox, dstSize, 1,
|
||||
GrMipMapped::kNo, GrProtected::kNo, kTopLeft_GrSurfaceOrigin);
|
||||
int halfW = dstSize.width() /2;
|
||||
int halfH = dstSize.height()/2;
|
||||
auto uRTC = GrRenderTargetContext::MakeWithFallback(
|
||||
direct, GrColorType::kAlpha_8, dstColorSpace, SkBackingFit::kApprox, {halfW, halfH}, 1,
|
||||
GrMipMapped::kNo, GrProtected::kNo, kTopLeft_GrSurfaceOrigin);
|
||||
auto vRTC = GrRenderTargetContext::MakeWithFallback(
|
||||
direct, GrColorType::kAlpha_8, dstColorSpace, SkBackingFit::kApprox, {halfW, halfH}, 1,
|
||||
GrMipMapped::kNo, GrProtected::kNo, kTopLeft_GrSurfaceOrigin);
|
||||
if (!yRTC || !uRTC || !vRTC) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
float baseM[20];
|
||||
SkColorMatrix_RGB2YUV(yuvColorSpace, baseM);
|
||||
|
||||
// TODO: Use one transfer buffer for all three planes to reduce map/unmap cost?
|
||||
|
||||
auto texMatrix = SkMatrix::Translate(x, y);
|
||||
|
||||
SkRect dstRectY = SkRect::Make(dstSize);
|
||||
SkRect dstRectUV = SkRect::MakeWH(halfW, halfH);
|
||||
|
||||
bool doSynchronousRead = !this->caps()->transferFromSurfaceToBufferSupport();
|
||||
PixelTransferResult yTransfer, uTransfer, vTransfer;
|
||||
|
||||
// This matrix generates (r,g,b,a) = (0, 0, 0, y)
|
||||
float yM[20];
|
||||
std::fill_n(yM, 15, 0.f);
|
||||
std::copy_n(baseM + 0, 5, yM + 15);
|
||||
GrPaint yPaint;
|
||||
auto yTexFP = GrTextureEffect::Make(srcView, this->colorInfo().alphaType(), texMatrix);
|
||||
auto yColFP = GrColorMatrixFragmentProcessor::Make(std::move(yTexFP), yM,
|
||||
/*unpremulInput=*/false,
|
||||
/*clampRGBOutput=*/true,
|
||||
/*premulOutput=*/false);
|
||||
yPaint.addColorFragmentProcessor(std::move(yColFP));
|
||||
yPaint.setPorterDuffXPFactory(SkBlendMode::kSrc);
|
||||
yRTC->fillRectToRect(nullptr, std::move(yPaint), GrAA::kNo, SkMatrix::I(), dstRectY, dstRectY);
|
||||
if (!doSynchronousRead) {
|
||||
yTransfer = yRTC->transferPixels(GrColorType::kAlpha_8,
|
||||
SkIRect::MakeWH(yRTC->width(), yRTC->height()));
|
||||
if (!yTransfer.fTransferBuffer) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
texMatrix.preScale(2.f, 2.f);
|
||||
// This matrix generates (r,g,b,a) = (0, 0, 0, u)
|
||||
float uM[20];
|
||||
std::fill_n(uM, 15, 0.f);
|
||||
std::copy_n(baseM + 5, 5, uM + 15);
|
||||
GrPaint uPaint;
|
||||
auto uTexFP = GrTextureEffect::Make(srcView, this->colorInfo().alphaType(), texMatrix,
|
||||
GrSamplerState::Filter::kBilerp);
|
||||
auto uColFP = GrColorMatrixFragmentProcessor::Make(std::move(uTexFP), uM,
|
||||
/*unpremulInput=*/false,
|
||||
/*clampRGBOutput=*/true,
|
||||
/*premulOutput=*/false);
|
||||
uPaint.addColorFragmentProcessor(std::move(uColFP));
|
||||
uPaint.setPorterDuffXPFactory(SkBlendMode::kSrc);
|
||||
uRTC->fillRectToRect(nullptr, std::move(uPaint), GrAA::kNo, SkMatrix::I(), dstRectUV,
|
||||
dstRectUV);
|
||||
if (!doSynchronousRead) {
|
||||
uTransfer = uRTC->transferPixels(GrColorType::kAlpha_8,
|
||||
SkIRect::MakeWH(uRTC->width(), uRTC->height()));
|
||||
if (!uTransfer.fTransferBuffer) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// This matrix generates (r,g,b,a) = (0, 0, 0, v)
|
||||
float vM[20];
|
||||
std::fill_n(vM, 15, 0.f);
|
||||
std::copy_n(baseM + 10, 5, vM + 15);
|
||||
GrPaint vPaint;
|
||||
auto vTexFP = GrTextureEffect::Make(std::move(srcView), this->colorInfo().alphaType(),
|
||||
texMatrix, GrSamplerState::Filter::kBilerp);
|
||||
auto vColFP = GrColorMatrixFragmentProcessor::Make(std::move(vTexFP), vM,
|
||||
/*unpremulInput=*/false,
|
||||
/*clampRGBOutput=*/true,
|
||||
/*premulOutput=*/false);
|
||||
vPaint.addColorFragmentProcessor(std::move(vColFP));
|
||||
vPaint.setPorterDuffXPFactory(SkBlendMode::kSrc);
|
||||
vRTC->fillRectToRect(nullptr, std::move(vPaint), GrAA::kNo, SkMatrix::I(), dstRectUV,
|
||||
dstRectUV);
|
||||
if (!doSynchronousRead) {
|
||||
vTransfer = vRTC->transferPixels(GrColorType::kAlpha_8,
|
||||
SkIRect::MakeWH(vRTC->width(), vRTC->height()));
|
||||
if (!vTransfer.fTransferBuffer) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (doSynchronousRead) {
|
||||
GrImageInfo yInfo(GrColorType::kAlpha_8, kPremul_SkAlphaType, nullptr, dstSize);
|
||||
GrImageInfo uvInfo = yInfo.makeWH(halfW, halfH);
|
||||
size_t yRB = yInfo.minRowBytes();
|
||||
size_t uvRB = uvInfo.minRowBytes();
|
||||
std::unique_ptr<char[]> y(new char[yRB * yInfo.height()]);
|
||||
std::unique_ptr<char[]> u(new char[uvRB*uvInfo.height()]);
|
||||
std::unique_ptr<char[]> v(new char[uvRB*uvInfo.height()]);
|
||||
if (!yRTC->readPixels(yInfo, y.get(), yRB, {0, 0}, direct) ||
|
||||
!uRTC->readPixels(uvInfo, u.get(), uvRB, {0, 0}, direct) ||
|
||||
!vRTC->readPixels(uvInfo, v.get(), uvRB, {0, 0}, direct)) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
auto result = std::make_unique<AsyncReadResult>(direct->priv().contextID());
|
||||
result->addCpuPlane(std::move(y), yRB );
|
||||
result->addCpuPlane(std::move(u), uvRB);
|
||||
result->addCpuPlane(std::move(v), uvRB);
|
||||
callback(context, std::move(result));
|
||||
return;
|
||||
}
|
||||
|
||||
struct FinishContext {
|
||||
ReadPixelsCallback* fClientCallback;
|
||||
ReadPixelsContext fClientContext;
|
||||
GrClientMappedBufferManager* fMappedBufferManager;
|
||||
SkISize fSize;
|
||||
PixelTransferResult fYTransfer;
|
||||
PixelTransferResult fUTransfer;
|
||||
PixelTransferResult fVTransfer;
|
||||
};
|
||||
// Assumption is that the caller would like to flush. We could take a parameter or require an
|
||||
// explicit flush from the caller. We'd have to have a way to defer attaching the finish
|
||||
// callback to GrGpu until after the next flush that flushes our op list, though.
|
||||
auto* finishContext = new FinishContext{callback,
|
||||
context,
|
||||
direct->priv().clientMappedBufferManager(),
|
||||
dstSize,
|
||||
std::move(yTransfer),
|
||||
std::move(uTransfer),
|
||||
std::move(vTransfer)};
|
||||
auto finishCallback = [](GrGpuFinishedContext c) {
|
||||
const auto* context = reinterpret_cast<const FinishContext*>(c);
|
||||
auto result = std::make_unique<AsyncReadResult>(context->fMappedBufferManager->inboxID());
|
||||
auto manager = context->fMappedBufferManager;
|
||||
size_t rowBytes = SkToSizeT(context->fSize.width());
|
||||
if (!result->addTransferResult(context->fYTransfer, context->fSize, rowBytes, manager)) {
|
||||
(*context->fClientCallback)(context->fClientContext, nullptr);
|
||||
delete context;
|
||||
return;
|
||||
}
|
||||
rowBytes /= 2;
|
||||
SkISize uvSize = {context->fSize.width() / 2, context->fSize.height() / 2};
|
||||
if (!result->addTransferResult(context->fUTransfer, uvSize, rowBytes, manager)) {
|
||||
(*context->fClientCallback)(context->fClientContext, nullptr);
|
||||
delete context;
|
||||
return;
|
||||
}
|
||||
if (!result->addTransferResult(context->fVTransfer, uvSize, rowBytes, manager)) {
|
||||
(*context->fClientCallback)(context->fClientContext, nullptr);
|
||||
delete context;
|
||||
return;
|
||||
}
|
||||
(*context->fClientCallback)(context->fClientContext, std::move(result));
|
||||
delete context;
|
||||
};
|
||||
GrFlushInfo flushInfo;
|
||||
flushInfo.fFinishedContext = finishContext;
|
||||
flushInfo.fFinishedProc = finishCallback;
|
||||
this->flush(SkSurface::BackendSurfaceAccess::kNoAccess, flushInfo, nullptr);
|
||||
}
|
||||
|
||||
bool GrSurfaceContext::copy(GrSurfaceProxy* src, const SkIRect& srcRect, const SkIPoint& dstPoint) {
|
||||
ASSERT_SINGLE_OWNER
|
||||
RETURN_FALSE_IF_ABANDONED
|
||||
@ -499,12 +1006,11 @@ bool GrSurfaceContext::copy(GrSurfaceProxy* src, const SkIRect& srcRect, const S
|
||||
this->readSurfaceView(), dstPoint);
|
||||
}
|
||||
|
||||
std::unique_ptr<GrRenderTargetContext> GrSurfaceContext::rescale(
|
||||
const GrImageInfo& info,
|
||||
GrSurfaceOrigin origin,
|
||||
SkIRect srcRect,
|
||||
SkSurface::RescaleGamma rescaleGamma,
|
||||
SkFilterQuality rescaleQuality) {
|
||||
std::unique_ptr<GrRenderTargetContext> GrSurfaceContext::rescale(const GrImageInfo& info,
|
||||
GrSurfaceOrigin origin,
|
||||
SkIRect srcRect,
|
||||
RescaleGamma rescaleGamma,
|
||||
SkFilterQuality rescaleQuality) {
|
||||
auto rtProxy = this->asRenderTargetProxy();
|
||||
if (rtProxy && rtProxy->wrapsVkSecondaryCB()) {
|
||||
return nullptr;
|
||||
@ -538,7 +1044,7 @@ std::unique_ptr<GrRenderTargetContext> GrSurfaceContext::rescale(
|
||||
|
||||
// Assume we should ignore the rescale linear request if the surface has no color space since
|
||||
// it's unclear how we'd linearize from an unknown color space.
|
||||
if (rescaleGamma == SkSurface::kLinear && this->colorInfo().colorSpace() &&
|
||||
if (rescaleGamma == RescaleGamma::kLinear && this->colorInfo().colorSpace() &&
|
||||
!this->colorInfo().colorSpace()->gammaIsLinear()) {
|
||||
auto cs = this->colorInfo().colorSpace()->makeLinearGamma();
|
||||
auto xform = GrColorSpaceXform::Make(this->colorInfo().colorSpace(), srcAlphaType, cs.get(),
|
||||
@ -640,6 +1146,25 @@ std::unique_ptr<GrRenderTargetContext> GrSurfaceContext::rescale(
|
||||
return tempA;
|
||||
}
|
||||
|
||||
GrSemaphoresSubmitted GrSurfaceContext::flush(SkSurface::BackendSurfaceAccess access,
|
||||
const GrFlushInfo& info,
|
||||
const GrBackendSurfaceMutableState* newState) {
|
||||
ASSERT_SINGLE_OWNER
|
||||
if (fContext->priv().abandoned()) {
|
||||
if (info.fSubmittedProc) {
|
||||
info.fSubmittedProc(info.fSubmittedContext, false);
|
||||
}
|
||||
if (info.fFinishedProc) {
|
||||
info.fFinishedProc(info.fFinishedContext);
|
||||
}
|
||||
return GrSemaphoresSubmitted::kNo;
|
||||
}
|
||||
SkDEBUGCODE(this->validate();)
|
||||
GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "flush", fContext);
|
||||
|
||||
return this->drawingManager()->flushSurface(this->asSurfaceProxy(), access, info, newState);
|
||||
}
|
||||
|
||||
GrSurfaceContext::PixelTransferResult GrSurfaceContext::transferPixels(GrColorType dstCT,
|
||||
const SkIRect& rect) {
|
||||
SkASSERT(rect.fLeft >= 0 && rect.fRight <= this->width());
|
||||
|
@ -9,9 +9,11 @@
|
||||
#define GrSurfaceContext_DEFINED
|
||||
|
||||
#include "include/core/SkFilterQuality.h"
|
||||
#include "include/core/SkImage.h"
|
||||
#include "include/core/SkRect.h"
|
||||
#include "include/core/SkRefCnt.h"
|
||||
#include "include/core/SkSurface.h"
|
||||
#include "src/gpu/GrClientMappedBufferManager.h"
|
||||
#include "src/gpu/GrColorInfo.h"
|
||||
#include "src/gpu/GrDataUtils.h"
|
||||
#include "src/gpu/GrImageInfo.h"
|
||||
@ -83,6 +85,28 @@ public:
|
||||
bool readPixels(const GrImageInfo& dstInfo, void* dst, size_t rowBytes, SkIPoint srcPt,
|
||||
GrContext* direct = nullptr);
|
||||
|
||||
using ReadPixelsCallback = SkImage::ReadPixelsCallback;
|
||||
using ReadPixelsContext = SkImage::ReadPixelsContext;
|
||||
using RescaleGamma = SkImage::RescaleGamma;
|
||||
|
||||
// GPU implementation for SkImage:: and SkSurface::asyncRescaleAndReadPixels.
|
||||
void asyncRescaleAndReadPixels(const SkImageInfo& info,
|
||||
const SkIRect& srcRect,
|
||||
RescaleGamma rescaleGamma,
|
||||
SkFilterQuality rescaleQuality,
|
||||
ReadPixelsCallback callback,
|
||||
ReadPixelsContext context);
|
||||
|
||||
// GPU implementation for SkImage:: and SkSurface::asyncRescaleAndReadPixelsYUV420.
|
||||
void asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,
|
||||
sk_sp<SkColorSpace> dstColorSpace,
|
||||
const SkIRect& srcRect,
|
||||
SkISize dstSize,
|
||||
RescaleGamma rescaleGamma,
|
||||
SkFilterQuality rescaleQuality,
|
||||
ReadPixelsCallback callback,
|
||||
ReadPixelsContext context);
|
||||
|
||||
/**
|
||||
* Writes a rectangle of pixels [srcInfo, srcBuffer, srcRowbytes] into the
|
||||
* renderTargetContext at the specified position.
|
||||
@ -124,9 +148,17 @@ public:
|
||||
std::unique_ptr<GrRenderTargetContext> rescale(const GrImageInfo& info,
|
||||
GrSurfaceOrigin,
|
||||
SkIRect srcRect,
|
||||
SkSurface::RescaleGamma,
|
||||
SkImage::RescaleGamma,
|
||||
SkFilterQuality);
|
||||
|
||||
/**
|
||||
* After this returns any pending surface IO will be issued to the backend 3D API and
|
||||
* if the surface has MSAA it will be resolved.
|
||||
*/
|
||||
GrSemaphoresSubmitted flush(SkSurface::BackendSurfaceAccess access,
|
||||
const GrFlushInfo&,
|
||||
const GrBackendSurfaceMutableState*);
|
||||
|
||||
GrAuditTrail* auditTrail();
|
||||
|
||||
// Provides access to functions that aren't part of the public API.
|
||||
@ -171,6 +203,12 @@ protected:
|
||||
};
|
||||
PixelTransferResult transferPixels(GrColorType colorType, const SkIRect& rect);
|
||||
|
||||
// The async read step of asyncRescaleAndReadPixels()
|
||||
void asyncReadPixels(const SkIRect& rect,
|
||||
SkColorType colorType,
|
||||
ReadPixelsCallback callback,
|
||||
ReadPixelsContext context);
|
||||
|
||||
private:
|
||||
friend class GrSurfaceProxy; // for copy
|
||||
|
||||
@ -192,6 +230,8 @@ private:
|
||||
*/
|
||||
bool copy(GrSurfaceProxy* src, const SkIRect& srcRect, const SkIPoint& dstPoint);
|
||||
|
||||
class AsyncReadResult;
|
||||
|
||||
GrColorInfo fColorInfo;
|
||||
|
||||
typedef SkRefCnt INHERITED;
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "src/core/SkSpecialImage.h"
|
||||
#include "src/image/SkImage_Base.h"
|
||||
#include "src/image/SkReadPixelsRec.h"
|
||||
#include "src/image/SkRescaleAndReadPixels.h"
|
||||
#include "src/shaders/SkImageShader.h"
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
@ -52,6 +53,44 @@ bool SkImage::readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dst
|
||||
return as_IB(this)->onReadPixels(dstInfo, dstPixels, dstRowBytes, srcX, srcY, chint);
|
||||
}
|
||||
|
||||
void SkImage::asyncRescaleAndReadPixels(const SkImageInfo& info,
|
||||
const SkIRect& srcRect,
|
||||
RescaleGamma rescaleGamma,
|
||||
SkFilterQuality rescaleQuality,
|
||||
ReadPixelsCallback callback,
|
||||
ReadPixelsContext context) {
|
||||
if (!SkIRect::MakeWH(this->width(), this->height()).contains(srcRect) ||
|
||||
!SkImageInfoIsValid(info)) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
as_IB(this)->onAsyncRescaleAndReadPixels(
|
||||
info, srcRect, rescaleGamma, rescaleQuality, callback, context);
|
||||
}
|
||||
|
||||
void SkImage::asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,
|
||||
sk_sp<SkColorSpace> dstColorSpace,
|
||||
const SkIRect& srcRect,
|
||||
const SkISize& dstSize,
|
||||
RescaleGamma rescaleGamma,
|
||||
SkFilterQuality rescaleQuality,
|
||||
ReadPixelsCallback callback,
|
||||
ReadPixelsContext context) {
|
||||
if (!SkIRect::MakeWH(this->width(), this->height()).contains(srcRect) || dstSize.isZero() ||
|
||||
(dstSize.width() & 0b1) || (dstSize.height() & 0b1)) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
as_IB(this)->onAsyncRescaleAndReadPixelsYUV420(yuvColorSpace,
|
||||
std::move(dstColorSpace),
|
||||
srcRect,
|
||||
dstSize,
|
||||
rescaleGamma,
|
||||
rescaleQuality,
|
||||
callback,
|
||||
context);
|
||||
}
|
||||
|
||||
bool SkImage::scalePixels(const SkPixmap& dst, SkFilterQuality quality, CachingHint chint) const {
|
||||
if (this->width() == dst.width() && this->height() == dst.height()) {
|
||||
return this->readPixels(dst, 0, 0, chint);
|
||||
@ -207,6 +246,44 @@ SkImage_Base::~SkImage_Base() {
|
||||
}
|
||||
}
|
||||
|
||||
void SkImage_Base::onAsyncRescaleAndReadPixels(const SkImageInfo& info,
|
||||
const SkIRect& origSrcRect,
|
||||
RescaleGamma rescaleGamma,
|
||||
SkFilterQuality rescaleQuality,
|
||||
ReadPixelsCallback callback,
|
||||
ReadPixelsContext context) {
|
||||
SkBitmap src;
|
||||
SkPixmap peek;
|
||||
SkIRect srcRect;
|
||||
if (this->peekPixels(&peek)) {
|
||||
src.installPixels(peek);
|
||||
srcRect = origSrcRect;
|
||||
} else {
|
||||
src.setInfo(this->imageInfo().makeDimensions(origSrcRect.size()));
|
||||
src.allocPixels();
|
||||
if (!this->readPixels(src.pixmap(), origSrcRect.x(), origSrcRect.y())) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
srcRect = SkIRect::MakeSize(src.dimensions());
|
||||
}
|
||||
return SkRescaleAndReadPixels(
|
||||
src, info, srcRect, rescaleGamma, rescaleQuality, callback, context);
|
||||
}
|
||||
|
||||
void SkImage_Base::onAsyncRescaleAndReadPixelsYUV420(SkYUVColorSpace,
|
||||
sk_sp<SkColorSpace> dstColorSpace,
|
||||
const SkIRect& srcRect,
|
||||
const SkISize& dstSize,
|
||||
RescaleGamma,
|
||||
SkFilterQuality,
|
||||
ReadPixelsCallback callback,
|
||||
ReadPixelsContext context) {
|
||||
// TODO: Call non-YUV asyncRescaleAndReadPixels and then make our callback convert to YUV and
|
||||
// call client's callback.
|
||||
callback(context, nullptr);
|
||||
}
|
||||
|
||||
GrBackendTexture SkImage_Base::onGetBackendTexture(bool flushPendingGrContextIO,
|
||||
GrSurfaceOrigin* origin) const {
|
||||
return GrBackendTexture(); // invalid
|
||||
|
@ -46,6 +46,27 @@ public:
|
||||
virtual bool onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
|
||||
int srcX, int srcY, CachingHint) const = 0;
|
||||
|
||||
/**
|
||||
* Default implementation does a rescale/read and then calls the callback.
|
||||
*/
|
||||
virtual void onAsyncRescaleAndReadPixels(const SkImageInfo&,
|
||||
const SkIRect& srcRect,
|
||||
RescaleGamma,
|
||||
SkFilterQuality,
|
||||
ReadPixelsCallback,
|
||||
ReadPixelsContext);
|
||||
/**
|
||||
* Default implementation does a rescale/read/yuv conversion and then calls the callback.
|
||||
*/
|
||||
virtual void onAsyncRescaleAndReadPixelsYUV420(SkYUVColorSpace,
|
||||
sk_sp<SkColorSpace> dstColorSpace,
|
||||
const SkIRect& srcRect,
|
||||
const SkISize& dstSize,
|
||||
RescaleGamma,
|
||||
SkFilterQuality,
|
||||
ReadPixelsCallback,
|
||||
ReadPixelsContext);
|
||||
|
||||
virtual GrContext* context() const { return nullptr; }
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
|
@ -123,6 +123,47 @@ sk_sp<SkImage> SkImage_Gpu::onReinterpretColorSpace(sk_sp<SkColorSpace> newCS) c
|
||||
this->alphaType(), std::move(newCS));
|
||||
}
|
||||
|
||||
void SkImage_Gpu::onAsyncRescaleAndReadPixels(const SkImageInfo& info,
|
||||
const SkIRect& srcRect,
|
||||
RescaleGamma rescaleGamma,
|
||||
SkFilterQuality rescaleQuality,
|
||||
ReadPixelsCallback callback,
|
||||
ReadPixelsContext context) {
|
||||
GrColorType ct = SkColorTypeToGrColorType(this->colorType());
|
||||
auto ctx = GrSurfaceContext::Make(fContext.get(), fView, ct, this->alphaType(),
|
||||
this->refColorSpace());
|
||||
if (!ctx) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
ctx->asyncRescaleAndReadPixels(info, srcRect, rescaleGamma, rescaleQuality, callback, context);
|
||||
}
|
||||
|
||||
void SkImage_Gpu::onAsyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,
|
||||
sk_sp<SkColorSpace> dstColorSpace,
|
||||
const SkIRect& srcRect,
|
||||
const SkISize& dstSize,
|
||||
RescaleGamma rescaleGamma,
|
||||
SkFilterQuality rescaleQuality,
|
||||
ReadPixelsCallback callback,
|
||||
ReadPixelsContext context) {
|
||||
GrColorType ct = SkColorTypeToGrColorType(this->colorType());
|
||||
auto ctx = GrSurfaceContext::Make(fContext.get(), fView, ct, this->alphaType(),
|
||||
this->refColorSpace());
|
||||
if (!ctx) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
ctx->asyncRescaleAndReadPixelsYUV420(yuvColorSpace,
|
||||
std::move(dstColorSpace),
|
||||
srcRect,
|
||||
dstSize,
|
||||
rescaleGamma,
|
||||
rescaleQuality,
|
||||
callback,
|
||||
context);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static sk_sp<SkImage> new_wrapped_texture_common(GrContext* ctx,
|
||||
|
@ -50,6 +50,22 @@ public:
|
||||
|
||||
sk_sp<SkImage> onReinterpretColorSpace(sk_sp<SkColorSpace>) const final;
|
||||
|
||||
void onAsyncRescaleAndReadPixels(const SkImageInfo&,
|
||||
const SkIRect& srcRect,
|
||||
RescaleGamma,
|
||||
SkFilterQuality,
|
||||
ReadPixelsCallback,
|
||||
ReadPixelsContext) override;
|
||||
|
||||
void onAsyncRescaleAndReadPixelsYUV420(SkYUVColorSpace,
|
||||
sk_sp<SkColorSpace>,
|
||||
const SkIRect& srcRect,
|
||||
const SkISize& dstSize,
|
||||
RescaleGamma,
|
||||
SkFilterQuality,
|
||||
ReadPixelsCallback,
|
||||
ReadPixelsContext) override;
|
||||
|
||||
/**
|
||||
* This is the implementation of SkDeferredDisplayListRecorder::makePromiseImage.
|
||||
*/
|
||||
|
139
src/image/SkRescaleAndReadPixels.cpp
Normal file
139
src/image/SkRescaleAndReadPixels.cpp
Normal file
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* 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/SkCanvas.h"
|
||||
#include "include/core/SkImageInfo.h"
|
||||
#include "include/core/SkPaint.h"
|
||||
#include "include/core/SkRect.h"
|
||||
#include "include/core/SkSurface.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
void SkRescaleAndReadPixels(SkBitmap bmp,
|
||||
const SkImageInfo& resultInfo,
|
||||
const SkIRect& srcRect,
|
||||
SkImage::RescaleGamma rescaleGamma,
|
||||
SkFilterQuality rescaleQuality,
|
||||
SkImage::ReadPixelsCallback callback,
|
||||
SkImage::ReadPixelsContext context) {
|
||||
int srcW = srcRect.width();
|
||||
int srcH = srcRect.height();
|
||||
|
||||
float sx = (float)resultInfo.width() / srcW;
|
||||
float sy = (float)resultInfo.height() / srcH;
|
||||
// How many bilerp/bicubic steps to do in X and Y. + means upscaling, - means downscaling.
|
||||
int stepsX;
|
||||
int stepsY;
|
||||
if (rescaleQuality > kNone_SkFilterQuality) {
|
||||
stepsX = static_cast<int>((sx > 1.f) ? std::ceil(std::log2f(sx))
|
||||
: std::floor(std::log2f(sx)));
|
||||
stepsY = static_cast<int>((sy > 1.f) ? std::ceil(std::log2f(sy))
|
||||
: std::floor(std::log2f(sy)));
|
||||
} else {
|
||||
stepsX = sx != 1.f;
|
||||
stepsY = sy != 1.f;
|
||||
}
|
||||
|
||||
SkPaint paint;
|
||||
paint.setBlendMode(SkBlendMode::kSrc);
|
||||
if (stepsX < 0 || stepsY < 0) {
|
||||
// Don't trigger MIP generation. We don't currently have a way to trigger bicubic for
|
||||
// downscaling draws.
|
||||
rescaleQuality = std::min(rescaleQuality, kLow_SkFilterQuality);
|
||||
}
|
||||
paint.setFilterQuality(rescaleQuality);
|
||||
sk_sp<SkSurface> tempSurf;
|
||||
sk_sp<SkImage> srcImage;
|
||||
int srcX = srcRect.fLeft;
|
||||
int srcY = srcRect.fTop;
|
||||
SkCanvas::SrcRectConstraint constraint = SkCanvas::kStrict_SrcRectConstraint;
|
||||
// Assume we should ignore the rescale linear request if the surface has no color space since
|
||||
// it's unclear how we'd linearize from an unknown color space.
|
||||
if (rescaleGamma == SkSurface::RescaleGamma::kLinear && bmp.info().colorSpace() &&
|
||||
!bmp.info().colorSpace()->gammaIsLinear()) {
|
||||
auto cs = bmp.info().colorSpace()->makeLinearGamma();
|
||||
// Promote to F16 color type to preserve precision.
|
||||
auto ii = SkImageInfo::Make(srcW, srcH, kRGBA_F16_SkColorType, bmp.info().alphaType(),
|
||||
std::move(cs));
|
||||
auto linearSurf = SkSurface::MakeRaster(ii);
|
||||
if (!linearSurf) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
linearSurf->getCanvas()->drawBitmap(bmp, -srcX, -srcY, &paint);
|
||||
tempSurf = std::move(linearSurf);
|
||||
srcImage = tempSurf->makeImageSnapshot();
|
||||
srcX = 0;
|
||||
srcY = 0;
|
||||
constraint = SkCanvas::kFast_SrcRectConstraint;
|
||||
} else {
|
||||
// MakeFromBitmap would trigger a copy if bmp is mutable.
|
||||
srcImage = SkImage::MakeFromRaster(bmp.pixmap(), nullptr, nullptr);
|
||||
}
|
||||
while (stepsX || stepsY) {
|
||||
int nextW = resultInfo.width();
|
||||
int nextH = resultInfo.height();
|
||||
if (stepsX < 0) {
|
||||
nextW = resultInfo.width() << (-stepsX - 1);
|
||||
stepsX++;
|
||||
} else if (stepsX != 0) {
|
||||
if (stepsX > 1) {
|
||||
nextW = srcW * 2;
|
||||
}
|
||||
--stepsX;
|
||||
}
|
||||
if (stepsY < 0) {
|
||||
nextH = resultInfo.height() << (-stepsY - 1);
|
||||
stepsY++;
|
||||
} else if (stepsY != 0) {
|
||||
if (stepsY > 1) {
|
||||
nextH = srcH * 2;
|
||||
}
|
||||
--stepsY;
|
||||
}
|
||||
auto ii = srcImage->imageInfo().makeWH(nextW, nextH);
|
||||
if (!stepsX && !stepsY) {
|
||||
// Might as well fold conversion to final info in the last step.
|
||||
ii = resultInfo;
|
||||
}
|
||||
auto next = SkSurface::MakeRaster(ii);
|
||||
if (!next) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
next->getCanvas()->drawImageRect(
|
||||
std::move(srcImage), SkIRect::MakeXYWH(srcX, srcY, srcW, srcH),
|
||||
SkRect::MakeWH((float)nextW, (float)nextH), &paint, constraint);
|
||||
tempSurf = std::move(next);
|
||||
srcImage = tempSurf->makeImageSnapshot();
|
||||
srcX = srcY = 0;
|
||||
srcW = nextW;
|
||||
srcH = nextH;
|
||||
constraint = SkCanvas::kFast_SrcRectConstraint;
|
||||
}
|
||||
|
||||
size_t rowBytes = resultInfo.minRowBytes();
|
||||
std::unique_ptr<char[]> data(new char[resultInfo.height() * rowBytes]);
|
||||
SkPixmap pm(resultInfo, data.get(), rowBytes);
|
||||
if (srcImage->readPixels(pm, srcX, srcY)) {
|
||||
class Result : public SkImage::AsyncReadResult {
|
||||
public:
|
||||
Result(std::unique_ptr<const char[]> data, size_t rowBytes)
|
||||
: fData(std::move(data)), fRowBytes(rowBytes) {}
|
||||
int count() const override { return 1; }
|
||||
const void* data(int i) const override { return fData.get(); }
|
||||
size_t rowBytes(int i) const override { return fRowBytes; }
|
||||
|
||||
private:
|
||||
std::unique_ptr<const char[]> fData;
|
||||
size_t fRowBytes;
|
||||
};
|
||||
callback(context, std::make_unique<Result>(std::move(data), rowBytes));
|
||||
} else {
|
||||
callback(context, nullptr);
|
||||
}
|
||||
}
|
22
src/image/SkRescaleAndReadPixels.h
Normal file
22
src/image/SkRescaleAndReadPixels.h
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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/SkBitmap.h"
|
||||
#include "include/core/SkFilterQuality.h"
|
||||
#include "include/core/SkImage.h"
|
||||
|
||||
struct SkImageInfo;
|
||||
struct SkIRect;
|
||||
|
||||
/** Generic/synchronous implementation for SkImage:: and SkSurface::asyncRescaleAndReadPixels. */
|
||||
void SkRescaleAndReadPixels(SkBitmap src,
|
||||
const SkImageInfo& resultInfo,
|
||||
const SkIRect& srcRect,
|
||||
SkImage::RescaleGamma,
|
||||
SkFilterQuality,
|
||||
SkImage::ReadPixelsCallback,
|
||||
SkImage::ReadPixelsContext);
|
@ -12,6 +12,7 @@
|
||||
#include "include/gpu/GrBackendSurface.h"
|
||||
#include "src/core/SkAutoPixmapStorage.h"
|
||||
#include "src/core/SkImagePriv.h"
|
||||
#include "src/image/SkRescaleAndReadPixels.h"
|
||||
#include "src/image/SkSurface_Base.h"
|
||||
|
||||
static SkPixelGeometry compute_default_geometry() {
|
||||
@ -97,126 +98,29 @@ void SkSurface_Base::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPa
|
||||
}
|
||||
}
|
||||
|
||||
void SkSurface_Base::onAsyncRescaleAndReadPixels(const SkImageInfo& info, const SkIRect& srcRect,
|
||||
void SkSurface_Base::onAsyncRescaleAndReadPixels(const SkImageInfo& info,
|
||||
const SkIRect& origSrcRect,
|
||||
SkSurface::RescaleGamma rescaleGamma,
|
||||
SkFilterQuality rescaleQuality,
|
||||
SkSurface::ReadPixelsCallback callback,
|
||||
SkSurface::ReadPixelsContext context) {
|
||||
int srcW = srcRect.width();
|
||||
int srcH = srcRect.height();
|
||||
float sx = (float)info.width() / srcW;
|
||||
float sy = (float)info.height() / srcH;
|
||||
// How many bilerp/bicubic steps to do in X and Y. + means upscaling, - means downscaling.
|
||||
int stepsX;
|
||||
int stepsY;
|
||||
if (rescaleQuality > kNone_SkFilterQuality) {
|
||||
stepsX = static_cast<int>((sx > 1.f) ? std::ceil(std::log2f(sx))
|
||||
: std::floor(std::log2f(sx)));
|
||||
stepsY = static_cast<int>((sy > 1.f) ? std::ceil(std::log2f(sy))
|
||||
: std::floor(std::log2f(sy)));
|
||||
SkBitmap src;
|
||||
SkPixmap peek;
|
||||
SkIRect srcRect;
|
||||
if (this->peekPixels(&peek)) {
|
||||
src.installPixels(peek);
|
||||
srcRect = origSrcRect;
|
||||
} else {
|
||||
stepsX = sx != 1.f;
|
||||
stepsY = sy != 1.f;
|
||||
}
|
||||
|
||||
SkPaint paint;
|
||||
paint.setBlendMode(SkBlendMode::kSrc);
|
||||
if (stepsX < 0 || stepsY < 0) {
|
||||
// Don't trigger MIP generation. We don't currently have a way to trigger bicubic for
|
||||
// downscaling draws.
|
||||
rescaleQuality = std::min(rescaleQuality, kLow_SkFilterQuality);
|
||||
}
|
||||
paint.setFilterQuality(rescaleQuality);
|
||||
sk_sp<SkSurface> src(SkRef(this));
|
||||
int srcX = srcRect.fLeft;
|
||||
int srcY = srcRect.fTop;
|
||||
SkCanvas::SrcRectConstraint constraint = SkCanvas::kStrict_SrcRectConstraint;
|
||||
// Assume we should ignore the rescale linear request if the surface has no color space since
|
||||
// it's unclear how we'd linearize from an unknown color space.
|
||||
if (rescaleGamma == SkSurface::RescaleGamma::kLinear &&
|
||||
this->getCanvas()->imageInfo().colorSpace() &&
|
||||
!this->getCanvas()->imageInfo().colorSpace()->gammaIsLinear()) {
|
||||
auto cs = this->getCanvas()->imageInfo().colorSpace()->makeLinearGamma();
|
||||
// Promote to F16 color type to preserve precision.
|
||||
auto ii = SkImageInfo::Make(srcW, srcH, kRGBA_F16_SkColorType,
|
||||
this->getCanvas()->imageInfo().alphaType(), std::move(cs));
|
||||
auto linearSurf = this->makeSurface(ii);
|
||||
if (!linearSurf) {
|
||||
// Maybe F16 isn't supported? Try again with original color type.
|
||||
ii = ii.makeColorType(this->getCanvas()->imageInfo().colorType());
|
||||
linearSurf = this->makeSurface(ii);
|
||||
if (!linearSurf) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
this->draw(linearSurf->getCanvas(), -srcX, -srcY, &paint);
|
||||
src = std::move(linearSurf);
|
||||
srcX = 0;
|
||||
srcY = 0;
|
||||
constraint = SkCanvas::kFast_SrcRectConstraint;
|
||||
}
|
||||
while (stepsX || stepsY) {
|
||||
int nextW = info.width();
|
||||
int nextH = info.height();
|
||||
if (stepsX < 0) {
|
||||
nextW = info.width() << (-stepsX - 1);
|
||||
stepsX++;
|
||||
} else if (stepsX != 0) {
|
||||
if (stepsX > 1) {
|
||||
nextW = srcW * 2;
|
||||
}
|
||||
--stepsX;
|
||||
}
|
||||
if (stepsY < 0) {
|
||||
nextH = info.height() << (-stepsY - 1);
|
||||
stepsY++;
|
||||
} else if (stepsY != 0) {
|
||||
if (stepsY > 1) {
|
||||
nextH = srcH * 2;
|
||||
}
|
||||
--stepsY;
|
||||
}
|
||||
auto ii = src->getCanvas()->imageInfo().makeWH(nextW, nextH);
|
||||
if (!stepsX && !stepsY) {
|
||||
// Might as well fold conversion to final info in the last step.
|
||||
ii = info;
|
||||
}
|
||||
auto next = this->makeSurface(ii);
|
||||
if (!next) {
|
||||
src.setInfo(this->imageInfo().makeDimensions(origSrcRect.size()));
|
||||
src.allocPixels();
|
||||
if (!this->readPixels(src, origSrcRect.x(), origSrcRect.y())) {
|
||||
callback(context, nullptr);
|
||||
return;
|
||||
}
|
||||
next->getCanvas()->drawImageRect(
|
||||
src->makeImageSnapshot(), SkIRect::MakeXYWH(srcX, srcY, srcW, srcH),
|
||||
SkRect::MakeWH((float)nextW, (float)nextH), &paint, constraint);
|
||||
src = std::move(next);
|
||||
srcX = srcY = 0;
|
||||
srcW = nextW;
|
||||
srcH = nextH;
|
||||
constraint = SkCanvas::kFast_SrcRectConstraint;
|
||||
}
|
||||
|
||||
size_t rowBytes = info.minRowBytes();
|
||||
std::unique_ptr<char[]> data(new char[info.height() * rowBytes]);
|
||||
SkPixmap pm(info, data.get(), rowBytes);
|
||||
if (src->readPixels(pm, srcX, srcY)) {
|
||||
class Result : public AsyncReadResult {
|
||||
public:
|
||||
Result(std::unique_ptr<const char[]> data, size_t rowBytes)
|
||||
: fData(std::move(data)), fRowBytes(rowBytes) {}
|
||||
int count() const override { return 1; }
|
||||
const void* data(int i) const override { return fData.get(); }
|
||||
size_t rowBytes(int i) const override { return fRowBytes; }
|
||||
|
||||
private:
|
||||
std::unique_ptr<const char[]> fData;
|
||||
size_t fRowBytes;
|
||||
};
|
||||
callback(context, std::make_unique<Result>(std::move(data), rowBytes));
|
||||
} else {
|
||||
callback(context, nullptr);
|
||||
srcRect = SkIRect::MakeSize(src.dimensions());
|
||||
}
|
||||
return SkRescaleAndReadPixels(src, info, srcRect, rescaleGamma, rescaleQuality, callback,
|
||||
context);
|
||||
}
|
||||
|
||||
void SkSurface_Base::onAsyncRescaleAndReadPixelsYUV420(
|
||||
|
@ -5,8 +5,8 @@
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <initializer_list>
|
||||
#include "include/core/SkCanvas.h"
|
||||
#include "include/core/SkImage.h"
|
||||
#include "include/core/SkSurface.h"
|
||||
#include "include/effects/SkGradientShader.h"
|
||||
#include "include/gpu/GrContext.h"
|
||||
@ -23,9 +23,12 @@
|
||||
#include "tests/Test.h"
|
||||
#include "tests/TestUtils.h"
|
||||
#include "tools/ToolUtils.h"
|
||||
#include "tools/gpu/BackendTextureImageFactory.h"
|
||||
#include "tools/gpu/GrContextFactory.h"
|
||||
#include "tools/gpu/ProxyUtils.h"
|
||||
|
||||
#include <initializer_list>
|
||||
|
||||
static const int DEV_W = 100, DEV_H = 100;
|
||||
static const SkIRect DEV_RECT = SkIRect::MakeWH(DEV_W, DEV_H);
|
||||
static const SkRect DEV_RECT_S = SkRect::MakeWH(DEV_W * SK_Scalar1,
|
||||
@ -647,8 +650,15 @@ struct GpuReadPixelTestRules {
|
||||
// the pixmap.
|
||||
template <typename T> using GpuSrcFactory = T(SkPixmap&);
|
||||
|
||||
enum class GpuReadResult {
|
||||
kFail,
|
||||
kSuccess,
|
||||
kExcusedFailure,
|
||||
};
|
||||
|
||||
// Does a read from the T into the pixmap.
|
||||
template <typename T> using GpuReadSrcFn = bool(const T&, const SkIVector& offset, const SkPixmap&);
|
||||
template <typename T>
|
||||
using GpuReadSrcFn = GpuReadResult(const T&, const SkIVector& offset, const SkPixmap&);
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
@ -685,19 +695,19 @@ static void gpu_read_pixels_test_driver(skiatest::Reporter* reporter,
|
||||
dstPixels.computeByteSize(),
|
||||
kInitialByte);
|
||||
|
||||
const bool success = read(src, offset, dstPixels);
|
||||
const GpuReadResult result = read(src, offset, dstPixels);
|
||||
|
||||
if (!SkIRect::Intersects(rect, surfBounds)) {
|
||||
REPORTER_ASSERT(reporter, !success);
|
||||
REPORTER_ASSERT(reporter, result != GpuReadResult::kSuccess);
|
||||
} else if (readCT == kUnknown_SkColorType) {
|
||||
REPORTER_ASSERT(reporter, !success);
|
||||
REPORTER_ASSERT(reporter, result != GpuReadResult::kSuccess);
|
||||
} else if (readAT == kUnknown_SkAlphaType) {
|
||||
REPORTER_ASSERT(reporter, !success);
|
||||
REPORTER_ASSERT(reporter, result != GpuReadResult::kSuccess);
|
||||
} else if (!rules.fUncontainedRectSucceeds && !surfBounds.contains(rect)) {
|
||||
REPORTER_ASSERT(reporter, !success);
|
||||
REPORTER_ASSERT(reporter, result != GpuReadResult::kSuccess);
|
||||
} else if (!rules.fAllowUnpremulRead && readAT == kUnpremul_SkAlphaType) {
|
||||
REPORTER_ASSERT(reporter, !success);
|
||||
} else if (!success) {
|
||||
REPORTER_ASSERT(reporter, result != GpuReadResult::kSuccess);
|
||||
} else if (result == GpuReadResult::kFail) {
|
||||
// TODO: Support RGB/BGR 101010x, BGRA 1010102 on the GPU.
|
||||
if (SkColorTypeToGrColorType(readCT) != GrColorType::kUnknown) {
|
||||
ERRORF(reporter,
|
||||
@ -716,7 +726,7 @@ static void gpu_read_pixels_test_driver(skiatest::Reporter* reporter,
|
||||
// Considering the rect we tried to read and the surface bounds figure out which pixels in
|
||||
// both src and dst space should actually have been read and written.
|
||||
SkIRect srcReadRect;
|
||||
if (success && srcReadRect.intersect(surfBounds, rect)) {
|
||||
if (result == GpuReadResult::kSuccess && srcReadRect.intersect(surfBounds, rect)) {
|
||||
SkIRect dstWriteRect = srcReadRect.makeOffset(-rect.fLeft, -rect.fTop);
|
||||
|
||||
const bool lumConversion =
|
||||
@ -724,18 +734,19 @@ static void gpu_read_pixels_test_driver(skiatest::Reporter* reporter,
|
||||
(SkColorTypeChannelFlags(readCT) & kGray_SkColorChannelFlag);
|
||||
// A CS or luminance conversion allows a 3 value difference and otherwise a 2 value
|
||||
// difference. Note that sometimes read back on GPU can be lossy even when there no
|
||||
// conversion at allbecause GPU->CPU read may go to a lower bit depth format and then be
|
||||
// promoted back to the original type. For example, GL ES cannot read to 1010102, so we
|
||||
// go through 8888.
|
||||
// conversion at all because GPU->CPU read may go to a lower bit depth format and then
|
||||
// be promoted back to the original type. For example, GL ES cannot read to 1010102, so
|
||||
// we go through 8888.
|
||||
const float numer = (lumConversion || csConversion) ? 3.f : 2.f;
|
||||
int rgbBits = std::min({min_rgb_channel_bits(readCT),
|
||||
min_rgb_channel_bits(srcCT),
|
||||
8});
|
||||
int rgbBits = std::min(
|
||||
{min_rgb_channel_bits(readCT), min_rgb_channel_bits(srcCT), 8});
|
||||
float tol = numer / (1 << rgbBits);
|
||||
float alphaTol = 0;
|
||||
if (readAT != kOpaque_SkAlphaType && srcAT != kOpaque_SkAlphaType) {
|
||||
const int alphaBits = std::min(alpha_channel_bits(readCT),
|
||||
alpha_channel_bits(srcCT));
|
||||
// Alpha can also get squashed down to 8 bits going through an intermediate
|
||||
// color format.
|
||||
const int alphaBits =
|
||||
std::min({alpha_channel_bits(readCT), alpha_channel_bits(srcCT), 8});
|
||||
alphaTol = 2.f / (1 << alphaBits);
|
||||
}
|
||||
|
||||
@ -924,20 +935,20 @@ static void gpu_read_pixels_test_driver(skiatest::Reporter* reporter,
|
||||
namespace {
|
||||
struct AsyncContext {
|
||||
bool fCalled = false;
|
||||
std::unique_ptr<const SkSurface::AsyncReadResult> fResult;
|
||||
std::unique_ptr<const SkImage::AsyncReadResult> fResult;
|
||||
};
|
||||
} // anonymous namespace
|
||||
|
||||
// Making this a lambda in the test functions caused:
|
||||
// "error: cannot compile this forwarded non-trivially copyable parameter yet"
|
||||
// on x86/Win/Clang bot, referring to 'result'.
|
||||
static void async_callback(void* c, std::unique_ptr<const SkSurface::AsyncReadResult> result) {
|
||||
static void async_callback(void* c, std::unique_ptr<const SkImage::AsyncReadResult> result) {
|
||||
auto context = static_cast<AsyncContext*>(c);
|
||||
context->fResult = std::move(result);
|
||||
context->fCalled = true;
|
||||
};
|
||||
|
||||
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(AsyncReadPixels, reporter, ctxInfo) {
|
||||
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceAsyncReadPixels, reporter, ctxInfo) {
|
||||
using Surface = sk_sp<SkSurface>;
|
||||
auto reader = std::function<GpuReadSrcFn<Surface>>([](const Surface& surface,
|
||||
const SkIVector& offset,
|
||||
@ -946,18 +957,18 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(AsyncReadPixels, reporter, ctxInfo) {
|
||||
auto rect = SkIRect::MakeSize(pixels.dimensions()).makeOffset(offset);
|
||||
|
||||
// Rescale quality and linearity don't matter since we're doing a non-scaling readback.
|
||||
surface->asyncRescaleAndReadPixels(pixels.info(), rect, SkSurface::RescaleGamma::kSrc,
|
||||
surface->asyncRescaleAndReadPixels(pixels.info(), rect, SkImage::RescaleGamma::kSrc,
|
||||
kNone_SkFilterQuality, async_callback, &context);
|
||||
surface->getContext()->submit();
|
||||
while (!context.fCalled) {
|
||||
surface->getCanvas()->getGrContext()->checkAsyncWorkCompletion();
|
||||
}
|
||||
if (!context.fResult) {
|
||||
return false;
|
||||
return GpuReadResult::kFail;
|
||||
}
|
||||
SkRectMemcpy(pixels.writable_addr(), pixels.rowBytes(), context.fResult->data(0),
|
||||
context.fResult->rowBytes(0), pixels.info().minRowBytes(), pixels.height());
|
||||
return true;
|
||||
return GpuReadResult::kSuccess;
|
||||
});
|
||||
GpuReadPixelTestRules rules;
|
||||
rules.fAllowUnpremulSrc = false;
|
||||
@ -981,11 +992,65 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(AsyncReadPixels, reporter, ctxInfo) {
|
||||
}
|
||||
}
|
||||
|
||||
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageAsyncReadPixels, reporter, ctxInfo) {
|
||||
using Image = sk_sp<SkImage>;
|
||||
GrContext* context = ctxInfo.grContext();
|
||||
auto reader = std::function<GpuReadSrcFn<Image>>([context](const Image& image,
|
||||
const SkIVector& offset,
|
||||
const SkPixmap& pixels) {
|
||||
AsyncContext asyncContext;
|
||||
auto rect = SkIRect::MakeSize(pixels.dimensions()).makeOffset(offset);
|
||||
// The GPU implementation is based on rendering and will fail for non-renderable color
|
||||
// types.
|
||||
auto ct = SkColorTypeToGrColorType(image->colorType());
|
||||
auto format = context->priv().caps()->getDefaultBackendFormat(ct, GrRenderable::kYes);
|
||||
if (!context->priv().caps()->isFormatAsColorTypeRenderable(ct, format)) {
|
||||
return GpuReadResult::kExcusedFailure;
|
||||
}
|
||||
|
||||
// Rescale quality and linearity don't matter since we're doing a non-scaling readback.
|
||||
image->asyncRescaleAndReadPixels(pixels.info(), rect, SkImage::RescaleGamma::kSrc,
|
||||
kNone_SkFilterQuality, async_callback, &asyncContext);
|
||||
context->submit();
|
||||
while (!asyncContext.fCalled) {
|
||||
context->checkAsyncWorkCompletion();
|
||||
}
|
||||
if (!asyncContext.fResult) {
|
||||
return GpuReadResult::kFail;
|
||||
}
|
||||
SkRectMemcpy(pixels.writable_addr(), pixels.rowBytes(), asyncContext.fResult->data(0),
|
||||
asyncContext.fResult->rowBytes(0), pixels.info().minRowBytes(),
|
||||
pixels.height());
|
||||
return GpuReadResult::kSuccess;
|
||||
});
|
||||
|
||||
GpuReadPixelTestRules rules;
|
||||
rules.fAllowUnpremulSrc = true;
|
||||
// GPU doesn't support reading to kUnpremul because the rescaling works by rendering and now
|
||||
// we only support premul rendering.
|
||||
rules.fAllowUnpremulRead = false;
|
||||
rules.fUncontainedRectSucceeds = false;
|
||||
|
||||
for (auto origin : {kTopLeft_GrSurfaceOrigin, kBottomLeft_GrSurfaceOrigin}) {
|
||||
for (auto renderable : {GrRenderable::kNo, GrRenderable::kYes}) {
|
||||
auto factory = std::function<GpuSrcFactory<Image>>([&](const SkPixmap& src) {
|
||||
if (src.colorType() == kRGB_888x_SkColorType) {
|
||||
return Image();
|
||||
}
|
||||
return sk_gpu_test::MakeBackendTextureImage(ctxInfo.grContext(), src, renderable,
|
||||
origin);
|
||||
});
|
||||
gpu_read_pixels_test_driver(reporter, rules, factory, reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ReadPixels_Gpu, reporter, ctxInfo) {
|
||||
using Surface = sk_sp<SkSurface>;
|
||||
auto reader = std::function<GpuReadSrcFn<Surface>>(
|
||||
[](const Surface& surface, const SkIVector& offset, const SkPixmap& pixels) {
|
||||
return surface->readPixels(pixels, offset.fX, offset.fY);
|
||||
return surface->readPixels(pixels, offset.fX, offset.fY) ? GpuReadResult::kSuccess
|
||||
: GpuReadResult::kFail;
|
||||
});
|
||||
GpuReadPixelTestRules rules;
|
||||
rules.fAllowUnpremulSrc = false;
|
||||
@ -1062,10 +1127,10 @@ DEF_GPUTEST(AsyncReadPixelsContextShutdown, reporter, options) {
|
||||
if (yuv) {
|
||||
surf->asyncRescaleAndReadPixelsYUV420(
|
||||
kIdentity_SkYUVColorSpace, SkColorSpace::MakeSRGB(), ii.bounds(),
|
||||
ii.dimensions(), SkSurface::RescaleGamma::kSrc, kNone_SkFilterQuality,
|
||||
ii.dimensions(), SkImage::RescaleGamma::kSrc, kNone_SkFilterQuality,
|
||||
&async_callback, &cbContext);
|
||||
} else {
|
||||
surf->asyncRescaleAndReadPixels(ii, ii.bounds(), SkSurface::RescaleGamma::kSrc,
|
||||
surf->asyncRescaleAndReadPixels(ii, ii.bounds(), SkImage::RescaleGamma::kSrc,
|
||||
kNone_SkFilterQuality, &async_callback,
|
||||
&cbContext);
|
||||
}
|
||||
|
83
tools/gpu/BackendTextureImageFactory.cpp
Normal file
83
tools/gpu/BackendTextureImageFactory.cpp
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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 "tools/gpu/BackendTextureImageFactory.h"
|
||||
|
||||
#include "include/core/SkImage.h"
|
||||
#include "include/core/SkPixmap.h"
|
||||
#include "include/gpu/GrBackendSurface.h"
|
||||
#include "include/gpu/GrContext.h"
|
||||
#include "src/core/SkAutoPixmapStorage.h"
|
||||
|
||||
namespace {
|
||||
class ManagedBackendTexture : public SkNVRefCnt<ManagedBackendTexture> {
|
||||
public:
|
||||
~ManagedBackendTexture() {
|
||||
if (fContext && fTexture.isValid()) {
|
||||
fContext->submit(true);
|
||||
fContext->deleteBackendTexture(fTexture);
|
||||
}
|
||||
}
|
||||
|
||||
static void Proc(void* context) { static_cast<ManagedBackendTexture*>(context)->unref(); }
|
||||
|
||||
template <typename... Args>
|
||||
static sk_sp<ManagedBackendTexture> Make(GrContext* context, Args&&... args) {
|
||||
sk_sp<ManagedBackendTexture> mbet(new ManagedBackendTexture);
|
||||
mbet->fContext = context;
|
||||
mbet->fTexture = context->createBackendTexture(std::forward<Args>(args)...,
|
||||
Proc,
|
||||
mbet->refAndPassAsContext());
|
||||
return mbet;
|
||||
}
|
||||
|
||||
const GrBackendTexture& texture() { return fTexture; }
|
||||
|
||||
void* refAndPassAsContext() {
|
||||
this->ref();
|
||||
return static_cast<void*>(this);
|
||||
}
|
||||
|
||||
private:
|
||||
ManagedBackendTexture() = default;
|
||||
GrContext* fContext = nullptr;
|
||||
GrBackendTexture fTexture;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace sk_gpu_test {
|
||||
sk_sp<SkImage> MakeBackendTextureImage(GrContext* context,
|
||||
const SkPixmap& pixmap,
|
||||
GrRenderable renderable,
|
||||
GrSurfaceOrigin origin) {
|
||||
const SkPixmap* src = &pixmap;
|
||||
SkAutoPixmapStorage temp;
|
||||
if (origin == kBottomLeft_GrSurfaceOrigin) {
|
||||
temp.alloc(src->info());
|
||||
auto s = static_cast<const char*>(src->addr(0, pixmap.height() - 1));
|
||||
auto d = static_cast<char*>(temp.writable_addr(0, 0));
|
||||
for (int y = 0; y < temp.height(); ++y, s -= pixmap.rowBytes(), d += temp.rowBytes()) {
|
||||
std::copy_n(s, temp.info().minRowBytes(), d);
|
||||
}
|
||||
src = &temp;
|
||||
}
|
||||
auto mbet = ManagedBackendTexture::Make(context, src, 1, renderable, GrProtected::kNo);
|
||||
auto image = SkImage::MakeFromTexture(context, mbet->texture(), origin, src->colorType(),
|
||||
src->alphaType(), src->refColorSpace(),
|
||||
ManagedBackendTexture::Proc, mbet->refAndPassAsContext());
|
||||
// We currently have an issue where depending on how MakeFromTexture fails it may not
|
||||
// call the release proc (to be fixed soon, crbug.com/1097484). For now we use this hack
|
||||
// to see if it failed without calling Proc.
|
||||
if (!image) {
|
||||
context->submit(true);
|
||||
if (!mbet->unique()) {
|
||||
ManagedBackendTexture::Proc(mbet.get());
|
||||
}
|
||||
}
|
||||
return image;
|
||||
}
|
||||
} // namespace sk_gpu_test
|
24
tools/gpu/BackendTextureImageFactory.h
Normal file
24
tools/gpu/BackendTextureImageFactory.h
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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/SkRefCnt.h"
|
||||
#include "include/gpu/GrTypes.h"
|
||||
|
||||
class GrContext;
|
||||
class SkImage;
|
||||
class SkPixmap;
|
||||
|
||||
namespace sk_gpu_test {
|
||||
/**
|
||||
* Creates a backend texture with pixmap contents and wraps it in a SkImage that safely deletes
|
||||
* the texture when it goes away. Unlike using makeTextureImage() on a non-GPU image, this will
|
||||
* fail rather than fallback if the pixmaps's color type doesn't map to a supported texture format.
|
||||
* For testing purposes the texture can be made renderable to exercise different code paths for
|
||||
* renderable textures/formats.
|
||||
*/
|
||||
sk_sp<SkImage> MakeBackendTextureImage(GrContext*, const SkPixmap&, GrRenderable, GrSurfaceOrigin);
|
||||
} // namespace sk_gpu_test
|
Loading…
Reference in New Issue
Block a user