[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());
+}