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 "SkTypes.h" 9 10 #include "GrContext.h" 11 #include "GrContextFactory.h" 12 #include "GrContextPriv.h" 13 #include "GrDeferredUpload.h" 14 #include "GrDrawOpAtlas.h" 15 #include "GrDrawingManager.h" 16 #include "GrMemoryPool.h" 17 #include "GrOnFlushResourceProvider.h" 18 #include "GrOpFlushState.h" 19 #include "GrRenderTargetContext.h" 20 #include "GrSurfaceProxyPriv.h" 21 #include "GrTextureProxy.h" 22 #include "GrTypesPriv.h" 23 #include "GrXferProcessor.h" 24 #include "SkBitmap.h" 25 #include "SkColor.h" 26 #include "SkColorSpace.h" 27 #include "SkIPoint16.h" 28 #include "SkImageInfo.h" 29 #include "SkMatrix.h" 30 #include "SkPaint.h" 31 #include "SkPoint.h" 32 #include "SkRefCnt.h" 33 #include "Test.h" 34 #include "ops/GrDrawOp.h" 35 #include "text/GrAtlasManager.h" 36 #include "text/GrTextContext.h" 37 #include "text/GrTextTarget.h" 38 39 #include <memory> 40 41 class GrResourceProvider; 42 43 static const int kNumPlots = 2; 44 static const int kPlotSize = 32; 45 static const int kAtlasSize = kNumPlots * kPlotSize; 46 47 int GrDrawOpAtlas::numAllocated_TestingOnly() const { 48 int count = 0; 49 for (uint32_t i = 0; i < this->maxPages(); ++i) { 50 if (fProxies[i]->isInstantiated()) { 51 ++count; 52 } 53 } 54 55 return count; 56 } 57 58 void GrAtlasManager::setMaxPages_TestingOnly(uint32_t maxPages) { 59 for (int i = 0; i < kMaskFormatCount; i++) { 60 if (fAtlases[i]) { 61 fAtlases[i]->setMaxPages_TestingOnly(maxPages); 62 } 63 } 64 } 65 66 void GrDrawOpAtlas::setMaxPages_TestingOnly(uint32_t maxPages) { 67 SkASSERT(!fNumActivePages); 68 69 fMaxPages = maxPages; 70 } 71 72 void EvictionFunc(GrDrawOpAtlas::AtlasID atlasID, void*) { 73 SkASSERT(0); // The unit test shouldn't exercise this code path 74 } 75 76 static void check(skiatest::Reporter* r, GrDrawOpAtlas* atlas, 77 uint32_t expectedActive, uint32_t expectedMax, int expectedAlloced) { 78 REPORTER_ASSERT(r, expectedActive == atlas->numActivePages()); 79 REPORTER_ASSERT(r, expectedMax == atlas->maxPages()); 80 REPORTER_ASSERT(r, expectedAlloced == atlas->numAllocated_TestingOnly()); 81 } 82 83 class TestingUploadTarget : public GrDeferredUploadTarget { 84 public: 85 TestingUploadTarget() { } 86 87 const GrTokenTracker* tokenTracker() final { return &fTokenTracker; } 88 GrTokenTracker* writeableTokenTracker() { return &fTokenTracker; } 89 90 GrDeferredUploadToken addInlineUpload(GrDeferredTextureUploadFn&&) final { 91 SkASSERT(0); // this test shouldn't invoke this code path 92 return fTokenTracker.nextDrawToken(); 93 } 94 95 virtual GrDeferredUploadToken addASAPUpload(GrDeferredTextureUploadFn&& upload) final { 96 return fTokenTracker.nextTokenToFlush(); 97 } 98 99 void issueDrawToken() { fTokenTracker.issueDrawToken(); } 100 void flushToken() { fTokenTracker.flushToken(); } 101 102 private: 103 GrTokenTracker fTokenTracker; 104 105 typedef GrDeferredUploadTarget INHERITED; 106 }; 107 108 static bool fill_plot(GrDrawOpAtlas* atlas, 109 GrResourceProvider* resourceProvider, 110 GrDeferredUploadTarget* target, 111 GrDrawOpAtlas::AtlasID* atlasID, 112 int alpha) { 113 SkImageInfo ii = SkImageInfo::MakeA8(kPlotSize, kPlotSize); 114 115 SkBitmap data; 116 data.allocPixels(ii); 117 data.eraseARGB(alpha, 0, 0, 0); 118 119 SkIPoint16 loc; 120 GrDrawOpAtlas::ErrorCode code; 121 code = atlas->addToAtlas(resourceProvider, atlasID, target, kPlotSize, kPlotSize, 122 data.getAddr(0, 0), &loc); 123 return GrDrawOpAtlas::ErrorCode::kSucceeded == code; 124 } 125 126 127 // This is a basic DrawOpAtlas test. It simply verifies that multitexture atlases correctly 128 // add and remove pages. Note that this is simulating flush-time behavior. 129 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(BasicDrawOpAtlas, reporter, ctxInfo) { 130 auto context = ctxInfo.grContext(); 131 auto proxyProvider = context->contextPriv().proxyProvider(); 132 auto resourceProvider = context->contextPriv().resourceProvider(); 133 auto drawingManager = context->contextPriv().drawingManager(); 134 135 GrOnFlushResourceProvider onFlushResourceProvider(drawingManager); 136 TestingUploadTarget uploadTarget; 137 138 GrBackendFormat format = 139 context->contextPriv().caps()->getBackendFormatFromColorType(kAlpha_8_SkColorType); 140 141 std::unique_ptr<GrDrawOpAtlas> atlas = GrDrawOpAtlas::Make( 142 proxyProvider, 143 format, 144 kAlpha_8_GrPixelConfig, 145 kAtlasSize, kAtlasSize, 146 kAtlasSize/kNumPlots, kAtlasSize/kNumPlots, 147 GrDrawOpAtlas::AllowMultitexturing::kYes, 148 EvictionFunc, nullptr); 149 check(reporter, atlas.get(), 0, 4, 0); 150 151 // Fill up the first level 152 GrDrawOpAtlas::AtlasID atlasIDs[kNumPlots * kNumPlots]; 153 for (int i = 0; i < kNumPlots * kNumPlots; ++i) { 154 bool result = fill_plot(atlas.get(), resourceProvider, &uploadTarget, &atlasIDs[i], i*32); 155 REPORTER_ASSERT(reporter, result); 156 check(reporter, atlas.get(), 1, 4, 1); 157 } 158 159 atlas->instantiate(&onFlushResourceProvider); 160 check(reporter, atlas.get(), 1, 4, 1); 161 162 // Force allocation of a second level 163 GrDrawOpAtlas::AtlasID atlasID; 164 bool result = fill_plot(atlas.get(), resourceProvider, &uploadTarget, &atlasID, 4*32); 165 REPORTER_ASSERT(reporter, result); 166 check(reporter, atlas.get(), 2, 4, 2); 167 168 // Simulate a lot of draws using only the first plot. The last texture should be compacted. 169 for (int i = 0; i < 512; ++i) { 170 atlas->setLastUseToken(atlasIDs[0], uploadTarget.tokenTracker()->nextDrawToken()); 171 uploadTarget.issueDrawToken(); 172 uploadTarget.flushToken(); 173 atlas->compact(uploadTarget.tokenTracker()->nextTokenToFlush()); 174 } 175 176 check(reporter, atlas.get(), 1, 4, 1); 177 } 178 179 // This test verifies that the GrAtlasTextOp::onPrepare method correctly handles a failure 180 // when allocating an atlas page. 181 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrAtlasTextOpPreparation, reporter, ctxInfo) { 182 183 auto context = ctxInfo.grContext(); 184 185 auto gpu = context->contextPriv().getGpu(); 186 auto resourceProvider = context->contextPriv().resourceProvider(); 187 auto drawingManager = context->contextPriv().drawingManager(); 188 auto textContext = drawingManager->getTextContext(); 189 auto opMemoryPool = context->contextPriv().opMemoryPool(); 190 191 GrBackendFormat format = 192 context->contextPriv().caps()->getBackendFormatFromColorType(kRGBA_8888_SkColorType); 193 194 auto rtc = context->contextPriv().makeDeferredRenderTargetContext(format, 195 SkBackingFit::kApprox, 196 32, 32, 197 kRGBA_8888_GrPixelConfig, 198 nullptr); 199 200 SkPaint paint; 201 paint.setColor(SK_ColorRED); 202 203 SkFont font; 204 font.setEdging(SkFont::Edging::kAlias); 205 206 const char* text = "a"; 207 208 std::unique_ptr<GrDrawOp> op = textContext->createOp_TestingOnly( 209 context, textContext, rtc.get(), paint, font, SkMatrix::I(), text, 16, 16); 210 op->finalize(*context->contextPriv().caps(), nullptr); 211 212 TestingUploadTarget uploadTarget; 213 214 GrOpFlushState flushState(gpu, resourceProvider, uploadTarget.writeableTokenTracker(), nullptr, 215 nullptr); 216 GrOpFlushState::OpArgs opArgs = { 217 op.get(), 218 rtc->asRenderTargetProxy(), 219 nullptr, 220 GrXferProcessor::DstProxy(nullptr, SkIPoint::Make(0, 0)) 221 }; 222 223 // Cripple the atlas manager so it can't allocate any pages. This will force a failure 224 // in the preparation of the text op 225 auto atlasManager = context->contextPriv().getAtlasManager(); 226 unsigned int numProxies; 227 atlasManager->getProxies(kA8_GrMaskFormat, &numProxies); 228 atlasManager->setMaxPages_TestingOnly(0); 229 230 flushState.setOpArgs(&opArgs); 231 op->prepare(&flushState); 232 flushState.setOpArgs(nullptr); 233 opMemoryPool->release(std::move(op)); 234 } 235 236 void test_atlas_config(skiatest::Reporter* reporter, int maxTextureSize, size_t maxBytes, 237 GrMaskFormat maskFormat, SkISize expectedDimensions, 238 SkISize expectedPlotDimensions) { 239 GrDrawOpAtlasConfig config(maxTextureSize, maxBytes); 240 REPORTER_ASSERT(reporter, config.atlasDimensions(maskFormat) == expectedDimensions); 241 REPORTER_ASSERT(reporter, config.plotDimensions(maskFormat) == expectedPlotDimensions); 242 } 243 244 DEF_GPUTEST(GrDrawOpAtlasConfig_Basic, reporter, options) { 245 // 1/4 MB 246 test_atlas_config(reporter, 65536, 256 * 1024, kARGB_GrMaskFormat, 247 { 256, 256 }, { 256, 256 }); 248 test_atlas_config(reporter, 65536, 256 * 1024, kA8_GrMaskFormat, 249 { 512, 512 }, { 256, 256 }); 250 // 1/2 MB 251 test_atlas_config(reporter, 65536, 512 * 1024, kARGB_GrMaskFormat, 252 { 512, 256 }, { 256, 256 }); 253 test_atlas_config(reporter, 65536, 512 * 1024, kA8_GrMaskFormat, 254 { 1024, 512 }, { 256, 256 }); 255 // 1 MB 256 test_atlas_config(reporter, 65536, 1024 * 1024, kARGB_GrMaskFormat, 257 { 512, 512 }, { 256, 256 }); 258 test_atlas_config(reporter, 65536, 1024 * 1024, kA8_GrMaskFormat, 259 { 1024, 1024 }, { 256, 256 }); 260 // 2 MB 261 test_atlas_config(reporter, 65536, 2 * 1024 * 1024, kARGB_GrMaskFormat, 262 { 1024, 512 }, { 256, 256 }); 263 test_atlas_config(reporter, 65536, 2 * 1024 * 1024, kA8_GrMaskFormat, 264 { 2048, 1024 }, { 512, 256 }); 265 // 4 MB 266 test_atlas_config(reporter, 65536, 4 * 1024 * 1024, kARGB_GrMaskFormat, 267 { 1024, 1024 }, { 256, 256 }); 268 test_atlas_config(reporter, 65536, 4 * 1024 * 1024, kA8_GrMaskFormat, 269 { 2048, 2048 }, { 512, 512 }); 270 // 8 MB 271 test_atlas_config(reporter, 65536, 8 * 1024 * 1024, kARGB_GrMaskFormat, 272 { 2048, 1024 }, { 256, 256 }); 273 test_atlas_config(reporter, 65536, 8 * 1024 * 1024, kA8_GrMaskFormat, 274 { 2048, 2048 }, { 512, 512 }); 275 // 16 MB (should be same as 8 MB) 276 test_atlas_config(reporter, 65536, 16 * 1024 * 1024, kARGB_GrMaskFormat, 277 { 2048, 1024 }, { 256, 256 }); 278 test_atlas_config(reporter, 65536, 16 * 1024 * 1024, kA8_GrMaskFormat, 279 { 2048, 2048 }, { 512, 512 }); 280 281 // 4MB, restricted texture size 282 test_atlas_config(reporter, 1024, 8 * 1024 * 1024, kARGB_GrMaskFormat, 283 { 1024, 1024 }, { 256, 256 }); 284 test_atlas_config(reporter, 1024, 8 * 1024 * 1024, kA8_GrMaskFormat, 285 { 1024, 1024 }, { 256, 256 }); 286 287 // 3 MB (should be same as 2 MB) 288 test_atlas_config(reporter, 65536, 3 * 1024 * 1024, kARGB_GrMaskFormat, 289 { 1024, 512 }, { 256, 256 }); 290 test_atlas_config(reporter, 65536, 3 * 1024 * 1024, kA8_GrMaskFormat, 291 { 2048, 1024 }, { 512, 256 }); 292 293 // minimum size 294 test_atlas_config(reporter, 65536, 0, kARGB_GrMaskFormat, 295 { 256, 256 }, { 256, 256 }); 296 test_atlas_config(reporter, 65536, 0, kA8_GrMaskFormat, 297 { 512, 512 }, { 256, 256 }); 298 } 299