blob: 49aa6fec2466ce2e06185d2e6399d797914123cf [file] [log] [blame]
/*
* Copyright 2022 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "tests/Test.h"
#include "include/core/SkBitmap.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkPixmap.h"
#include "include/gpu/graphite/Context.h"
#include "include/gpu/graphite/Recorder.h"
#include "include/gpu/graphite/Recording.h"
#include "include/gpu/graphite/Surface.h"
#include "src/gpu/graphite/Surface_Graphite.h"
namespace skgpu::graphite {
using DrawCallback = std::function<void(SkCanvas*)>;
struct Expectation {
int fX;
int fY;
SkColor4f fColor;
};
void run_test(skiatest::Reporter* reporter,
Context* context,
SkISize surfaceSize,
SkISize recordingSize,
SkISize replayOffset,
DrawCallback draw,
const std::vector<Expectation>& expectations) {
const SkImageInfo surfaceImageInfo = SkImageInfo::Make(
surfaceSize, SkColorType::kRGBA_8888_SkColorType, SkAlphaType::kPremul_SkAlphaType);
std::unique_ptr<Recorder> surfaceRecorder = context->makeRecorder();
sk_sp<SkSurface> surface = SkSurfaces::RenderTarget(surfaceRecorder.get(), surfaceImageInfo);
Surface* graphiteSurface = static_cast<Surface*>(surface.get());
const TextureInfo& textureInfo = graphiteSurface->backingTextureProxy()->textureInfo();
// Flush the initial clear added by MakeGraphite.
std::unique_ptr<skgpu::graphite::Recording> surfaceRecording = surfaceRecorder->snap();
context->insertRecording({surfaceRecording.get()});
// Snap a recording without a bound target.
const SkImageInfo recordingImageInfo = surfaceImageInfo.makeDimensions(recordingSize);
std::unique_ptr<Recorder> recorder = context->makeRecorder();
SkCanvas* canvas = recorder->makeDeferredCanvas(recordingImageInfo, textureInfo);
draw(canvas);
// Can't make another canvas before snapping.
REPORTER_ASSERT(reporter,
recorder->makeDeferredCanvas(recordingImageInfo, textureInfo) == nullptr);
std::unique_ptr<Recording> recording = recorder->snap();
// Play back recording.
context->insertRecording(
{recording.get(), surface.get(), {replayOffset.fWidth, replayOffset.fHeight}});
// Read pixels.
SkBitmap bitmap;
SkPixmap pixmap;
bitmap.allocPixels(surfaceImageInfo);
SkAssertResult(bitmap.peekPixels(&pixmap));
if (!surface->readPixels(pixmap, 0, 0)) {
ERRORF(reporter, "readPixels failed");
return;
}
// Veryify expectations are met and recording is uninstantiated.
REPORTER_ASSERT(reporter, !recording->isTargetProxyInstantiated());
for (const Expectation& e : expectations) {
SkColor4f color = pixmap.getColor4f(e.fX, e.fY);
#ifdef SK_DEBUG
if (color != e.fColor) {
SkDebugf("Wrong color\n\texpected: %f %f %f %f\n\tactual: %f %f %f %f",
color.fR,
color.fG,
color.fB,
color.fA,
e.fColor.fR,
e.fColor.fG,
e.fColor.fB,
e.fColor.fA);
}
#endif
REPORTER_ASSERT(reporter, color == e.fColor);
}
}
// Tests that clear does not clear an entire replayed-to surface if recorded onto a smaller surface.
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestClear, reporter, context) {
SkISize surfaceSize = SkISize::Make(8, 4);
SkISize recordingSize = SkISize::Make(4, 4);
SkISize replayOffset = SkISize::Make(0, 0);
auto draw = [](SkCanvas* canvas) { canvas->clear(SkColors::kRed); };
std::vector<Expectation> expectations = {{0, 0, SkColors::kRed},
{4, 0, SkColors::kTransparent}};
run_test(reporter, context, surfaceSize, recordingSize, replayOffset, draw, expectations);
}
// Tests that writePixels is translated correctly when replayed with an offset.
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestWritePixels, reporter, context) {
SkBitmap bitmap;
bitmap.allocN32Pixels(4, 4, true);
SkCanvas bitmapCanvas(bitmap);
SkPaint paint;
paint.setColor(SkColors::kRed);
bitmapCanvas.drawIRect(SkIRect::MakeXYWH(0, 0, 4, 4), paint);
SkISize surfaceSize = SkISize::Make(8, 4);
SkISize recordingSize = SkISize::Make(4, 4);
SkISize replayOffset = SkISize::Make(4, 0);
auto draw = [&bitmap](SkCanvas* canvas) { canvas->writePixels(bitmap, 0, 0); };
std::vector<Expectation> expectations = {{0, 0, SkColors::kTransparent},
{4, 0, SkColors::kRed}};
run_test(reporter, context, surfaceSize, recordingSize, replayOffset, draw, expectations);
}
// Tests that the result of writePixels is cropped correctly when offscreen.
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecordingSurfacesTestWritePixelsOffscreen, reporter, context) {
SkBitmap bitmap;
bitmap.allocN32Pixels(4, 4, true);
SkCanvas bitmapCanvas(bitmap);
SkPaint paint;
paint.setColor(SkColors::kRed);
bitmapCanvas.drawIRect(SkIRect::MakeXYWH(0, 0, 4, 4), paint);
paint.setColor(SkColors::kGreen);
bitmapCanvas.drawIRect(SkIRect::MakeXYWH(2, 2, 2, 2), paint);
SkISize surfaceSize = SkISize::Make(4, 4);
SkISize recordingSize = SkISize::Make(4, 4);
SkISize replayOffset = SkISize::Make(-2, -2);
auto draw = [&bitmap](SkCanvas* canvas) { canvas->writePixels(bitmap, 0, 0); };
std::vector<Expectation> expectations = {{0, 0, SkColors::kGreen}};
run_test(reporter, context, surfaceSize, recordingSize, replayOffset, draw, expectations);
}
} // namespace skgpu::graphite