1 /*
2 * Copyright 2019 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "tests/Test.h"
9
10 #include <chrono>
11 #include "include/core/SkSurface.h"
12 #include "include/gpu/GrContext.h"
13 #include "src/gpu/GrContextPriv.h"
14 #include "src/gpu/GrGpu.h"
15
16 using namespace sk_gpu_test;
17
testing_finished_proc(void * ctx)18 static void testing_finished_proc(void* ctx) {
19 int* count = (int*)ctx;
20 *count += 1;
21 }
22
busy_wait_for_callback(int * count,int expectedValue,GrContext * ctx,skiatest::Reporter * reporter)23 static void busy_wait_for_callback(int* count, int expectedValue, GrContext* ctx,
24 skiatest::Reporter* reporter) {
25 // Busy waiting should detect that the work is done.
26 auto begin = std::chrono::steady_clock::now();
27 auto end = begin;
28 do {
29 ctx->checkAsyncWorkCompletion();
30 end = std::chrono::steady_clock::now();
31 } while (*count != expectedValue && (end - begin) < std::chrono::seconds(1));
32 if (*count != expectedValue) {
33 ERRORF(reporter, "Expected count failed to reach %d within 1 second of busy waiting.",
34 expectedValue);
35 }
36 }
37
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(FlushFinishedProcTest,reporter,ctxInfo)38 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(FlushFinishedProcTest, reporter, ctxInfo) {
39 GrContext* ctx = ctxInfo.grContext();
40
41 SkImageInfo info =
42 SkImageInfo::Make(8, 8, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
43 sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info);
44 SkCanvas* canvas = surface->getCanvas();
45
46 canvas->clear(SK_ColorGREEN);
47 auto image = surface->makeImageSnapshot();
48
49 GrFlushInfo flushInfoSyncCpu;
50 flushInfoSyncCpu.fFlags = kSyncCpu_GrFlushFlag;
51 ctx->flush(flushInfoSyncCpu);
52
53 int count = 0;
54
55 GrFlushInfo flushInfoFinishedProc;
56 flushInfoFinishedProc.fFinishedProc = testing_finished_proc;
57 flushInfoFinishedProc.fFinishedContext = (void*)&count;
58 // There is no work on the surface so flushing may immediately call the finished proc.
59 surface->flush(SkSurface::BackendSurfaceAccess::kNoAccess, flushInfoFinishedProc);
60 REPORTER_ASSERT(reporter, count == 0 || count == 1);
61 // Busy waiting should detect that the work is done.
62 busy_wait_for_callback(&count, 1, ctx, reporter);
63
64 canvas->clear(SK_ColorRED);
65
66 surface->flush(SkSurface::BackendSurfaceAccess::kNoAccess, flushInfoFinishedProc);
67
68 bool expectAsyncCallback =
69 ctx->backend() == GrBackendApi::kVulkan ||
70 ((ctx->backend() == GrBackendApi::kOpenGL) && ctx->priv().caps()->fenceSyncSupport());
71 if (expectAsyncCallback) {
72 // On Vulkan the command buffer we just submitted may or may not have finished immediately
73 // so the finish proc may not have been called.
74 REPORTER_ASSERT(reporter, count == 1 || count == 2);
75 } else {
76 REPORTER_ASSERT(reporter, count == 2);
77 }
78 ctx->flush(flushInfoSyncCpu);
79 REPORTER_ASSERT(reporter, count == 2);
80
81 // Test flushing via the SkImage
82 canvas->drawImage(image, 0, 0);
83 image->flush(ctx, flushInfoFinishedProc);
84 if (expectAsyncCallback) {
85 // On Vulkan the command buffer we just submitted may or may not have finished immediately
86 // so the finish proc may not have been called.
87 REPORTER_ASSERT(reporter, count == 2 || count == 3);
88 } else {
89 REPORTER_ASSERT(reporter, count == 3);
90 }
91 ctx->flush(flushInfoSyncCpu);
92 REPORTER_ASSERT(reporter, count == 3);
93
94 // Test flushing via the GrContext
95 canvas->clear(SK_ColorBLUE);
96 ctx->flush(flushInfoFinishedProc);
97 if (expectAsyncCallback) {
98 // On Vulkan the command buffer we just submitted may or may not have finished immediately
99 // so the finish proc may not have been called.
100 REPORTER_ASSERT(reporter, count == 3 || count == 4);
101 } else {
102 REPORTER_ASSERT(reporter, count == 4);
103 }
104 ctx->flush(flushInfoSyncCpu);
105 REPORTER_ASSERT(reporter, count == 4);
106
107 // There is no work on the surface so flushing may immediately call the finished proc.
108 ctx->flush(flushInfoFinishedProc);
109 REPORTER_ASSERT(reporter, count == 4 || count == 5);
110 busy_wait_for_callback(&count, 5, ctx, reporter);
111
112 count = 0;
113 int count2 = 0;
114 canvas->clear(SK_ColorGREEN);
115 surface->flush(SkSurface::BackendSurfaceAccess::kNoAccess, flushInfoFinishedProc);
116 // There is no work to be flushed here so this will return immediately, but make sure the
117 // finished call from this proc isn't called till the previous surface flush also is finished.
118 flushInfoFinishedProc.fFinishedContext = (void*)&count2;
119 ctx->flush(flushInfoFinishedProc);
120 REPORTER_ASSERT(reporter, count <= 1 && count2 <= count);
121
122 ctx->flush(flushInfoSyncCpu);
123
124 REPORTER_ASSERT(reporter, count == 1);
125 REPORTER_ASSERT(reporter, count == count2);
126 }
127
128