GrSurfaceTest.cpp 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824
  1. /*
  2. * Copyright 2013 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. #include <set>
  8. #include "include/core/SkSurface.h"
  9. #include "include/gpu/GrContext.h"
  10. #include "include/gpu/GrRenderTarget.h"
  11. #include "include/gpu/GrTexture.h"
  12. #include "src/core/SkAutoPixmapStorage.h"
  13. #include "src/core/SkMipMap.h"
  14. #include "src/gpu/GrClip.h"
  15. #include "src/gpu/GrContextPriv.h"
  16. #include "src/gpu/GrDataUtils.h"
  17. #include "src/gpu/GrGpu.h"
  18. #include "src/gpu/GrProxyProvider.h"
  19. #include "src/gpu/GrResourceProvider.h"
  20. #include "src/gpu/GrTexturePriv.h"
  21. #include "tests/Test.h"
  22. #include "tests/TestUtils.h"
  23. // Tests that GrSurface::asTexture(), GrSurface::asRenderTarget(), and static upcasting of texture
  24. // and render targets to GrSurface all work as expected.
  25. DEF_GPUTEST_FOR_MOCK_CONTEXT(GrSurface, reporter, ctxInfo) {
  26. GrContext* context = ctxInfo.grContext();
  27. auto resourceProvider = context->priv().resourceProvider();
  28. GrSurfaceDesc desc;
  29. desc.fWidth = 256;
  30. desc.fHeight = 256;
  31. desc.fConfig = kRGBA_8888_GrPixelConfig;
  32. sk_sp<GrSurface> texRT1 = resourceProvider->createTexture(
  33. desc, GrRenderable::kYes, 1, SkBudgeted::kNo, GrProtected::kNo,
  34. GrResourceProvider::Flags::kNoPendingIO);
  35. REPORTER_ASSERT(reporter, texRT1.get() == texRT1->asRenderTarget());
  36. REPORTER_ASSERT(reporter, texRT1.get() == texRT1->asTexture());
  37. REPORTER_ASSERT(reporter, static_cast<GrSurface*>(texRT1->asRenderTarget()) ==
  38. texRT1->asTexture());
  39. REPORTER_ASSERT(reporter, texRT1->asRenderTarget() ==
  40. static_cast<GrSurface*>(texRT1->asTexture()));
  41. REPORTER_ASSERT(reporter, static_cast<GrSurface*>(texRT1->asRenderTarget()) ==
  42. static_cast<GrSurface*>(texRT1->asTexture()));
  43. sk_sp<GrTexture> tex1 = resourceProvider->createTexture(
  44. desc, GrRenderable::kNo, 1, SkBudgeted::kNo, GrProtected::kNo,
  45. GrResourceProvider::Flags::kNoPendingIO);
  46. REPORTER_ASSERT(reporter, nullptr == tex1->asRenderTarget());
  47. REPORTER_ASSERT(reporter, tex1.get() == tex1->asTexture());
  48. REPORTER_ASSERT(reporter, static_cast<GrSurface*>(tex1.get()) == tex1->asTexture());
  49. GrBackendTexture backendTex = context->createBackendTexture(
  50. 256, 256, kRGBA_8888_SkColorType,
  51. SkColors::kTransparent, GrMipMapped::kNo, GrRenderable::kNo, GrProtected::kNo);
  52. sk_sp<GrSurface> texRT2 = resourceProvider->wrapRenderableBackendTexture(
  53. backendTex, 1, GrColorType::kRGBA_8888, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo);
  54. REPORTER_ASSERT(reporter, texRT2.get() == texRT2->asRenderTarget());
  55. REPORTER_ASSERT(reporter, texRT2.get() == texRT2->asTexture());
  56. REPORTER_ASSERT(reporter, static_cast<GrSurface*>(texRT2->asRenderTarget()) ==
  57. texRT2->asTexture());
  58. REPORTER_ASSERT(reporter, texRT2->asRenderTarget() ==
  59. static_cast<GrSurface*>(texRT2->asTexture()));
  60. REPORTER_ASSERT(reporter, static_cast<GrSurface*>(texRT2->asRenderTarget()) ==
  61. static_cast<GrSurface*>(texRT2->asTexture()));
  62. context->deleteBackendTexture(backendTex);
  63. }
  64. // This test checks that the isConfigTexturable and isConfigRenderable are
  65. // consistent with createTexture's result.
  66. DEF_GPUTEST_FOR_ALL_CONTEXTS(GrSurfaceRenderability, reporter, ctxInfo) {
  67. GrContext* context = ctxInfo.grContext();
  68. GrProxyProvider* proxyProvider = context->priv().proxyProvider();
  69. GrResourceProvider* resourceProvider = context->priv().resourceProvider();
  70. const GrCaps* caps = context->priv().caps();
  71. auto createTexture = [](int width, int height, GrPixelConfig config, GrRenderable renderable,
  72. GrResourceProvider* rp) -> sk_sp<GrTexture> {
  73. if (GrPixelConfigIsCompressed(config)) {
  74. if (renderable == GrRenderable::kYes) {
  75. return nullptr;
  76. }
  77. SkImage::CompressionType type;
  78. switch (config) {
  79. case kRGB_ETC1_GrPixelConfig:
  80. type = SkImage::kETC1_CompressionType;
  81. break;
  82. default:
  83. SK_ABORT("Unexpected config");
  84. return nullptr;
  85. }
  86. // Only supported compression type right now.
  87. SkASSERT(config == kRGB_ETC1_GrPixelConfig);
  88. auto size = GrCompressedDataSize(type, width, height);
  89. auto data = SkData::MakeUninitialized(size);
  90. SkColor4f color = {0, 0, 0, 0};
  91. GrFillInCompressedData(type, width, height, (char*)data->writable_data(), color);
  92. return rp->createCompressedTexture(width, height, SkImage::kETC1_CompressionType,
  93. SkBudgeted::kNo, data.get());
  94. } else {
  95. GrSurfaceDesc desc;
  96. desc.fWidth = width;
  97. desc.fHeight = height;
  98. desc.fConfig = config;
  99. return rp->createTexture(desc, renderable, 1, SkBudgeted::kNo, GrProtected::kNo,
  100. GrResourceProvider::Flags::kNoPendingIO);
  101. }
  102. };
  103. for (int c = 0; c <= kLast_GrPixelConfig; ++c) {
  104. GrPixelConfig config = static_cast<GrPixelConfig>(c);
  105. // We don't round trip correctly going from pixelConfig to colorType to
  106. // backendFormat with the RGBX config.
  107. if (config == kRGB_888X_GrPixelConfig) {
  108. continue;
  109. }
  110. // The specific kAlpha_* and kGray_8* pixel configs cause difficulties.
  111. // The mapping from config -> colorType -> format doesn't necessarily
  112. // resolve back to the expected pixel config. Just test the generic pixel configs.
  113. if (config == kAlpha_8_as_Alpha_GrPixelConfig ||
  114. config == kAlpha_8_as_Red_GrPixelConfig ||
  115. config == kGray_8_as_Lum_GrPixelConfig ||
  116. config == kGray_8_as_Red_GrPixelConfig ||
  117. config == kAlpha_half_as_Red_GrPixelConfig ||
  118. config == kAlpha_half_as_Lum_GrPixelConfig) {
  119. continue;
  120. }
  121. for (GrSurfaceOrigin origin : { kTopLeft_GrSurfaceOrigin, kBottomLeft_GrSurfaceOrigin }) {
  122. if (config == kUnknown_GrPixelConfig) {
  123. // It is not valid to be calling into GrProxyProvider with an unknown pixel config.
  124. continue;
  125. }
  126. static constexpr int kW = 64;
  127. static constexpr int kH = 64;
  128. bool ict = caps->isConfigTexturable(config);
  129. sk_sp<GrSurface> tex =
  130. createTexture(kW, kH, config, GrRenderable::kNo, resourceProvider);
  131. REPORTER_ASSERT(reporter, SkToBool(tex) == ict,
  132. "config:%d, tex:%d, isConfigTexturable:%d", config, SkToBool(tex), ict);
  133. GrColorType colorType = GrPixelConfigToColorType(config);
  134. const GrBackendFormat format = caps->getBackendFormatFromColorType(colorType);
  135. if (!format.isValid()) {
  136. continue;
  137. }
  138. GrSurfaceDesc desc;
  139. desc.fWidth = kW;
  140. desc.fHeight = kH;
  141. desc.fConfig = config;
  142. sk_sp<GrTextureProxy> proxy = proxyProvider->createMipMapProxy(
  143. format, desc, GrRenderable::kNo, 1, origin, SkBudgeted::kNo, GrProtected::kNo);
  144. REPORTER_ASSERT(reporter,
  145. SkToBool(proxy.get()) ==
  146. (caps->isConfigTexturable(desc.fConfig) &&
  147. caps->mipMapSupport() && !GrPixelConfigIsCompressed(config)));
  148. tex = resourceProvider->createTexture(desc, GrRenderable::kYes, 1, SkBudgeted::kNo,
  149. GrProtected::kNo,
  150. GrResourceProvider::Flags::kNoPendingIO);
  151. bool isRenderable = caps->isConfigRenderable(config);
  152. REPORTER_ASSERT(reporter, SkToBool(tex) == isRenderable,
  153. "config:%d, tex:%d, isRenderable:%d", config, SkToBool(tex),
  154. isRenderable);
  155. tex = resourceProvider->createTexture(desc, GrRenderable::kYes, 2, SkBudgeted::kNo,
  156. GrProtected::kNo,
  157. GrResourceProvider::Flags::kNoPendingIO);
  158. isRenderable = SkToBool(caps->getRenderTargetSampleCount(2, config));
  159. REPORTER_ASSERT(reporter, SkToBool(tex) == isRenderable,
  160. "config:%d, tex:%d, isRenderable:%d", config, SkToBool(tex),
  161. isRenderable);
  162. }
  163. }
  164. }
  165. #include "src/gpu/GrDrawingManager.h"
  166. #include "src/gpu/GrSurfaceProxy.h"
  167. #include "src/gpu/GrTextureContext.h"
  168. DEF_GPUTEST(InitialTextureClear, reporter, baseOptions) {
  169. GrContextOptions options = baseOptions;
  170. options.fClearAllTextures = true;
  171. static constexpr int kSize = 100;
  172. std::unique_ptr<uint32_t[]> data(new uint32_t[kSize * kSize]);
  173. for (int ct = 0; ct < sk_gpu_test::GrContextFactory::kContextTypeCnt; ++ct) {
  174. sk_gpu_test::GrContextFactory factory(options);
  175. auto contextType = static_cast<sk_gpu_test::GrContextFactory::ContextType>(ct);
  176. if (!sk_gpu_test::GrContextFactory::IsRenderingContext(contextType)) {
  177. continue;
  178. }
  179. auto context = factory.get(contextType);
  180. if (!context) {
  181. continue;
  182. }
  183. GrSurfaceDesc desc;
  184. desc.fWidth = desc.fHeight = kSize;
  185. const GrCaps* caps = context->priv().caps();
  186. GrProxyProvider* proxyProvider = context->priv().proxyProvider();
  187. for (int c = 0; c <= kLast_GrPixelConfig; ++c) {
  188. desc.fConfig = static_cast<GrPixelConfig>(c);
  189. if (!caps->isConfigTexturable(desc.fConfig)) {
  190. continue;
  191. }
  192. for (auto renderable : {GrRenderable::kNo, GrRenderable::kYes}) {
  193. if (renderable == GrRenderable::kYes && !caps->isConfigRenderable(desc.fConfig)) {
  194. continue;
  195. }
  196. for (GrSurfaceOrigin origin :
  197. {kTopLeft_GrSurfaceOrigin, kBottomLeft_GrSurfaceOrigin}) {
  198. for (auto fit : {SkBackingFit::kApprox, SkBackingFit::kExact}) {
  199. auto proxy = proxyProvider->testingOnly_createInstantiatedProxy(
  200. desc, renderable, 1, origin, fit, SkBudgeted::kYes,
  201. GrProtected::kNo);
  202. if (!proxy) {
  203. continue;
  204. }
  205. auto texCtx = context->priv().makeWrappedSurfaceContext(
  206. std::move(proxy), GrPixelConfigToColorType(desc.fConfig),
  207. kPremul_SkAlphaType);
  208. SkImageInfo info = SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType,
  209. kPremul_SkAlphaType);
  210. memset(data.get(), 0xAB, kSize * kSize * sizeof(uint32_t));
  211. if (texCtx->readPixels(info, data.get(), 0, {0, 0})) {
  212. uint32_t cmp = GrPixelConfigIsOpaque(desc.fConfig) ? 0xFF000000 : 0;
  213. for (int i = 0; i < kSize * kSize; ++i) {
  214. if (cmp != data.get()[i]) {
  215. ERRORF(reporter, "Failed on conf %d (pix %d) 0x%x != 0x%x",
  216. desc.fConfig, i, cmp, data.get()[i]);
  217. break;
  218. }
  219. }
  220. }
  221. context->priv().testingOnly_purgeAllUnlockedResources();
  222. // We don't round trip correctly going from pixelConfig to colorType to
  223. // backendFormat with the RGBX config. The actual config stored on the
  224. // GrSurface will be RGBA_8888 but the format we create below will say it is
  225. // RGB_888.
  226. if (desc.fConfig == kRGB_888X_GrPixelConfig) {
  227. continue;
  228. }
  229. // The specific kAlpha_* pixel configs also cause difficulties with OpenGL.
  230. // The mapping from config -> colorType -> format doesn't necessarily
  231. // resolve back to the expected pixel config. In this case we just test
  232. // the generics.
  233. if (GrBackendApi::kOpenGL == context->backend() &&
  234. (desc.fConfig == kAlpha_8_as_Alpha_GrPixelConfig ||
  235. desc.fConfig == kAlpha_8_as_Red_GrPixelConfig ||
  236. desc.fConfig == kAlpha_half_as_Red_GrPixelConfig ||
  237. desc.fConfig == kAlpha_half_as_Lum_GrPixelConfig)) {
  238. continue;
  239. }
  240. // The specific kGray_8_* pixel configs also cause difficulties with OpenGL.
  241. // The mapping from config -> colorType -> format doesn't necessarily
  242. // resolve back to the expected pixel config. In this case we just test
  243. // the generic.
  244. if (GrBackendApi::kOpenGL == context->backend() &&
  245. (desc.fConfig == kGray_8_as_Lum_GrPixelConfig ||
  246. desc.fConfig == kGray_8_as_Red_GrPixelConfig)) {
  247. continue;
  248. }
  249. GrColorType colorType = GrPixelConfigToColorType(desc.fConfig);
  250. // Try creating the texture as a deferred proxy.
  251. for (int i = 0; i < 2; ++i) {
  252. sk_sp<GrSurfaceContext> surfCtx;
  253. if (renderable == GrRenderable::kYes) {
  254. surfCtx = context->priv().makeDeferredRenderTargetContext(
  255. fit, desc.fWidth, desc.fHeight, colorType, nullptr, 1,
  256. GrMipMapped::kNo, origin, nullptr);
  257. } else {
  258. surfCtx = context->priv().makeDeferredTextureContext(
  259. fit, desc.fWidth, desc.fHeight, colorType,
  260. kUnknown_SkAlphaType, nullptr, GrMipMapped::kNo, origin);
  261. }
  262. if (!surfCtx) {
  263. continue;
  264. }
  265. SkImageInfo info = SkImageInfo::Make(
  266. kSize, kSize, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
  267. memset(data.get(), 0xAB, kSize * kSize * sizeof(uint32_t));
  268. if (surfCtx->readPixels(info, data.get(), 0, {0, 0})) {
  269. uint32_t cmp = GrPixelConfigIsOpaque(desc.fConfig) ? 0xFF000000 : 0;
  270. for (int i = 0; i < kSize * kSize; ++i) {
  271. if (cmp != data.get()[i]) {
  272. ERRORF(reporter, "Failed on conf %d (pix %d) 0x%x != 0x%x",
  273. desc.fConfig, i, cmp, data.get()[i]);
  274. break;
  275. }
  276. }
  277. }
  278. context->priv().testingOnly_purgeAllUnlockedResources();
  279. }
  280. }
  281. }
  282. }
  283. }
  284. }
  285. }
  286. DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ReadOnlyTexture, reporter, context_info) {
  287. auto fillPixels = [](SkPixmap* p, const std::function<uint32_t(int x, int y)>& f) {
  288. for (int y = 0; y < p->height(); ++y) {
  289. for (int x = 0; x < p->width(); ++x) {
  290. *p->writable_addr32(x, y) = f(x, y);
  291. }
  292. }
  293. };
  294. auto comparePixels = [](const SkPixmap& p1, const SkPixmap& p2, skiatest::Reporter* reporter) {
  295. SkASSERT(p1.info() == p2.info());
  296. for (int y = 0; y < p1.height(); ++y) {
  297. for (int x = 0; x < p1.width(); ++x) {
  298. REPORTER_ASSERT(reporter, p1.getColor(x, y) == p2.getColor(x, y));
  299. if (p1.getColor(x, y) != p2.getColor(x, y)) {
  300. return;
  301. }
  302. }
  303. }
  304. };
  305. static constexpr int kSize = 100;
  306. SkImageInfo ii = SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
  307. SkAutoPixmapStorage srcPixmap;
  308. srcPixmap.alloc(ii);
  309. fillPixels(&srcPixmap,
  310. [](int x, int y) {
  311. return (0xFFU << 24) | (x << 16) | (y << 8) | uint8_t((x * y) & 0xFF);
  312. });
  313. GrContext* context = context_info.grContext();
  314. GrProxyProvider* proxyProvider = context->priv().proxyProvider();
  315. // We test both kRW in addition to kRead mostly to ensure that the calls are structured such
  316. // that they'd succeed if the texture wasn't kRead. We want to be sure we're failing with
  317. // kRead for the right reason.
  318. for (auto ioType : {kRead_GrIOType, kRW_GrIOType}) {
  319. auto backendTex = context->priv().createBackendTexture(&srcPixmap, 1,
  320. GrRenderable::kYes,
  321. GrProtected::kNo);
  322. auto proxy = proxyProvider->wrapBackendTexture(backendTex, GrColorType::kRGBA_8888,
  323. kTopLeft_GrSurfaceOrigin,
  324. kBorrow_GrWrapOwnership,
  325. GrWrapCacheable::kNo, ioType);
  326. auto surfContext = context->priv().makeWrappedSurfaceContext(proxy, GrColorType::kRGBA_8888,
  327. kPremul_SkAlphaType);
  328. // Read pixels should work with a read-only texture.
  329. {
  330. SkAutoPixmapStorage read;
  331. read.alloc(srcPixmap.info());
  332. auto readResult = surfContext->readPixels(srcPixmap.info(), read.writable_addr(),
  333. 0, { 0, 0 });
  334. REPORTER_ASSERT(reporter, readResult);
  335. if (readResult) {
  336. comparePixels(srcPixmap, read, reporter);
  337. }
  338. }
  339. // Write pixels should not work with a read-only texture.
  340. SkAutoPixmapStorage write;
  341. write.alloc(srcPixmap.info());
  342. fillPixels(&write, [&srcPixmap](int x, int y) { return ~*srcPixmap.addr32(); });
  343. auto writeResult = surfContext->writePixels(srcPixmap.info(), write.addr(), 0, {0, 0});
  344. REPORTER_ASSERT(reporter, writeResult == (ioType == kRW_GrIOType));
  345. // Try the low level write.
  346. context->flush();
  347. auto gpuWriteResult = context->priv().getGpu()->writePixels(
  348. proxy->peekTexture(), 0, 0, kSize, kSize, GrColorType::kRGBA_8888, write.addr32(),
  349. kSize * GrColorTypeBytesPerPixel(GrColorType::kRGBA_8888));
  350. REPORTER_ASSERT(reporter, gpuWriteResult == (ioType == kRW_GrIOType));
  351. // Copies should not work with a read-only texture
  352. auto copySrc = proxyProvider->createTextureProxy(
  353. SkImage::MakeFromRaster(write, nullptr, nullptr), GrRenderable::kNo, 1,
  354. SkBudgeted::kYes, SkBackingFit::kExact);
  355. REPORTER_ASSERT(reporter, copySrc);
  356. auto copyResult = surfContext->testCopy(copySrc.get());
  357. REPORTER_ASSERT(reporter, copyResult == (ioType == kRW_GrIOType));
  358. // Try the low level copy.
  359. context->flush();
  360. auto gpuCopyResult = context->priv().getGpu()->copySurface(
  361. proxy->peekTexture(), copySrc->peekTexture(), SkIRect::MakeWH(kSize, kSize),
  362. {0, 0});
  363. REPORTER_ASSERT(reporter, gpuCopyResult == (ioType == kRW_GrIOType));
  364. // Mip regen should not work with a read only texture.
  365. if (context->priv().caps()->mipMapSupport()) {
  366. delete_backend_texture(context, backendTex);
  367. backendTex = context->createBackendTexture(
  368. kSize, kSize, kRGBA_8888_SkColorType,
  369. SkColors::kTransparent, GrMipMapped::kYes, GrRenderable::kYes,
  370. GrProtected::kNo);
  371. proxy = proxyProvider->wrapBackendTexture(backendTex, GrColorType::kRGBA_8888,
  372. kTopLeft_GrSurfaceOrigin,
  373. kBorrow_GrWrapOwnership, GrWrapCacheable::kNo,
  374. ioType);
  375. context->flush();
  376. proxy->peekTexture()->texturePriv().markMipMapsDirty(); // avoids assert in GrGpu.
  377. auto regenResult =
  378. context->priv().getGpu()->regenerateMipMapLevels(proxy->peekTexture());
  379. REPORTER_ASSERT(reporter, regenResult == (ioType == kRW_GrIOType));
  380. }
  381. delete_backend_texture(context, backendTex);
  382. }
  383. }
  384. static const int kSurfSize = 10;
  385. static sk_sp<GrTexture> make_wrapped_texture(GrContext* context, GrRenderable renderable) {
  386. auto backendTexture = context->createBackendTexture(
  387. kSurfSize, kSurfSize, kRGBA_8888_SkColorType, SkColors::kTransparent, GrMipMapped::kNo,
  388. renderable, GrProtected::kNo);
  389. sk_sp<GrTexture> texture;
  390. if (GrRenderable::kYes == renderable) {
  391. texture = context->priv().resourceProvider()->wrapRenderableBackendTexture(
  392. backendTexture, 1, GrColorType::kRGBA_8888, kBorrow_GrWrapOwnership,
  393. GrWrapCacheable::kNo);
  394. } else {
  395. texture = context->priv().resourceProvider()->wrapBackendTexture(
  396. backendTexture, GrColorType::kRGBA_8888, kBorrow_GrWrapOwnership,
  397. GrWrapCacheable::kNo, kRW_GrIOType);
  398. }
  399. // Add a release proc that deletes the GrBackendTexture.
  400. struct ReleaseContext {
  401. GrContext* fContext;
  402. GrBackendTexture fBackendTexture;
  403. };
  404. auto release = [](void* rc) {
  405. auto releaseContext = static_cast<ReleaseContext*>(rc);
  406. auto context = releaseContext->fContext;
  407. context->deleteBackendTexture(releaseContext->fBackendTexture);
  408. delete releaseContext;
  409. };
  410. texture->setRelease(release, new ReleaseContext{context, backendTexture});
  411. return texture;
  412. }
  413. static sk_sp<GrTexture> make_normal_texture(GrContext* context, GrRenderable renderable) {
  414. GrSurfaceDesc desc;
  415. desc.fConfig = kRGBA_8888_GrPixelConfig;
  416. desc.fWidth = desc.fHeight = kSurfSize;
  417. return context->priv().resourceProvider()->createTexture(
  418. desc, renderable, 1, SkBudgeted::kNo, GrProtected::kNo,
  419. GrResourceProvider::Flags::kNoPendingIO);
  420. }
  421. DEF_GPUTEST(TextureIdleProcTest, reporter, options) {
  422. // Various ways of making textures.
  423. auto makeWrapped = [](GrContext* context) {
  424. return make_wrapped_texture(context, GrRenderable::kNo);
  425. };
  426. auto makeWrappedRenderable = [](GrContext* context) {
  427. return make_wrapped_texture(context, GrRenderable::kYes);
  428. };
  429. auto makeNormal = [](GrContext* context) {
  430. return make_normal_texture(context, GrRenderable::kNo);
  431. };
  432. auto makeRenderable = [](GrContext* context) {
  433. return make_normal_texture(context, GrRenderable::kYes);
  434. };
  435. std::function<sk_sp<GrTexture>(GrContext*)> makers[] = {makeWrapped, makeWrappedRenderable,
  436. makeNormal, makeRenderable};
  437. // Add a unique key, or not.
  438. auto addKey = [](GrTexture* texture) {
  439. static uint32_t gN = 0;
  440. static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
  441. GrUniqueKey key;
  442. GrUniqueKey::Builder builder(&key, kDomain, 1);
  443. builder[0] = gN++;
  444. builder.finish();
  445. texture->resourcePriv().setUniqueKey(key);
  446. };
  447. auto dontAddKey = [](GrTexture* texture) {};
  448. std::function<void(GrTexture*)> keyAdders[] = {addKey, dontAddKey};
  449. for (const auto& m : makers) {
  450. for (const auto& keyAdder : keyAdders) {
  451. for (int type = 0; type < sk_gpu_test::GrContextFactory::kContextTypeCnt; ++type) {
  452. sk_gpu_test::GrContextFactory factory;
  453. auto contextType = static_cast<sk_gpu_test::GrContextFactory::ContextType>(type);
  454. GrContext* context = factory.get(contextType);
  455. if (!context) {
  456. continue;
  457. }
  458. // The callback we add simply adds an integer to a set.
  459. std::set<int> idleIDs;
  460. struct Context {
  461. std::set<int>* fIdleIDs;
  462. int fNum;
  463. };
  464. auto proc = [](void* context) {
  465. static_cast<Context*>(context)->fIdleIDs->insert(
  466. static_cast<Context*>(context)->fNum);
  467. delete static_cast<Context*>(context);
  468. };
  469. // Makes a texture, possibly adds a key, and sets the callback.
  470. auto make = [&m, &keyAdder, &proc, &idleIDs](GrContext* context, int num) {
  471. sk_sp<GrTexture> texture = m(context);
  472. texture->addIdleProc(proc, new Context{&idleIDs, num},
  473. GrTexture::IdleState::kFinished);
  474. keyAdder(texture.get());
  475. return texture;
  476. };
  477. auto texture = make(context, 1);
  478. REPORTER_ASSERT(reporter, idleIDs.find(1) == idleIDs.end());
  479. auto renderable = GrRenderable(SkToBool(texture->asRenderTarget()));
  480. auto backendFormat = texture->backendFormat();
  481. texture.reset();
  482. REPORTER_ASSERT(reporter, idleIDs.find(1) != idleIDs.end());
  483. texture = make(context, 2);
  484. int w = texture->width();
  485. int h = texture->height();
  486. SkImageInfo info =
  487. SkImageInfo::Make(w, h, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
  488. auto rt = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info, 0, nullptr);
  489. auto rtc = rt->getCanvas()->internal_private_accessTopLayerRenderTargetContext();
  490. auto singleUseLazyCB = [&texture](GrResourceProvider* rp) {
  491. auto mode = GrSurfaceProxy::LazyInstantiationKeyMode::kSynced;
  492. if (texture->getUniqueKey().isValid()) {
  493. mode = GrSurfaceProxy::LazyInstantiationKeyMode::kUnsynced;
  494. }
  495. return GrSurfaceProxy::LazyInstantiationResult{std::move(texture), mode};
  496. };
  497. GrSurfaceDesc desc;
  498. desc.fWidth = w;
  499. desc.fHeight = h;
  500. desc.fConfig = kRGBA_8888_GrPixelConfig;
  501. SkBudgeted budgeted;
  502. if (texture->resourcePriv().budgetedType() == GrBudgetedType::kBudgeted) {
  503. budgeted = SkBudgeted::kYes;
  504. } else {
  505. budgeted = SkBudgeted::kNo;
  506. }
  507. auto proxy = context->priv().proxyProvider()->createLazyProxy(
  508. singleUseLazyCB, backendFormat, desc, renderable, 1,
  509. GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin, GrMipMapped::kNo,
  510. GrInternalSurfaceFlags ::kNone, SkBackingFit::kExact, budgeted,
  511. GrProtected::kNo, GrSurfaceProxy::LazyInstantiationType::kSingleUse);
  512. rtc->drawTexture(GrNoClip(), proxy, GrSamplerState::Filter::kNearest,
  513. SkBlendMode::kSrcOver, SkPMColor4f(), SkRect::MakeWH(w, h),
  514. SkRect::MakeWH(w, h), GrAA::kNo, GrQuadAAFlags::kNone,
  515. SkCanvas::kFast_SrcRectConstraint, SkMatrix::I(), nullptr);
  516. // We still have the proxy, which should remain instantiated, thereby keeping the
  517. // texture not purgeable.
  518. REPORTER_ASSERT(reporter, idleIDs.find(2) == idleIDs.end());
  519. context->flush();
  520. REPORTER_ASSERT(reporter, idleIDs.find(2) == idleIDs.end());
  521. context->priv().getGpu()->testingOnly_flushGpuAndSync();
  522. REPORTER_ASSERT(reporter, idleIDs.find(2) == idleIDs.end());
  523. // This time we move the proxy into the draw.
  524. rtc->drawTexture(GrNoClip(), std::move(proxy), GrSamplerState::Filter::kNearest,
  525. SkBlendMode::kSrcOver, SkPMColor4f(), SkRect::MakeWH(w, h),
  526. SkRect::MakeWH(w, h), GrAA::kNo, GrQuadAAFlags::kNone,
  527. SkCanvas::kFast_SrcRectConstraint, SkMatrix::I(), nullptr);
  528. REPORTER_ASSERT(reporter, idleIDs.find(2) == idleIDs.end());
  529. context->flush();
  530. context->priv().getGpu()->testingOnly_flushGpuAndSync();
  531. // Now that the draw is fully consumed by the GPU, the texture should be idle.
  532. REPORTER_ASSERT(reporter, idleIDs.find(2) != idleIDs.end());
  533. // Make a proxy that should deinstantiate even if we keep a ref on it.
  534. auto deinstantiateLazyCB = [&make, &context](GrResourceProvider* rp) {
  535. auto texture = make(context, 3);
  536. auto mode = GrSurfaceProxy::LazyInstantiationKeyMode::kSynced;
  537. if (texture->getUniqueKey().isValid()) {
  538. mode = GrSurfaceProxy::LazyInstantiationKeyMode::kUnsynced;
  539. }
  540. return GrSurfaceProxy::LazyInstantiationResult{std::move(texture), mode};
  541. };
  542. proxy = context->priv().proxyProvider()->createLazyProxy(
  543. deinstantiateLazyCB, backendFormat, desc, renderable, 1,
  544. GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin, GrMipMapped::kNo,
  545. GrInternalSurfaceFlags ::kNone, SkBackingFit::kExact, budgeted,
  546. GrProtected::kNo, GrSurfaceProxy::LazyInstantiationType::kDeinstantiate);
  547. rtc->drawTexture(GrNoClip(), std::move(proxy), GrSamplerState::Filter::kNearest,
  548. SkBlendMode::kSrcOver, SkPMColor4f(), SkRect::MakeWH(w, h),
  549. SkRect::MakeWH(w, h), GrAA::kNo, GrQuadAAFlags::kNone,
  550. SkCanvas::kFast_SrcRectConstraint, SkMatrix::I(), nullptr);
  551. // At this point the proxy shouldn't even be instantiated, there is no texture with
  552. // id 3.
  553. REPORTER_ASSERT(reporter, idleIDs.find(3) == idleIDs.end());
  554. context->flush();
  555. context->priv().getGpu()->testingOnly_flushGpuAndSync();
  556. // Now that the draw is fully consumed, we should have deinstantiated the proxy and
  557. // the texture it made should be idle.
  558. REPORTER_ASSERT(reporter, idleIDs.find(3) != idleIDs.end());
  559. // Make sure we make the call during various shutdown scenarios where the texture
  560. // might persist after context is destroyed, abandoned, etc. We test three
  561. // variations of each scenario. One where the texture is just created. Another,
  562. // where the texture has been used in a draw and then the context is flushed. And
  563. // one where the the texture was drawn but the context is not flushed.
  564. // In each scenario we test holding a ref beyond the context shutdown and not.
  565. // These tests are difficult to get working with Vulkan. See http://skbug.com/8705
  566. // and http://skbug.com/8275
  567. GrBackendApi api = sk_gpu_test::GrContextFactory::ContextTypeBackend(contextType);
  568. if (api == GrBackendApi::kVulkan) {
  569. continue;
  570. }
  571. int id = 4;
  572. enum class DrawType {
  573. kNoDraw,
  574. kDraw,
  575. kDrawAndFlush,
  576. };
  577. for (auto drawType :
  578. {DrawType::kNoDraw, DrawType::kDraw, DrawType::kDrawAndFlush}) {
  579. for (bool unrefFirst : {false, true}) {
  580. auto possiblyDrawAndFlush = [&context, &texture, drawType, unrefFirst, w,
  581. h] {
  582. if (drawType == DrawType::kNoDraw) {
  583. return;
  584. }
  585. SkImageInfo info = SkImageInfo::Make(w, h, kRGBA_8888_SkColorType,
  586. kPremul_SkAlphaType);
  587. auto rt = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info, 0,
  588. nullptr);
  589. auto rtc = rt->getCanvas()
  590. ->internal_private_accessTopLayerRenderTargetContext();
  591. auto proxy = context->priv().proxyProvider()->testingOnly_createWrapped(
  592. texture, kTopLeft_GrSurfaceOrigin);
  593. rtc->drawTexture(
  594. GrNoClip(), proxy, GrSamplerState::Filter::kNearest,
  595. SkBlendMode::kSrcOver, SkPMColor4f(), SkRect::MakeWH(w, h),
  596. SkRect::MakeWH(w, h), GrAA::kNo, GrQuadAAFlags::kNone,
  597. SkCanvas::kFast_SrcRectConstraint, SkMatrix::I(), nullptr);
  598. if (drawType == DrawType::kDrawAndFlush) {
  599. context->flush();
  600. }
  601. if (unrefFirst) {
  602. texture.reset();
  603. }
  604. };
  605. texture = make(context, id);
  606. possiblyDrawAndFlush();
  607. context->abandonContext();
  608. texture.reset();
  609. REPORTER_ASSERT(reporter, idleIDs.find(id) != idleIDs.end());
  610. factory.destroyContexts();
  611. context = factory.get(contextType);
  612. ++id;
  613. // Similar to previous, but reset the texture after the context was
  614. // abandoned and then destroyed.
  615. texture = make(context, id);
  616. possiblyDrawAndFlush();
  617. context->abandonContext();
  618. factory.destroyContexts();
  619. texture.reset();
  620. REPORTER_ASSERT(reporter, idleIDs.find(id) != idleIDs.end());
  621. context = factory.get(contextType);
  622. id++;
  623. texture = make(context, id);
  624. possiblyDrawAndFlush();
  625. factory.destroyContexts();
  626. texture.reset();
  627. REPORTER_ASSERT(reporter, idleIDs.find(id) != idleIDs.end());
  628. context = factory.get(contextType);
  629. id++;
  630. texture = make(context, id);
  631. possiblyDrawAndFlush();
  632. factory.releaseResourcesAndAbandonContexts();
  633. texture.reset();
  634. REPORTER_ASSERT(reporter, idleIDs.find(id) != idleIDs.end());
  635. context = factory.get(contextType);
  636. id++;
  637. }
  638. }
  639. }
  640. }
  641. }
  642. }
  643. // Tests an idle proc that unrefs another resource down to zero.
  644. DEF_GPUTEST_FOR_ALL_CONTEXTS(TextureIdleProcCacheManipulationTest, reporter, contextInfo) {
  645. GrContext* context = contextInfo.grContext();
  646. // idle proc that releases another texture.
  647. auto idleProc = [](void* texture) { reinterpret_cast<GrTexture*>(texture)->unref(); };
  648. for (const auto& idleMaker : {make_wrapped_texture, make_normal_texture}) {
  649. for (const auto& otherMaker : {make_wrapped_texture, make_normal_texture}) {
  650. for (auto idleState :
  651. {GrTexture::IdleState::kFlushed, GrTexture::IdleState::kFinished}) {
  652. auto idleTexture = idleMaker(context, GrRenderable::kNo);
  653. auto otherTexture = otherMaker(context, GrRenderable::kNo);
  654. otherTexture->ref();
  655. idleTexture->addIdleProc(idleProc, otherTexture.get(), idleState);
  656. otherTexture.reset();
  657. idleTexture.reset();
  658. }
  659. }
  660. }
  661. }
  662. // Similar to above but more complicated. This flushes the context from the idle proc.
  663. // crbug.com/933526.
  664. DEF_GPUTEST_FOR_ALL_CONTEXTS(TextureIdleProcFlushTest, reporter, contextInfo) {
  665. GrContext* context = contextInfo.grContext();
  666. // idle proc that flushes the context.
  667. auto idleProc = [](void* context) { reinterpret_cast<GrContext*>(context)->flush(); };
  668. for (const auto& idleMaker : {make_wrapped_texture, make_normal_texture}) {
  669. for (auto idleState : {GrTexture::IdleState::kFlushed, GrTexture::IdleState::kFinished}) {
  670. auto idleTexture = idleMaker(context, GrRenderable::kNo);
  671. idleTexture->addIdleProc(idleProc, context, idleState);
  672. auto info = SkImageInfo::Make(10, 10, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
  673. auto surf = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info, 1, nullptr);
  674. // We'll draw two images to the canvas. One is a normal texture-backed image. The other
  675. // is a wrapped-texture backed image.
  676. surf->getCanvas()->clear(SK_ColorWHITE);
  677. auto img1 = surf->makeImageSnapshot();
  678. GrBackendTexture backendTexture;
  679. if (!create_backend_texture(context, &backendTexture, info, SkColors::kBlack,
  680. GrMipMapped::kNo, GrRenderable::kNo)) {
  681. REPORTER_ASSERT(reporter, false);
  682. continue;
  683. }
  684. auto img2 = SkImage::MakeFromTexture(context, backendTexture, kTopLeft_GrSurfaceOrigin,
  685. info.colorType(), info.alphaType(), nullptr);
  686. surf->getCanvas()->drawImage(std::move(img1), 0, 0);
  687. surf->getCanvas()->drawImage(std::move(img2), 1, 1);
  688. idleTexture.reset();
  689. delete_backend_texture(context, backendTexture);
  690. }
  691. }
  692. }
  693. DEF_GPUTEST_FOR_ALL_CONTEXTS(TextureIdleProcRerefTest, reporter, contextInfo) {
  694. GrContext* context = contextInfo.grContext();
  695. // idle proc that refs the texture
  696. auto idleProc = [](void* texture) { reinterpret_cast<GrTexture*>(texture)->ref(); };
  697. // release proc to check whether the texture was released or not.
  698. auto releaseProc = [](void* isReleased) { *reinterpret_cast<bool*>(isReleased) = true; };
  699. for (auto idleState : {GrTexture::IdleState::kFlushed, GrTexture::IdleState::kFinished}) {
  700. bool isReleased = false;
  701. auto idleTexture = make_normal_texture(context, GrRenderable::kNo);
  702. // This test assumes the texture won't be cached (or else the release proc doesn't get
  703. // called).
  704. idleTexture->resourcePriv().removeScratchKey();
  705. context->flush();
  706. idleTexture->addIdleProc(idleProc, idleTexture.get(), idleState);
  707. idleTexture->setRelease(releaseProc, &isReleased);
  708. auto* raw = idleTexture.get();
  709. idleTexture.reset();
  710. REPORTER_ASSERT(reporter, !isReleased);
  711. raw->unref();
  712. REPORTER_ASSERT(reporter, isReleased);
  713. }
  714. }
  715. DEF_GPUTEST_FOR_ALL_CONTEXTS(TextureIdleStateTest, reporter, contextInfo) {
  716. GrContext* context = contextInfo.grContext();
  717. for (const auto& idleMaker : {make_wrapped_texture, make_normal_texture}) {
  718. auto idleTexture = idleMaker(context, GrRenderable::kNo);
  719. uint32_t flags = 0;
  720. static constexpr uint32_t kFlushFlag = 0x1;
  721. static constexpr uint32_t kFinishFlag = 0x2;
  722. auto flushProc = [](void* flags) { *static_cast<uint32_t*>(flags) |= kFlushFlag; };
  723. auto finishProc = [](void* flags) { *static_cast<uint32_t*>(flags) |= kFinishFlag; };
  724. idleTexture->addIdleProc(flushProc, &flags, GrTexture::IdleState::kFlushed);
  725. idleTexture->addIdleProc(finishProc, &flags, GrTexture::IdleState::kFinished);
  726. // Insert a copy from idleTexture to another texture so that we have some queued IO on
  727. // idleTexture.
  728. SkImageInfo info = SkImageInfo::Make(kSurfSize, kSurfSize, kRGBA_8888_SkColorType,
  729. kPremul_SkAlphaType);
  730. auto rt = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info, 0, nullptr);
  731. auto rtc = rt->getCanvas()->internal_private_accessTopLayerRenderTargetContext();
  732. auto proxy = context->priv().proxyProvider()->testingOnly_createWrapped(
  733. std::move(idleTexture), rtc->asSurfaceProxy()->origin());
  734. context->flush();
  735. SkAssertResult(rtc->testCopy(proxy.get()));
  736. proxy.reset();
  737. REPORTER_ASSERT(reporter, flags == 0);
  738. // After a flush we expect idleTexture to have reached the kFlushed state on all backends.
  739. // On "managed" backends we expect it to reach kFinished as well. On Vulkan, the only
  740. // current "unmanaged" backend, we *may* need a sync to reach kFinished.
  741. context->flush();
  742. if (contextInfo.backend() == kVulkan_GrBackend) {
  743. REPORTER_ASSERT(reporter, flags & kFlushFlag);
  744. } else {
  745. REPORTER_ASSERT(reporter, flags == (kFlushFlag | kFinishFlag));
  746. }
  747. context->priv().getGpu()->testingOnly_flushGpuAndSync();
  748. REPORTER_ASSERT(reporter, flags == (kFlushFlag | kFinishFlag));
  749. }
  750. }