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