Greg Daniel | a8d9211 | 2018-03-09 12:05:04 -0500 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2018 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 "Test.h" |
| 9 | |
Greg Daniel | a8d9211 | 2018-03-09 12:05:04 -0500 | [diff] [blame] | 10 | #include "GrBackendSurface.h" |
| 11 | #include "GrContextPriv.h" |
| 12 | #include "GrGpu.h" |
Greg Daniel | a8d9211 | 2018-03-09 12:05:04 -0500 | [diff] [blame] | 13 | #include "SkDeferredDisplayListRecorder.h" |
| 14 | #include "SkImage_Gpu.h" |
| 15 | |
| 16 | using namespace sk_gpu_test; |
| 17 | |
| 18 | struct PromiseTextureChecker { |
| 19 | explicit PromiseTextureChecker(const GrBackendTexture& tex) |
| 20 | : fTexture(tex) |
| 21 | , fFulfillCount(0) |
Greg Daniel | 7278d68 | 2018-03-16 14:57:21 -0400 | [diff] [blame] | 22 | , fReleaseCount(0) |
| 23 | , fDoneCount(0) {} |
Greg Daniel | a8d9211 | 2018-03-09 12:05:04 -0500 | [diff] [blame] | 24 | GrBackendTexture fTexture; |
| 25 | int fFulfillCount; |
| 26 | int fReleaseCount; |
Greg Daniel | 7278d68 | 2018-03-16 14:57:21 -0400 | [diff] [blame] | 27 | int fDoneCount; |
Greg Daniel | a8d9211 | 2018-03-09 12:05:04 -0500 | [diff] [blame] | 28 | static void Fulfill(void* self, GrBackendTexture* outTexture) { |
| 29 | static_cast<PromiseTextureChecker*>(self)->fFulfillCount++; |
| 30 | *outTexture = static_cast<PromiseTextureChecker*>(self)->fTexture; |
| 31 | } |
| 32 | static void Release(void* self) { |
| 33 | static_cast<PromiseTextureChecker*>(self)->fReleaseCount++; |
| 34 | } |
Greg Daniel | 7278d68 | 2018-03-16 14:57:21 -0400 | [diff] [blame] | 35 | static void Done(void* self) { |
| 36 | static_cast<PromiseTextureChecker*>(self)->fDoneCount++; |
| 37 | } |
Greg Daniel | a8d9211 | 2018-03-09 12:05:04 -0500 | [diff] [blame] | 38 | }; |
| 39 | |
| 40 | // Because Vulkan may delay when it actually calls the ReleaseProcs depending on when command |
| 41 | // buffers finish their work, we need some slight wiggle room in what values we expect for fulfill |
| 42 | // and release counts. |
| 43 | static bool check_fulfill_and_release_cnts(const PromiseTextureChecker& promiseChecker, |
| 44 | bool countsMustBeEqual, |
| 45 | int expectedFulfillCnt, |
| 46 | int expectedReleaseCnt, |
| 47 | bool expectedRequired, |
Greg Daniel | 7278d68 | 2018-03-16 14:57:21 -0400 | [diff] [blame] | 48 | int expectedDoneCnt, |
Greg Daniel | a8d9211 | 2018-03-09 12:05:04 -0500 | [diff] [blame] | 49 | skiatest::Reporter* reporter) { |
| 50 | bool result = true; |
| 51 | int countDiff = promiseChecker.fFulfillCount - promiseChecker.fReleaseCount; |
| 52 | // FulfillCount should always equal ReleaseCount or be at most one higher |
| 53 | if (countDiff != 0) { |
| 54 | if (countsMustBeEqual) { |
| 55 | result = false; |
| 56 | REPORTER_ASSERT(reporter, 0 == countDiff); |
| 57 | } else if (countDiff != 1) { |
| 58 | result = false; |
| 59 | REPORTER_ASSERT(reporter, 0 == countDiff || 1 == countDiff); |
| 60 | } |
| 61 | } |
| 62 | |
| 63 | int fulfillDiff = expectedFulfillCnt - promiseChecker.fFulfillCount; |
| 64 | REPORTER_ASSERT(reporter, fulfillDiff >= 0); |
| 65 | if (fulfillDiff != 0) { |
| 66 | if (expectedRequired) { |
| 67 | result = false; |
| 68 | REPORTER_ASSERT(reporter, expectedFulfillCnt == promiseChecker.fFulfillCount); |
| 69 | } else if (fulfillDiff > 1) { |
| 70 | result = false; |
| 71 | REPORTER_ASSERT(reporter, fulfillDiff <= 1); |
| 72 | } |
| 73 | } |
| 74 | |
| 75 | int releaseDiff = expectedReleaseCnt - promiseChecker.fReleaseCount; |
| 76 | REPORTER_ASSERT(reporter, releaseDiff >= 0); |
| 77 | if (releaseDiff != 0) { |
| 78 | if (expectedRequired) { |
| 79 | result = false; |
| 80 | REPORTER_ASSERT(reporter, expectedReleaseCnt == promiseChecker.fReleaseCount); |
| 81 | } else if (releaseDiff > 1) { |
| 82 | result = false; |
| 83 | REPORTER_ASSERT(reporter, releaseDiff <= 1); |
| 84 | } |
| 85 | } |
| 86 | |
Greg Daniel | 7278d68 | 2018-03-16 14:57:21 -0400 | [diff] [blame] | 87 | if (expectedDoneCnt != promiseChecker.fDoneCount) { |
| 88 | result = false; |
| 89 | REPORTER_ASSERT(reporter, expectedDoneCnt == promiseChecker.fDoneCount); |
| 90 | } |
| 91 | |
Greg Daniel | a8d9211 | 2018-03-09 12:05:04 -0500 | [diff] [blame] | 92 | return result; |
| 93 | } |
| 94 | |
| 95 | DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTest, reporter, ctxInfo) { |
| 96 | const int kWidth = 10; |
| 97 | const int kHeight = 10; |
Greg Daniel | a8d9211 | 2018-03-09 12:05:04 -0500 | [diff] [blame] | 98 | |
| 99 | GrContext* ctx = ctxInfo.grContext(); |
| 100 | GrGpu* gpu = ctx->contextPriv().getGpu(); |
| 101 | |
Greg Daniel | 7278d68 | 2018-03-16 14:57:21 -0400 | [diff] [blame] | 102 | for (bool releaseImageEarly : {true, false}) { |
| 103 | GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture( |
Robert Phillips | 646f637 | 2018-09-25 09:31:10 -0400 | [diff] [blame] | 104 | nullptr, kWidth, kHeight, GrColorType::kRGBA_8888, true, GrMipMapped::kNo); |
Greg Daniel | 7278d68 | 2018-03-16 14:57:21 -0400 | [diff] [blame] | 105 | REPORTER_ASSERT(reporter, backendTex.isValid()); |
Greg Daniel | a8d9211 | 2018-03-09 12:05:04 -0500 | [diff] [blame] | 106 | |
Timothy Liang | 036fdfe | 2018-06-28 15:50:36 -0400 | [diff] [blame] | 107 | GrBackendFormat backendFormat = gpu->caps()->createFormatFromBackendTexture(backendTex); |
Greg Daniel | 7278d68 | 2018-03-16 14:57:21 -0400 | [diff] [blame] | 108 | REPORTER_ASSERT(reporter, backendFormat.isValid()); |
Greg Daniel | a8d9211 | 2018-03-09 12:05:04 -0500 | [diff] [blame] | 109 | |
Greg Daniel | 7278d68 | 2018-03-16 14:57:21 -0400 | [diff] [blame] | 110 | PromiseTextureChecker promiseChecker(backendTex); |
| 111 | GrSurfaceOrigin texOrigin = kTopLeft_GrSurfaceOrigin; |
| 112 | sk_sp<SkImage> refImg( |
| 113 | SkImage_Gpu::MakePromiseTexture(ctx, backendFormat, kWidth, kHeight, |
| 114 | GrMipMapped::kNo, texOrigin, |
| 115 | kRGBA_8888_SkColorType, kPremul_SkAlphaType, |
| 116 | nullptr, |
| 117 | PromiseTextureChecker::Fulfill, |
| 118 | PromiseTextureChecker::Release, |
| 119 | PromiseTextureChecker::Done, |
| 120 | &promiseChecker)); |
Greg Daniel | a8d9211 | 2018-03-09 12:05:04 -0500 | [diff] [blame] | 121 | |
Greg Daniel | 7278d68 | 2018-03-16 14:57:21 -0400 | [diff] [blame] | 122 | SkImageInfo info = SkImageInfo::MakeN32Premul(kWidth, kHeight); |
| 123 | sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info); |
| 124 | SkCanvas* canvas = surface->getCanvas(); |
Greg Daniel | a8d9211 | 2018-03-09 12:05:04 -0500 | [diff] [blame] | 125 | |
Greg Daniel | 7278d68 | 2018-03-16 14:57:21 -0400 | [diff] [blame] | 126 | int expectedFulfillCnt = 0; |
| 127 | int expectedReleaseCnt = 0; |
| 128 | int expectedDoneCnt = 0; |
Greg Daniel | a8d9211 | 2018-03-09 12:05:04 -0500 | [diff] [blame] | 129 | |
Greg Daniel | 7278d68 | 2018-03-16 14:57:21 -0400 | [diff] [blame] | 130 | canvas->drawImage(refImg, 0, 0); |
| 131 | REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker, |
| 132 | true, |
| 133 | expectedFulfillCnt, |
| 134 | expectedReleaseCnt, |
| 135 | true, |
| 136 | expectedDoneCnt, |
| 137 | reporter)); |
Greg Daniel | a8d9211 | 2018-03-09 12:05:04 -0500 | [diff] [blame] | 138 | |
Greg Daniel | 7278d68 | 2018-03-16 14:57:21 -0400 | [diff] [blame] | 139 | bool isVulkan = kVulkan_GrBackend == ctx->contextPriv().getBackend(); |
| 140 | canvas->flush(); |
| 141 | expectedFulfillCnt++; |
| 142 | expectedReleaseCnt++; |
| 143 | REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker, |
| 144 | !isVulkan, |
| 145 | expectedFulfillCnt, |
| 146 | expectedReleaseCnt, |
| 147 | !isVulkan, |
| 148 | expectedDoneCnt, |
| 149 | reporter)); |
Greg Daniel | a8d9211 | 2018-03-09 12:05:04 -0500 | [diff] [blame] | 150 | |
Greg Daniel | 7278d68 | 2018-03-16 14:57:21 -0400 | [diff] [blame] | 151 | gpu->testingOnly_flushGpuAndSync(); |
| 152 | REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker, |
| 153 | true, |
| 154 | expectedFulfillCnt, |
| 155 | expectedReleaseCnt, |
| 156 | true, |
| 157 | expectedDoneCnt, |
| 158 | reporter)); |
Greg Daniel | a8d9211 | 2018-03-09 12:05:04 -0500 | [diff] [blame] | 159 | |
Greg Daniel | 7278d68 | 2018-03-16 14:57:21 -0400 | [diff] [blame] | 160 | canvas->drawImage(refImg, 0, 0); |
| 161 | canvas->drawImage(refImg, 0, 0); |
Greg Daniel | a8d9211 | 2018-03-09 12:05:04 -0500 | [diff] [blame] | 162 | |
Greg Daniel | 7278d68 | 2018-03-16 14:57:21 -0400 | [diff] [blame] | 163 | canvas->flush(); |
| 164 | expectedFulfillCnt++; |
| 165 | expectedReleaseCnt++; |
Greg Daniel | a8d9211 | 2018-03-09 12:05:04 -0500 | [diff] [blame] | 166 | |
Greg Daniel | 7278d68 | 2018-03-16 14:57:21 -0400 | [diff] [blame] | 167 | gpu->testingOnly_flushGpuAndSync(); |
| 168 | REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker, |
| 169 | true, |
| 170 | expectedFulfillCnt, |
| 171 | expectedReleaseCnt, |
| 172 | true, |
| 173 | expectedDoneCnt, |
| 174 | reporter)); |
Greg Daniel | a8d9211 | 2018-03-09 12:05:04 -0500 | [diff] [blame] | 175 | |
Greg Daniel | 7278d68 | 2018-03-16 14:57:21 -0400 | [diff] [blame] | 176 | // Now test code path on Vulkan where we released the texture, but the GPU isn't done with |
| 177 | // resource yet and we do another draw. We should only call fulfill on the first draw and |
| 178 | // use the cached GrBackendTexture on the second. Release should only be called after the |
| 179 | // second draw is finished. |
| 180 | canvas->drawImage(refImg, 0, 0); |
| 181 | canvas->flush(); |
| 182 | expectedFulfillCnt++; |
| 183 | expectedReleaseCnt++; |
| 184 | REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker, |
| 185 | !isVulkan, |
| 186 | expectedFulfillCnt, |
| 187 | expectedReleaseCnt, |
| 188 | !isVulkan, |
| 189 | expectedDoneCnt, |
| 190 | reporter)); |
Greg Daniel | a8d9211 | 2018-03-09 12:05:04 -0500 | [diff] [blame] | 191 | |
Greg Daniel | 7278d68 | 2018-03-16 14:57:21 -0400 | [diff] [blame] | 192 | canvas->drawImage(refImg, 0, 0); |
Greg Daniel | a8d9211 | 2018-03-09 12:05:04 -0500 | [diff] [blame] | 193 | |
Greg Daniel | 7278d68 | 2018-03-16 14:57:21 -0400 | [diff] [blame] | 194 | if (releaseImageEarly) { |
| 195 | refImg.reset(); |
| 196 | } |
Greg Daniel | a8d9211 | 2018-03-09 12:05:04 -0500 | [diff] [blame] | 197 | |
Greg Daniel | 7278d68 | 2018-03-16 14:57:21 -0400 | [diff] [blame] | 198 | REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker, |
| 199 | !isVulkan, |
| 200 | expectedFulfillCnt, |
| 201 | expectedReleaseCnt, |
| 202 | !isVulkan, |
| 203 | expectedDoneCnt, |
| 204 | reporter)); |
Greg Daniel | a8d9211 | 2018-03-09 12:05:04 -0500 | [diff] [blame] | 205 | |
Greg Daniel | 7278d68 | 2018-03-16 14:57:21 -0400 | [diff] [blame] | 206 | canvas->flush(); |
| 207 | expectedFulfillCnt++; |
Greg Daniel | a8d9211 | 2018-03-09 12:05:04 -0500 | [diff] [blame] | 208 | |
Greg Daniel | 7278d68 | 2018-03-16 14:57:21 -0400 | [diff] [blame] | 209 | gpu->testingOnly_flushGpuAndSync(); |
| 210 | expectedReleaseCnt++; |
| 211 | if (releaseImageEarly) { |
| 212 | expectedDoneCnt++; |
| 213 | } |
| 214 | REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker, |
| 215 | true, |
| 216 | expectedFulfillCnt, |
| 217 | expectedReleaseCnt, |
| 218 | !isVulkan, |
| 219 | expectedDoneCnt, |
| 220 | reporter)); |
| 221 | expectedFulfillCnt = promiseChecker.fFulfillCount; |
| 222 | expectedReleaseCnt = promiseChecker.fReleaseCount; |
| 223 | |
| 224 | if (!releaseImageEarly) { |
| 225 | refImg.reset(); |
| 226 | expectedDoneCnt++; |
| 227 | } |
| 228 | |
| 229 | REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker, |
| 230 | true, |
| 231 | expectedFulfillCnt, |
| 232 | expectedReleaseCnt, |
| 233 | true, |
| 234 | expectedDoneCnt, |
| 235 | reporter)); |
| 236 | |
| 237 | gpu->deleteTestingOnlyBackendTexture(backendTex); |
| 238 | } |
Greg Daniel | a8d9211 | 2018-03-09 12:05:04 -0500 | [diff] [blame] | 239 | } |