VkDrawableTest.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  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 SK_SUPPORT_GPU && defined(SK_VULKAN)
  10. #include "include/gpu/vk/GrVkVulkan.h"
  11. #include "include/core/SkDrawable.h"
  12. #include "include/core/SkSurface.h"
  13. #include "include/gpu/GrBackendDrawableInfo.h"
  14. #include "src/gpu/GrContextPriv.h"
  15. #include "src/gpu/vk/GrVkGpu.h"
  16. #include "src/gpu/vk/GrVkInterface.h"
  17. #include "src/gpu/vk/GrVkMemory.h"
  18. #include "src/gpu/vk/GrVkSecondaryCBDrawContext.h"
  19. #include "src/gpu/vk/GrVkUtil.h"
  20. #include "tests/Test.h"
  21. #include "tools/gpu/GrContextFactory.h"
  22. using sk_gpu_test::GrContextFactory;
  23. static const int DEV_W = 16, DEV_H = 16;
  24. class TestDrawable : public SkDrawable {
  25. public:
  26. TestDrawable(const GrVkInterface* interface, GrContext* context, int32_t width, int32_t height)
  27. : INHERITED()
  28. , fInterface(interface)
  29. , fContext(context)
  30. , fWidth(width)
  31. , fHeight(height) {}
  32. ~TestDrawable() override {}
  33. class DrawHandlerBasic : public GpuDrawHandler {
  34. public:
  35. DrawHandlerBasic(const GrVkInterface* interface, int32_t width, int32_t height)
  36. : INHERITED()
  37. , fInterface(interface)
  38. , fWidth(width)
  39. , fHeight(height) {}
  40. ~DrawHandlerBasic() override {}
  41. void draw(const GrBackendDrawableInfo& info) override {
  42. GrVkDrawableInfo vkInfo;
  43. SkAssertResult(info.getVkDrawableInfo(&vkInfo));
  44. // Clear to Red
  45. VkClearColorValue vkColor;
  46. vkColor.float32[0] = 1.0f; // r
  47. vkColor.float32[1] = 0.0f; // g
  48. vkColor.float32[2] = 0.0f; // b
  49. vkColor.float32[3] = 1.0f; // a
  50. // Clear right half of render target
  51. VkClearRect clearRect;
  52. clearRect.rect.offset = { fWidth / 2, 0 };
  53. clearRect.rect.extent = { (uint32_t)fWidth / 2, (uint32_t)fHeight };
  54. clearRect.baseArrayLayer = 0;
  55. clearRect.layerCount = 1;
  56. VkClearAttachment attachment;
  57. attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  58. attachment.colorAttachment = vkInfo.fColorAttachmentIndex;
  59. attachment.clearValue.color = vkColor;
  60. GR_VK_CALL(fInterface, CmdClearAttachments(vkInfo.fSecondaryCommandBuffer,
  61. 1,
  62. &attachment,
  63. 1,
  64. &clearRect));
  65. vkInfo.fDrawBounds->offset = { fWidth / 2, 0 };
  66. vkInfo.fDrawBounds->extent = { (uint32_t)fWidth / 2, (uint32_t)fHeight };
  67. }
  68. private:
  69. const GrVkInterface* fInterface;
  70. int32_t fWidth;
  71. int32_t fHeight;
  72. typedef GpuDrawHandler INHERITED;
  73. };
  74. typedef void (*DrawProc)(TestDrawable*, const SkMatrix&, const SkIRect&,
  75. const SkImageInfo&, const GrVkDrawableInfo&);
  76. typedef void (*SubmitProc)(TestDrawable*);
  77. // Exercises the exporting of a secondary command buffer from one GrContext and then importing
  78. // it into a second GrContext. We then draw to the secondary command buffer from the second
  79. // GrContext.
  80. class DrawHandlerImport : public GpuDrawHandler {
  81. public:
  82. DrawHandlerImport(TestDrawable* td, DrawProc drawProc, SubmitProc submitProc,
  83. const SkMatrix& matrix,
  84. const SkIRect& clipBounds,
  85. const SkImageInfo& bufferInfo)
  86. : INHERITED()
  87. , fTestDrawable(td)
  88. , fDrawProc(drawProc)
  89. , fSubmitProc(submitProc)
  90. , fMatrix(matrix)
  91. , fClipBounds(clipBounds)
  92. , fBufferInfo(bufferInfo) {}
  93. ~DrawHandlerImport() override {
  94. fSubmitProc(fTestDrawable);
  95. }
  96. void draw(const GrBackendDrawableInfo& info) override {
  97. GrVkDrawableInfo vkInfo;
  98. SkAssertResult(info.getVkDrawableInfo(&vkInfo));
  99. fDrawProc(fTestDrawable, fMatrix, fClipBounds, fBufferInfo, vkInfo);
  100. }
  101. private:
  102. TestDrawable* fTestDrawable;
  103. DrawProc fDrawProc;
  104. SubmitProc fSubmitProc;
  105. const SkMatrix fMatrix;
  106. const SkIRect fClipBounds;
  107. const SkImageInfo fBufferInfo;
  108. typedef GpuDrawHandler INHERITED;
  109. };
  110. // Helper function to test drawing to a secondary command buffer that we imported into the
  111. // GrContext using a GrVkSecondaryCBDrawContext.
  112. static void ImportDraw(TestDrawable* td, const SkMatrix& matrix, const SkIRect& clipBounds,
  113. const SkImageInfo& bufferInfo, const GrVkDrawableInfo& info) {
  114. td->fDrawContext = GrVkSecondaryCBDrawContext::Make(td->fContext, bufferInfo, info, nullptr);
  115. if (!td->fDrawContext) {
  116. return;
  117. }
  118. SkCanvas* canvas = td->fDrawContext->getCanvas();
  119. canvas->clipRect(SkRect::Make(clipBounds));
  120. canvas->setMatrix(matrix);
  121. SkIRect rect = SkIRect::MakeXYWH(td->fWidth/2, 0, td->fWidth/4, td->fHeight);
  122. SkPaint paint;
  123. paint.setColor(SK_ColorRED);
  124. canvas->drawIRect(rect, paint);
  125. // Draw to an offscreen target so that we end up with a mix of "real" secondary command
  126. // buffers and the imported secondary command buffer.
  127. sk_sp<SkSurface> surf = SkSurface::MakeRenderTarget(td->fContext, SkBudgeted::kYes,
  128. bufferInfo);
  129. surf->getCanvas()->clear(SK_ColorRED);
  130. SkRect dstRect = SkRect::MakeXYWH(3*td->fWidth/4, 0, td->fWidth/4, td->fHeight);
  131. SkIRect srcRect = SkIRect::MakeWH(td->fWidth/4, td->fHeight);
  132. canvas->drawImageRect(surf->makeImageSnapshot(), srcRect, dstRect, &paint);
  133. td->fDrawContext->flush();
  134. }
  135. // Helper function to test waiting for the imported secondary command buffer to be submitted on
  136. // its original context and then cleaning up the GrVkSecondaryCBDrawContext from this GrContext.
  137. static void ImportSubmitted(TestDrawable* td) {
  138. // Typical use case here would be to create a fence that we submit to the gpu and then wait
  139. // on before releasing the GrVkSecondaryCBDrawContext resources. To simulate that for this
  140. // test (and since we are running single threaded anyways), we will just force a sync of
  141. // the gpu and cpu here.
  142. td->fContext->priv().getGpu()->testingOnly_flushGpuAndSync();
  143. td->fDrawContext->releaseResources();
  144. // We release the GrContext here manually to test that we waited long enough before
  145. // releasing the GrVkSecondaryCBDrawContext. This simulates when a client is able to delete
  146. // the GrContext it used to imported the secondary command buffer. If we had released the
  147. // GrContext's resources earlier (before waiting on the gpu above), we would get vulkan
  148. // validation layer errors saying we freed some vulkan objects while they were still in use
  149. // on the GPU.
  150. td->fContext->releaseResourcesAndAbandonContext();
  151. }
  152. std::unique_ptr<GpuDrawHandler> onSnapGpuDrawHandler(GrBackendApi backendApi,
  153. const SkMatrix& matrix,
  154. const SkIRect& clipBounds,
  155. const SkImageInfo& bufferInfo) override {
  156. if (backendApi != GrBackendApi::kVulkan) {
  157. return nullptr;
  158. }
  159. std::unique_ptr<GpuDrawHandler> draw;
  160. if (fContext) {
  161. draw.reset(new DrawHandlerImport(this, ImportDraw, ImportSubmitted, matrix,
  162. clipBounds, bufferInfo));
  163. } else {
  164. draw.reset(new DrawHandlerBasic(fInterface, fWidth, fHeight));
  165. }
  166. return draw;
  167. }
  168. SkRect onGetBounds() override {
  169. return SkRect::MakeLTRB(fWidth / 2, 0, fWidth, fHeight);
  170. }
  171. void onDraw(SkCanvas*) override {
  172. SkASSERT(false);
  173. }
  174. private:
  175. const GrVkInterface* fInterface;
  176. GrContext* fContext;
  177. sk_sp<GrVkSecondaryCBDrawContext> fDrawContext;
  178. int32_t fWidth;
  179. int32_t fHeight;
  180. typedef SkDrawable INHERITED;
  181. };
  182. void draw_drawable_test(skiatest::Reporter* reporter, GrContext* context, GrContext* childContext) {
  183. GrVkGpu* gpu = static_cast<GrVkGpu*>(context->priv().getGpu());
  184. const SkImageInfo ii = SkImageInfo::Make(DEV_W, DEV_H, kRGBA_8888_SkColorType,
  185. kPremul_SkAlphaType);
  186. sk_sp<SkSurface> surface(SkSurface::MakeRenderTarget(context, SkBudgeted::kNo,
  187. ii, 0, kTopLeft_GrSurfaceOrigin, nullptr));
  188. SkCanvas* canvas = surface->getCanvas();
  189. canvas->clear(SK_ColorBLUE);
  190. sk_sp<TestDrawable> drawable(new TestDrawable(gpu->vkInterface(), childContext, DEV_W, DEV_H));
  191. canvas->drawDrawable(drawable.get());
  192. SkPaint paint;
  193. paint.setColor(SK_ColorGREEN);
  194. SkIRect rect = SkIRect::MakeLTRB(0, DEV_H/2, DEV_W, DEV_H);
  195. canvas->drawIRect(rect, paint);
  196. // read pixels
  197. SkBitmap bitmap;
  198. bitmap.allocPixels(ii);
  199. canvas->readPixels(bitmap, 0, 0);
  200. const uint32_t* canvasPixels = static_cast<const uint32_t*>(bitmap.getPixels());
  201. bool failureFound = false;
  202. SkPMColor expectedPixel;
  203. for (int cy = 0; cy < DEV_H && !failureFound; ++cy) {
  204. for (int cx = 0; cx < DEV_W && !failureFound; ++cx) {
  205. SkPMColor canvasPixel = canvasPixels[cy * DEV_W + cx];
  206. if (cy < DEV_H / 2) {
  207. if (cx < DEV_W / 2) {
  208. expectedPixel = 0xFFFF0000; // Blue
  209. } else {
  210. expectedPixel = 0xFF0000FF; // Red
  211. }
  212. } else {
  213. expectedPixel = 0xFF00FF00; // Green
  214. }
  215. if (expectedPixel != canvasPixel) {
  216. failureFound = true;
  217. ERRORF(reporter, "Wrong color at %d, %d. Got 0x%08x when we expected 0x%08x",
  218. cx, cy, canvasPixel, expectedPixel);
  219. }
  220. }
  221. }
  222. }
  223. DEF_GPUTEST_FOR_VULKAN_CONTEXT(VkDrawableTest, reporter, ctxInfo) {
  224. draw_drawable_test(reporter, ctxInfo.grContext(), nullptr);
  225. }
  226. DEF_GPUTEST(VkDrawableImportTest, reporter, options) {
  227. for (int typeInt = 0; typeInt < sk_gpu_test::GrContextFactory::kContextTypeCnt; ++typeInt) {
  228. sk_gpu_test::GrContextFactory::ContextType contextType =
  229. (sk_gpu_test::GrContextFactory::ContextType) typeInt;
  230. if (contextType != sk_gpu_test::GrContextFactory::kVulkan_ContextType) {
  231. continue;
  232. }
  233. sk_gpu_test::GrContextFactory factory(options);
  234. sk_gpu_test::ContextInfo ctxInfo = factory.getContextInfo(contextType);
  235. skiatest::ReporterContext ctx(
  236. reporter, SkString(sk_gpu_test::GrContextFactory::ContextTypeName(contextType)));
  237. if (ctxInfo.grContext()) {
  238. sk_gpu_test::ContextInfo child =
  239. factory.getSharedContextInfo(ctxInfo.grContext(), 0);
  240. if (!child.grContext()) {
  241. continue;
  242. }
  243. draw_drawable_test(reporter, ctxInfo.grContext(), child.grContext());
  244. }
  245. }
  246. }
  247. #endif