VkBackendSurfaceTest.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  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. // This is a GPU-backend specific test. It relies on static intializers to work
  8. #include "include/core/SkTypes.h"
  9. #if defined(SK_VULKAN)
  10. #include "include/gpu/vk/GrVkVulkan.h"
  11. #include "tests/Test.h"
  12. #include "include/core/SkImage.h"
  13. #include "include/gpu/GrBackendSurface.h"
  14. #include "include/gpu/GrTexture.h"
  15. #include "include/gpu/vk/GrVkTypes.h"
  16. #include "src/gpu/GrContextPriv.h"
  17. #include "src/gpu/GrRenderTargetContext.h"
  18. #include "src/gpu/GrTextureProxy.h"
  19. #include "src/gpu/SkGpuDevice.h"
  20. #include "src/gpu/vk/GrVkGpu.h"
  21. #include "src/gpu/vk/GrVkImageLayout.h"
  22. #include "src/gpu/vk/GrVkTexture.h"
  23. #include "src/image/SkImage_Base.h"
  24. #include "src/image/SkSurface_Gpu.h"
  25. DEF_GPUTEST_FOR_VULKAN_CONTEXT(VkImageLayoutTest, reporter, ctxInfo) {
  26. GrContext* context = ctxInfo.grContext();
  27. GrBackendTexture backendTex = context->createBackendTexture(1, 1,
  28. kRGBA_8888_SkColorType,
  29. SkColors::kTransparent,
  30. GrMipMapped::kNo,
  31. GrRenderable::kNo,
  32. GrProtected::kNo);
  33. REPORTER_ASSERT(reporter, backendTex.isValid());
  34. GrVkImageInfo info;
  35. REPORTER_ASSERT(reporter, backendTex.getVkImageInfo(&info));
  36. VkImageLayout initLayout = info.fImageLayout;
  37. // Verify that setting that layout via a copy of a backendTexture is reflected in all the
  38. // backendTextures.
  39. GrBackendTexture backendTexCopy = backendTex;
  40. REPORTER_ASSERT(reporter, backendTexCopy.getVkImageInfo(&info));
  41. REPORTER_ASSERT(reporter, initLayout == info.fImageLayout);
  42. backendTexCopy.setVkImageLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
  43. REPORTER_ASSERT(reporter, backendTex.getVkImageInfo(&info));
  44. REPORTER_ASSERT(reporter, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == info.fImageLayout);
  45. REPORTER_ASSERT(reporter, backendTexCopy.getVkImageInfo(&info));
  46. REPORTER_ASSERT(reporter, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == info.fImageLayout);
  47. // Setting back the layout since we didn't actually change it
  48. backendTex.setVkImageLayout(initLayout);
  49. sk_sp<SkImage> wrappedImage = SkImage::MakeFromTexture(context, backendTex,
  50. kTopLeft_GrSurfaceOrigin,
  51. kRGBA_8888_SkColorType,
  52. kPremul_SkAlphaType, nullptr);
  53. REPORTER_ASSERT(reporter, wrappedImage.get());
  54. sk_sp<GrTextureProxy> texProxy = as_IB(wrappedImage)->asTextureProxyRef(context);
  55. REPORTER_ASSERT(reporter, texProxy.get());
  56. REPORTER_ASSERT(reporter, texProxy->isInstantiated());
  57. GrTexture* texture = texProxy->peekTexture();
  58. REPORTER_ASSERT(reporter, texture);
  59. // Verify that modifying the layout via the GrVkTexture is reflected in the GrBackendTexture
  60. GrVkTexture* vkTexture = static_cast<GrVkTexture*>(texture);
  61. REPORTER_ASSERT(reporter, initLayout == vkTexture->currentLayout());
  62. vkTexture->updateImageLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
  63. REPORTER_ASSERT(reporter, backendTex.getVkImageInfo(&info));
  64. REPORTER_ASSERT(reporter, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == info.fImageLayout);
  65. GrBackendTexture backendTexImage = wrappedImage->getBackendTexture(false);
  66. REPORTER_ASSERT(reporter, backendTexImage.getVkImageInfo(&info));
  67. REPORTER_ASSERT(reporter, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == info.fImageLayout);
  68. // Verify that modifying the layout via the GrBackendTexutre is reflected in the GrVkTexture
  69. backendTexImage.setVkImageLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
  70. REPORTER_ASSERT(reporter, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL == vkTexture->currentLayout());
  71. vkTexture->updateImageLayout(initLayout);
  72. REPORTER_ASSERT(reporter, backendTex.getVkImageInfo(&info));
  73. REPORTER_ASSERT(reporter, initLayout == info.fImageLayout);
  74. REPORTER_ASSERT(reporter, backendTexCopy.getVkImageInfo(&info));
  75. REPORTER_ASSERT(reporter, initLayout == info.fImageLayout);
  76. REPORTER_ASSERT(reporter, backendTexImage.getVkImageInfo(&info));
  77. REPORTER_ASSERT(reporter, initLayout == info.fImageLayout);
  78. // Check that we can do things like assigning the backend texture to invalid one, assign an
  79. // invalid one, assin a backend texture to inself etc. Success here is that we don't hit any of
  80. // our ref counting asserts.
  81. REPORTER_ASSERT(reporter, GrBackendTexture::TestingOnly_Equals(backendTex, backendTexCopy));
  82. GrBackendTexture invalidTexture;
  83. REPORTER_ASSERT(reporter, !invalidTexture.isValid());
  84. REPORTER_ASSERT(reporter, !GrBackendTexture::TestingOnly_Equals(invalidTexture, backendTexCopy));
  85. backendTexCopy = invalidTexture;
  86. REPORTER_ASSERT(reporter, !backendTexCopy.isValid());
  87. REPORTER_ASSERT(reporter, !GrBackendTexture::TestingOnly_Equals(invalidTexture, backendTexCopy));
  88. invalidTexture = backendTex;
  89. REPORTER_ASSERT(reporter, invalidTexture.isValid());
  90. REPORTER_ASSERT(reporter, GrBackendTexture::TestingOnly_Equals(invalidTexture, backendTex));
  91. invalidTexture = static_cast<decltype(invalidTexture)&>(invalidTexture);
  92. REPORTER_ASSERT(reporter, invalidTexture.isValid());
  93. REPORTER_ASSERT(reporter, GrBackendTexture::TestingOnly_Equals(invalidTexture, invalidTexture));
  94. context->deleteBackendTexture(backendTex);
  95. }
  96. static void testing_release_proc(void* ctx) {
  97. int* count = (int*)ctx;
  98. *count += 1;
  99. }
  100. // Test to make sure we don't call our release proc on an image until we've transferred it back to
  101. // its original queue family.
  102. DEF_GPUTEST_FOR_VULKAN_CONTEXT(VkReleaseExternalQueueTest, reporter, ctxInfo) {
  103. GrContext* context = ctxInfo.grContext();
  104. GrGpu* gpu = context->priv().getGpu();
  105. GrVkGpu* vkGpu = static_cast<GrVkGpu*>(gpu);
  106. if (!vkGpu->vkCaps().supportsExternalMemory()) {
  107. return;
  108. }
  109. for (bool useExternal : {false, true}) {
  110. GrBackendTexture backendTex = context->createBackendTexture(1, 1,
  111. kRGBA_8888_SkColorType,
  112. SkColors::kTransparent,
  113. GrMipMapped::kNo,
  114. GrRenderable::kNo,
  115. GrProtected::kNo);
  116. sk_sp<SkImage> image;
  117. int count = 0;
  118. if (useExternal) {
  119. // Make a backend texture with an external queue family;
  120. GrVkImageInfo vkInfo;
  121. if (!backendTex.getVkImageInfo(&vkInfo)) {
  122. return;
  123. }
  124. vkInfo.fCurrentQueueFamily = VK_QUEUE_FAMILY_EXTERNAL;
  125. GrBackendTexture vkExtTex(1, 1, vkInfo);
  126. REPORTER_ASSERT(reporter, vkExtTex.isValid());
  127. image = SkImage::MakeFromTexture(context, vkExtTex,
  128. kTopLeft_GrSurfaceOrigin,
  129. kRGBA_8888_SkColorType,
  130. kPremul_SkAlphaType,
  131. nullptr, testing_release_proc,
  132. (void*)&count);
  133. } else {
  134. image = SkImage::MakeFromTexture(context, backendTex,
  135. kTopLeft_GrSurfaceOrigin,
  136. kRGBA_8888_SkColorType,
  137. kPremul_SkAlphaType,
  138. nullptr, testing_release_proc,
  139. (void*)&count);
  140. }
  141. if (!image) {
  142. continue;
  143. }
  144. REPORTER_ASSERT(reporter, !count);
  145. GrTexture* texture = image->getTexture();
  146. REPORTER_ASSERT(reporter, texture);
  147. GrVkTexture* vkTex = static_cast<GrVkTexture*>(texture);
  148. if (useExternal) {
  149. // Testing helper so we claim that we don't need to transition from our fake external
  150. // queue first.
  151. vkTex->setCurrentQueueFamilyToGraphicsQueue(vkGpu);
  152. }
  153. image.reset();
  154. // Resetting the image should only trigger the release proc if we are not using an external
  155. // queue. When using an external queue when we free the SkImage and the underlying
  156. // GrTexture, we submit a queue transition on the command buffer.
  157. if (useExternal) {
  158. REPORTER_ASSERT(reporter, !count);
  159. } else {
  160. REPORTER_ASSERT(reporter, count == 1);
  161. }
  162. gpu->testingOnly_flushGpuAndSync();
  163. // Now that we flushed and waited the release proc should have be triggered.
  164. REPORTER_ASSERT(reporter, count == 1);
  165. context->deleteBackendTexture(backendTex);
  166. }
  167. }
  168. // Test to make sure we transition to the original queue when requests for prepareforexternalio are
  169. // in flush calls
  170. DEF_GPUTEST_FOR_VULKAN_CONTEXT(VkPrepareForExternalIOQueueTransitionTest, reporter, ctxInfo) {
  171. GrContext* context = ctxInfo.grContext();
  172. GrVkGpu* vkGpu = static_cast<GrVkGpu*>(context->priv().getGpu());
  173. if (!vkGpu->vkCaps().supportsExternalMemory()) {
  174. return;
  175. }
  176. for (bool useSurface : {false, true}) {
  177. for (bool preparePresent : {false, true}) {
  178. if (!useSurface && preparePresent) {
  179. // We don't set textures to present
  180. continue;
  181. }
  182. GrBackendTexture backendTex = context->createBackendTexture(
  183. 4, 4, kRGBA_8888_SkColorType,
  184. SkColors::kTransparent, GrMipMapped::kNo,
  185. useSurface ? GrRenderable::kYes : GrRenderable::kNo,
  186. GrProtected::kNo);
  187. // Make a backend texture with an external queue family and general layout.
  188. GrVkImageInfo vkInfo;
  189. if (!backendTex.getVkImageInfo(&vkInfo)) {
  190. return;
  191. }
  192. // We can't actually make an external texture in our test. However, we lie and say it is
  193. // and then will manually go and swap the queue to the graphics queue once we wrap it.
  194. if (preparePresent) {
  195. // We don't transition to present to things that are going to external for foreign
  196. // queues.
  197. vkInfo.fCurrentQueueFamily = vkGpu->queueIndex();
  198. } else {
  199. vkInfo.fCurrentQueueFamily = VK_QUEUE_FAMILY_EXTERNAL;
  200. }
  201. GrBackendTexture vkExtTex(1, 1, vkInfo);
  202. sk_sp<SkImage> image;
  203. sk_sp<SkSurface> surface;
  204. GrTexture* texture;
  205. if (useSurface) {
  206. surface = SkSurface::MakeFromBackendTexture(context, vkExtTex,
  207. kTopLeft_GrSurfaceOrigin, 0, kRGBA_8888_SkColorType, nullptr, nullptr);
  208. REPORTER_ASSERT(reporter, surface.get());
  209. if (!surface) {
  210. continue;
  211. }
  212. SkSurface_Gpu* gpuSurface = static_cast<SkSurface_Gpu*>(surface.get());
  213. auto* rtc = gpuSurface->getDevice()->accessRenderTargetContext();
  214. texture = rtc->asTextureProxy()->peekTexture();
  215. } else {
  216. image = SkImage::MakeFromTexture(context, vkExtTex, kTopLeft_GrSurfaceOrigin,
  217. kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr, nullptr, nullptr);
  218. REPORTER_ASSERT(reporter, image.get());
  219. if (!image) {
  220. continue;
  221. }
  222. texture = image->getTexture();
  223. }
  224. REPORTER_ASSERT(reporter, texture);
  225. GrVkTexture* vkTex = static_cast<GrVkTexture*>(texture);
  226. // Testing helper so we claim that we don't need to transition from our fake external
  227. // queue first.
  228. vkTex->setCurrentQueueFamilyToGraphicsQueue(vkGpu);
  229. GrBackendTexture newBackendTexture;
  230. if (useSurface) {
  231. newBackendTexture = surface->getBackendTexture(
  232. SkSurface::kFlushRead_TextureHandleAccess);
  233. } else {
  234. newBackendTexture = image->getBackendTexture(false);
  235. }
  236. GrVkImageInfo newVkInfo;
  237. REPORTER_ASSERT(reporter, newBackendTexture.getVkImageInfo(&newVkInfo));
  238. REPORTER_ASSERT(reporter, newVkInfo.fCurrentQueueFamily == vkGpu->queueIndex());
  239. VkImageLayout oldLayout = newVkInfo.fImageLayout;
  240. GrPrepareForExternalIORequests externalRequests;
  241. SkImage* imagePtr;
  242. SkSurface* surfacePtr;
  243. if (useSurface) {
  244. externalRequests.fNumSurfaces = 1;
  245. surfacePtr = surface.get();
  246. externalRequests.fSurfaces = &surfacePtr;
  247. externalRequests.fPrepareSurfaceForPresent = &preparePresent;
  248. } else {
  249. externalRequests.fNumImages = 1;
  250. imagePtr = image.get();
  251. externalRequests.fImages = &imagePtr;
  252. }
  253. context->flush(GrFlushInfo(), externalRequests);
  254. if (useSurface) {
  255. newBackendTexture = surface->getBackendTexture(
  256. SkSurface::kFlushRead_TextureHandleAccess);
  257. } else {
  258. newBackendTexture = image->getBackendTexture(false);
  259. }
  260. REPORTER_ASSERT(reporter, newBackendTexture.getVkImageInfo(&newVkInfo));
  261. if (preparePresent) {
  262. REPORTER_ASSERT(reporter, newVkInfo.fCurrentQueueFamily == vkGpu->queueIndex());
  263. REPORTER_ASSERT(reporter,
  264. newVkInfo.fImageLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
  265. } else {
  266. REPORTER_ASSERT(reporter, newVkInfo.fCurrentQueueFamily == VK_QUEUE_FAMILY_EXTERNAL);
  267. REPORTER_ASSERT(reporter, newVkInfo.fImageLayout == oldLayout);
  268. }
  269. GrFlushInfo flushInfo;
  270. flushInfo.fFlags = kSyncCpu_GrFlushFlag;
  271. context->flush(flushInfo);
  272. context->deleteBackendTexture(backendTex);
  273. }
  274. }
  275. }
  276. // This test is disabled because it executes illegal vulkan calls which cause the validations layers
  277. // to fail and makes us assert. Once fixed to use a valid vulkan call sequence it should be
  278. // renenabled, see skbug.com/8936.
  279. #if 0
  280. // Test to make sure we transition from the EXTERNAL queue even when no layout transition is needed.
  281. DEF_GPUTEST_FOR_VULKAN_CONTEXT(VkTransitionExternalQueueTest, reporter, ctxInfo) {
  282. GrContext* context = ctxInfo.grContext();
  283. GrGpu* gpu = context->priv().getGpu();
  284. GrVkGpu* vkGpu = static_cast<GrVkGpu*>(gpu);
  285. if (!vkGpu->vkCaps().supportsExternalMemory()) {
  286. return;
  287. }
  288. GrBackendTexture backendTex = context->createBackendTexture(
  289. 1, 1, kRGBA_8888_SkColorType,
  290. SkColors::kTransparent, GrMipMapped::kNo, GrRenderable::kNo);
  291. sk_sp<SkImage> image;
  292. // Make a backend texture with an external queue family and general layout.
  293. GrVkImageInfo vkInfo;
  294. if (!backendTex.getVkImageInfo(&vkInfo)) {
  295. return;
  296. }
  297. vkInfo.fCurrentQueueFamily = VK_QUEUE_FAMILY_EXTERNAL;
  298. // Use a read-only layout as these are the ones where we can otherwise skip a transition.
  299. vkInfo.fImageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
  300. GrBackendTexture vkExtTex(1, 1, vkInfo);
  301. REPORTER_ASSERT(reporter, vkExtTex.isValid());
  302. image = SkImage::MakeFromTexture(context, vkExtTex, kTopLeft_GrSurfaceOrigin,
  303. kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr, nullptr,
  304. nullptr);
  305. if (!image) {
  306. return;
  307. }
  308. GrTexture* texture = image->getTexture();
  309. REPORTER_ASSERT(reporter, texture);
  310. GrVkTexture* vkTex = static_cast<GrVkTexture*>(texture);
  311. // Change our backend texture to the internal queue, with the same layout. This should force a
  312. // queue transition even though the layouts match.
  313. vkTex->setImageLayout(vkGpu, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 0,
  314. VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, false, false);
  315. // Get our image info again and make sure we transitioned queues.
  316. GrBackendTexture newBackendTexture = image->getBackendTexture(true);
  317. GrVkImageInfo newVkInfo;
  318. REPORTER_ASSERT(reporter, newBackendTexture.getVkImageInfo(&newVkInfo));
  319. REPORTER_ASSERT(reporter, newVkInfo.fCurrentQueueFamily == vkGpu->queueIndex());
  320. image.reset();
  321. gpu->testingOnly_flushGpuAndSync();
  322. context->deleteBackendTexture(backendTex);
  323. }
  324. #endif
  325. #endif