[graphite] Add test for playing recordings regardless of order.
Very simple at the moment -- only checks that text is order-independent.
Bug: b/246953695
Change-Id: Ie0315bbf08a882862fd9395b725525ffe0c49ef4
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/583056
Reviewed-by: Robert Phillips <robertphillips@google.com>
Commit-Queue: Jim Van Verth <jvanverth@google.com>
diff --git a/gn/tests.gni b/gn/tests.gni
index abbc57f..2b7a5f8 100644
--- a/gn/tests.gni
+++ b/gn/tests.gni
@@ -345,6 +345,7 @@
"$_tests/graphite/PipelineDataCacheTest.cpp",
"$_tests/graphite/RTEffectTest.cpp",
"$_tests/graphite/RecorderTest.cpp",
+ "$_tests/graphite/RecordingOrderTest.cpp",
"$_tests/graphite/RectTest.cpp",
"$_tests/graphite/ShapeTest.cpp",
"$_tests/graphite/TransformTest.cpp",
diff --git a/tests/TestUtils.h b/tests/TestUtils.h
index f0c90ef..e08821a 100644
--- a/tests/TestUtils.h
+++ b/tests/TestUtils.h
@@ -10,6 +10,7 @@
#include "include/core/SkBitmap.h"
#include "src/gpu/ganesh/GrDataUtils.h"
+#include "src/gpu/ganesh/GrPixmap.h"
#include "tests/Test.h"
namespace skgpu::v1 { class SurfaceContext; }
@@ -43,8 +44,7 @@
using ComparePixmapsErrorReporter = void(int x, int y, const float diffs[4]);
/**
- * Compares pixels pointed to by 'a' with 'infoA' and rowBytesA to pixels pointed to by 'b' with
- * 'infoB' and 'rowBytesB'.
+ * Compares pixels pointed to by 'a' to pixels pointed to by 'b'.
*
* If the pixmaps have different dimensions error is called with negative coordinate values and
* zero diffs and no comparisons are made.
diff --git a/tests/graphite/RecordingOrderTest.cpp b/tests/graphite/RecordingOrderTest.cpp
new file mode 100644
index 0000000..ab3a5f1
--- /dev/null
+++ b/tests/graphite/RecordingOrderTest.cpp
@@ -0,0 +1,138 @@
+/*
+ * 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/gpu/graphite/Context.h"
+#include "include/gpu/graphite/Recording.h"
+#include "src/gpu/graphite/ContextPriv.h"
+#include "src/gpu/graphite/Surface_Graphite.h"
+#include "tests/TestUtils.h"
+#include "tools/ToolUtils.h"
+
+using namespace skgpu::graphite;
+
+namespace {
+
+const SkISize kSurfaceSize = { 64, 64 };
+
+constexpr SkColor4f kBackgroundColor = SkColors::kWhite;
+
+bool run_test(skiatest::Reporter* reporter,
+ Context* context,
+ Recorder* recorder) {
+ SkImageInfo ii = SkImageInfo::Make(kSurfaceSize, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
+
+ SkBitmap result0, result1;
+ result0.allocPixels(ii);
+ result1.allocPixels(ii);
+ SkPixmap pm0, pm1;
+
+ SkAssertResult(result0.peekPixels(&pm0));
+ SkAssertResult(result1.peekPixels(&pm1));
+
+ sk_sp<SkSurface> surface = SkSurface::MakeGraphite(recorder, ii);
+ if (!surface) {
+ ERRORF(reporter, "Surface creation failed");
+ return false;
+ }
+
+ SkCanvas* canvas = surface->getCanvas();
+
+ // Set up a recording to clear the surface
+ canvas->clear(kBackgroundColor);
+ std::unique_ptr<Recording> clearRecording = recorder->snap();
+ if (!clearRecording) {
+ ERRORF(reporter, "Recording creation failed");
+ return false;
+ }
+
+ // Draw some text and get recording
+ SkPaint paint;
+ paint.setAntiAlias(true);
+
+ SkFont font(ToolUtils::create_portable_typeface("serif", SkFontStyle()));
+ font.setSubpixel(true);
+ font.setSize(12);
+
+ const char* text0 = "Hamburge";
+ const size_t text0Len = strlen(text0);
+
+ canvas->drawSimpleText(text0, text0Len, SkTextEncoding::kUTF8, 3, 20, font, paint);
+ std::unique_ptr<Recording> text0Recording = recorder->snap();
+
+ // Draw some more text and get recording
+ const char* text1 = "burgefons";
+ const size_t text1Len = strlen(text1);
+
+ canvas->drawSimpleText(text1, text1Len, SkTextEncoding::kUTF8, 3, 40, font, paint);
+ std::unique_ptr<Recording> text1Recording = recorder->snap();
+
+ // Playback 0, then 1, and read pixels
+ InsertRecordingInfo info;
+ info.fRecording = clearRecording.get();
+ context->insertRecording(info);
+ info.fRecording = text0Recording.get();
+ context->insertRecording(info);
+ info.fRecording = text1Recording.get();
+ context->insertRecording(info);
+ context->submit();
+
+ // For now, we cast and call directly into Surface. Once we have a better idea of
+ // what the public API for synchronous graphite readPixels we can update this call to use
+ // that instead.
+ if (!static_cast<skgpu::graphite::Surface*>(surface.get())->onReadPixels(context,
+ recorder,
+ pm0,
+ 0,
+ 0)) {
+ ERRORF(reporter, "readPixels failed");
+ return false;
+ }
+
+ // Playback 1, then 0, and read pixels
+ info.fRecording = clearRecording.get();
+ context->insertRecording(info);
+ info.fRecording = text1Recording.get();
+ context->insertRecording(info);
+ info.fRecording = text0Recording.get();
+ context->insertRecording(info);
+ context->submit();
+
+ if (!static_cast<skgpu::graphite::Surface*>(surface.get())->onReadPixels(context,
+ recorder,
+ pm1,
+ 0,
+ 0)) {
+ ERRORF(reporter, "readPixels failed");
+ return false;
+ }
+
+ // Compare and contrast
+ float tol = 1.f/256;
+ const float tols[4] = {tol, tol, tol, tol};
+ auto error = std::function<ComparePixmapsErrorReporter>([&](int x, int y,
+ const float diffs[4]) {
+ SkASSERT(x >= 0 && y >= 0);
+ ERRORF(reporter,
+ "Error at %d, %d. Diff in floats: (%f, %f, %f, %f)",
+ x, y, diffs[0], diffs[1], diffs[2], diffs[3]);
+ });
+ ComparePixels(pm0, pm1, tols, error);
+
+ return true;
+}
+
+} // anonymous namespace
+
+// This test captures two recordings A and B, plays them back as A then B, and B then A,
+// and verifies that the result is the same.
+DEF_GRAPHITE_TEST_FOR_CONTEXTS(RecordingOrderTest_Graphite, reporter, context) {
+ std::unique_ptr<Recorder> recorder = context->makeRecorder();
+
+ (void) run_test(reporter, context, recorder.get());
+}