blob: 38378dc1fab59941eacc5143e9efca75c4a92448 [file] [log] [blame]
Greg Daniel64cc9aa2018-10-19 13:54:56 -04001/*
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// This is a GPU-backend specific test. It relies on static intializers to work
9
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/core/SkTypes.h"
Greg Daniel64cc9aa2018-10-19 13:54:56 -040011
12#if SK_SUPPORT_GPU && defined(SK_VULKAN)
13
Mike Kleinc0bd9f92019-04-23 12:05:21 -050014#include "include/gpu/vk/GrVkVulkan.h"
Greg Daniel54bfb182018-11-20 17:12:36 -050015
Mike Kleinc0bd9f92019-04-23 12:05:21 -050016#include "include/core/SkDrawable.h"
17#include "include/core/SkSurface.h"
18#include "include/gpu/GrBackendDrawableInfo.h"
Robert Phillips6d344c32020-07-06 10:56:46 -040019#include "include/gpu/GrDirectContext.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050020#include "src/gpu/GrContextPriv.h"
21#include "src/gpu/vk/GrVkGpu.h"
22#include "src/gpu/vk/GrVkInterface.h"
23#include "src/gpu/vk/GrVkMemory.h"
24#include "src/gpu/vk/GrVkSecondaryCBDrawContext.h"
25#include "src/gpu/vk/GrVkUtil.h"
26#include "tests/Test.h"
27#include "tools/gpu/GrContextFactory.h"
Greg Daniel64cc9aa2018-10-19 13:54:56 -040028
29using sk_gpu_test::GrContextFactory;
30
31static const int DEV_W = 16, DEV_H = 16;
32
33class TestDrawable : public SkDrawable {
34public:
Robert Phillipsb25e0652020-07-22 09:35:49 -040035 TestDrawable(const GrVkInterface* interface, GrDirectContext* dContext,
36 int32_t width, int32_t height)
Greg Daniel64cc9aa2018-10-19 13:54:56 -040037 : INHERITED()
38 , fInterface(interface)
Robert Phillipsb25e0652020-07-22 09:35:49 -040039 , fDContext(dContext)
Greg Daniel64cc9aa2018-10-19 13:54:56 -040040 , fWidth(width)
41 , fHeight(height) {}
42
43 ~TestDrawable() override {}
44
Greg Daniel070cbaf2019-01-03 17:35:54 -050045 class DrawHandlerBasic : public GpuDrawHandler {
Greg Daniel64cc9aa2018-10-19 13:54:56 -040046 public:
Greg Daniel070cbaf2019-01-03 17:35:54 -050047 DrawHandlerBasic(const GrVkInterface* interface, int32_t width, int32_t height)
Greg Daniel64cc9aa2018-10-19 13:54:56 -040048 : INHERITED()
49 , fInterface(interface)
50 , fWidth(width)
51 , fHeight(height) {}
Greg Daniel070cbaf2019-01-03 17:35:54 -050052 ~DrawHandlerBasic() override {}
Greg Daniel64cc9aa2018-10-19 13:54:56 -040053
54 void draw(const GrBackendDrawableInfo& info) override {
55 GrVkDrawableInfo vkInfo;
56 SkAssertResult(info.getVkDrawableInfo(&vkInfo));
57
58 // Clear to Red
59 VkClearColorValue vkColor;
60 vkColor.float32[0] = 1.0f; // r
61 vkColor.float32[1] = 0.0f; // g
62 vkColor.float32[2] = 0.0f; // b
63 vkColor.float32[3] = 1.0f; // a
64
65 // Clear right half of render target
66 VkClearRect clearRect;
67 clearRect.rect.offset = { fWidth / 2, 0 };
68 clearRect.rect.extent = { (uint32_t)fWidth / 2, (uint32_t)fHeight };
69 clearRect.baseArrayLayer = 0;
70 clearRect.layerCount = 1;
71
72 VkClearAttachment attachment;
73 attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
Greg Danielb353eeb2018-12-05 11:01:58 -050074 attachment.colorAttachment = vkInfo.fColorAttachmentIndex;
Greg Daniel64cc9aa2018-10-19 13:54:56 -040075 attachment.clearValue.color = vkColor;
76
77 GR_VK_CALL(fInterface, CmdClearAttachments(vkInfo.fSecondaryCommandBuffer,
78 1,
79 &attachment,
80 1,
81 &clearRect));
82 vkInfo.fDrawBounds->offset = { fWidth / 2, 0 };
83 vkInfo.fDrawBounds->extent = { (uint32_t)fWidth / 2, (uint32_t)fHeight };
84 }
85 private:
86 const GrVkInterface* fInterface;
87 int32_t fWidth;
88 int32_t fHeight;
89
90 typedef GpuDrawHandler INHERITED;
91 };
92
Derek Sollenbergere6fb76b2019-01-10 13:19:06 -050093 typedef void (*DrawProc)(TestDrawable*, const SkMatrix&, const SkIRect&,
94 const SkImageInfo&, const GrVkDrawableInfo&);
Greg Daniel070cbaf2019-01-03 17:35:54 -050095 typedef void (*SubmitProc)(TestDrawable*);
96
Robert Phillipse94b4e12020-07-23 13:54:35 -040097 // Exercises the exporting of a secondary command buffer from one context and then importing
98 // it into a second context. We then draw to the secondary command buffer from the second
99 // context.
Greg Daniel070cbaf2019-01-03 17:35:54 -0500100 class DrawHandlerImport : public GpuDrawHandler {
101 public:
Derek Sollenbergere6fb76b2019-01-10 13:19:06 -0500102 DrawHandlerImport(TestDrawable* td, DrawProc drawProc, SubmitProc submitProc,
103 const SkMatrix& matrix,
104 const SkIRect& clipBounds,
105 const SkImageInfo& bufferInfo)
Greg Daniel070cbaf2019-01-03 17:35:54 -0500106 : INHERITED()
107 , fTestDrawable(td)
108 , fDrawProc(drawProc)
Derek Sollenbergere6fb76b2019-01-10 13:19:06 -0500109 , fSubmitProc(submitProc)
110 , fMatrix(matrix)
111 , fClipBounds(clipBounds)
112 , fBufferInfo(bufferInfo) {}
Greg Daniel070cbaf2019-01-03 17:35:54 -0500113 ~DrawHandlerImport() override {
114 fSubmitProc(fTestDrawable);
115 }
116
117 void draw(const GrBackendDrawableInfo& info) override {
118 GrVkDrawableInfo vkInfo;
119 SkAssertResult(info.getVkDrawableInfo(&vkInfo));
120
Derek Sollenbergere6fb76b2019-01-10 13:19:06 -0500121 fDrawProc(fTestDrawable, fMatrix, fClipBounds, fBufferInfo, vkInfo);
Greg Daniel070cbaf2019-01-03 17:35:54 -0500122 }
123 private:
Derek Sollenbergere6fb76b2019-01-10 13:19:06 -0500124 TestDrawable* fTestDrawable;
125 DrawProc fDrawProc;
126 SubmitProc fSubmitProc;
127 const SkMatrix fMatrix;
128 const SkIRect fClipBounds;
129 const SkImageInfo fBufferInfo;
Greg Daniel070cbaf2019-01-03 17:35:54 -0500130
131 typedef GpuDrawHandler INHERITED;
132 };
133
134 // Helper function to test drawing to a secondary command buffer that we imported into the
Robert Phillipse94b4e12020-07-23 13:54:35 -0400135 // context using a GrVkSecondaryCBDrawContext.
Derek Sollenbergere6fb76b2019-01-10 13:19:06 -0500136 static void ImportDraw(TestDrawable* td, const SkMatrix& matrix, const SkIRect& clipBounds,
137 const SkImageInfo& bufferInfo, const GrVkDrawableInfo& info) {
Robert Phillipsb25e0652020-07-22 09:35:49 -0400138 td->fDrawContext = GrVkSecondaryCBDrawContext::Make(td->fDContext, bufferInfo,
139 info, nullptr);
Greg Daniel070cbaf2019-01-03 17:35:54 -0500140 if (!td->fDrawContext) {
141 return;
142 }
143
144 SkCanvas* canvas = td->fDrawContext->getCanvas();
Derek Sollenbergere6fb76b2019-01-10 13:19:06 -0500145 canvas->clipRect(SkRect::Make(clipBounds));
146 canvas->setMatrix(matrix);
147
Greg Daniel070cbaf2019-01-03 17:35:54 -0500148 SkIRect rect = SkIRect::MakeXYWH(td->fWidth/2, 0, td->fWidth/4, td->fHeight);
149 SkPaint paint;
150 paint.setColor(SK_ColorRED);
151 canvas->drawIRect(rect, paint);
152
153 // Draw to an offscreen target so that we end up with a mix of "real" secondary command
154 // buffers and the imported secondary command buffer.
Robert Phillipsb25e0652020-07-22 09:35:49 -0400155 sk_sp<SkSurface> surf = SkSurface::MakeRenderTarget(td->fDContext, SkBudgeted::kYes,
Derek Sollenbergere6fb76b2019-01-10 13:19:06 -0500156 bufferInfo);
Greg Daniel070cbaf2019-01-03 17:35:54 -0500157 surf->getCanvas()->clear(SK_ColorRED);
158
159 SkRect dstRect = SkRect::MakeXYWH(3*td->fWidth/4, 0, td->fWidth/4, td->fHeight);
160 SkIRect srcRect = SkIRect::MakeWH(td->fWidth/4, td->fHeight);
161 canvas->drawImageRect(surf->makeImageSnapshot(), srcRect, dstRect, &paint);
162
163 td->fDrawContext->flush();
164 }
165
166 // Helper function to test waiting for the imported secondary command buffer to be submitted on
Robert Phillipse94b4e12020-07-23 13:54:35 -0400167 // its original context and then cleaning up the GrVkSecondaryCBDrawContext from this context.
Greg Daniel070cbaf2019-01-03 17:35:54 -0500168 static void ImportSubmitted(TestDrawable* td) {
169 // Typical use case here would be to create a fence that we submit to the gpu and then wait
170 // on before releasing the GrVkSecondaryCBDrawContext resources. To simulate that for this
171 // test (and since we are running single threaded anyways), we will just force a sync of
172 // the gpu and cpu here.
Robert Phillipsb25e0652020-07-22 09:35:49 -0400173 td->fDContext->priv().getGpu()->testingOnly_flushGpuAndSync();
Greg Daniel070cbaf2019-01-03 17:35:54 -0500174
175 td->fDrawContext->releaseResources();
Robert Phillipse94b4e12020-07-23 13:54:35 -0400176 // We release the context here manually to test that we waited long enough before
Greg Daniel070cbaf2019-01-03 17:35:54 -0500177 // releasing the GrVkSecondaryCBDrawContext. This simulates when a client is able to delete
Robert Phillipse94b4e12020-07-23 13:54:35 -0400178 // the context it used to imported the secondary command buffer. If we had released the
179 // context's resources earlier (before waiting on the gpu above), we would get vulkan
Greg Daniel070cbaf2019-01-03 17:35:54 -0500180 // validation layer errors saying we freed some vulkan objects while they were still in use
181 // on the GPU.
Robert Phillipsb25e0652020-07-22 09:35:49 -0400182 td->fDContext->releaseResourcesAndAbandonContext();
Greg Daniel070cbaf2019-01-03 17:35:54 -0500183 }
184
185
Greg Daniel64cc9aa2018-10-19 13:54:56 -0400186 std::unique_ptr<GpuDrawHandler> onSnapGpuDrawHandler(GrBackendApi backendApi,
Greg Danielb2a259c2018-12-17 10:28:47 -0500187 const SkMatrix& matrix,
Derek Sollenbergere6fb76b2019-01-10 13:19:06 -0500188 const SkIRect& clipBounds,
189 const SkImageInfo& bufferInfo) override {
Greg Daniel64cc9aa2018-10-19 13:54:56 -0400190 if (backendApi != GrBackendApi::kVulkan) {
191 return nullptr;
192 }
Greg Daniel070cbaf2019-01-03 17:35:54 -0500193 std::unique_ptr<GpuDrawHandler> draw;
Robert Phillipsb25e0652020-07-22 09:35:49 -0400194 if (fDContext) {
Derek Sollenbergere6fb76b2019-01-10 13:19:06 -0500195 draw.reset(new DrawHandlerImport(this, ImportDraw, ImportSubmitted, matrix,
196 clipBounds, bufferInfo));
Greg Daniel070cbaf2019-01-03 17:35:54 -0500197 } else {
198 draw.reset(new DrawHandlerBasic(fInterface, fWidth, fHeight));
199 }
200 return draw;
Greg Daniel64cc9aa2018-10-19 13:54:56 -0400201 }
202
203 SkRect onGetBounds() override {
204 return SkRect::MakeLTRB(fWidth / 2, 0, fWidth, fHeight);
205 }
206
207 void onDraw(SkCanvas*) override {
208 SkASSERT(false);
209 }
210
211private:
212 const GrVkInterface* fInterface;
Robert Phillipsb25e0652020-07-22 09:35:49 -0400213 GrDirectContext* fDContext;
Greg Daniel070cbaf2019-01-03 17:35:54 -0500214 sk_sp<GrVkSecondaryCBDrawContext> fDrawContext;
215 int32_t fWidth;
216 int32_t fHeight;
Greg Daniel64cc9aa2018-10-19 13:54:56 -0400217
218 typedef SkDrawable INHERITED;
219};
220
Robert Phillipsb25e0652020-07-22 09:35:49 -0400221void draw_drawable_test(skiatest::Reporter* reporter,
222 GrDirectContext* dContext,
223 GrDirectContext* childDContext) {
224 GrVkGpu* gpu = static_cast<GrVkGpu*>(dContext->priv().getGpu());
Greg Daniel64cc9aa2018-10-19 13:54:56 -0400225
226 const SkImageInfo ii = SkImageInfo::Make(DEV_W, DEV_H, kRGBA_8888_SkColorType,
227 kPremul_SkAlphaType);
Robert Phillipsb25e0652020-07-22 09:35:49 -0400228 sk_sp<SkSurface> surface(SkSurface::MakeRenderTarget(dContext, SkBudgeted::kNo,
Greg Daniel64cc9aa2018-10-19 13:54:56 -0400229 ii, 0, kTopLeft_GrSurfaceOrigin, nullptr));
230 SkCanvas* canvas = surface->getCanvas();
231 canvas->clear(SK_ColorBLUE);
232
Robert Phillipsb25e0652020-07-22 09:35:49 -0400233 sk_sp<TestDrawable> drawable(new TestDrawable(gpu->vkInterface(), childDContext, DEV_W, DEV_H));
Greg Daniel64cc9aa2018-10-19 13:54:56 -0400234 canvas->drawDrawable(drawable.get());
235
236 SkPaint paint;
237 paint.setColor(SK_ColorGREEN);
238 SkIRect rect = SkIRect::MakeLTRB(0, DEV_H/2, DEV_W, DEV_H);
239 canvas->drawIRect(rect, paint);
240
241 // read pixels
242 SkBitmap bitmap;
243 bitmap.allocPixels(ii);
244 canvas->readPixels(bitmap, 0, 0);
245
246 const uint32_t* canvasPixels = static_cast<const uint32_t*>(bitmap.getPixels());
247 bool failureFound = false;
248 SkPMColor expectedPixel;
Greg Daniel070cbaf2019-01-03 17:35:54 -0500249 for (int cy = 0; cy < DEV_H && !failureFound; ++cy) {
250 for (int cx = 0; cx < DEV_W && !failureFound; ++cx) {
Greg Daniel64cc9aa2018-10-19 13:54:56 -0400251 SkPMColor canvasPixel = canvasPixels[cy * DEV_W + cx];
252 if (cy < DEV_H / 2) {
253 if (cx < DEV_W / 2) {
254 expectedPixel = 0xFFFF0000; // Blue
255 } else {
256 expectedPixel = 0xFF0000FF; // Red
257 }
258 } else {
259 expectedPixel = 0xFF00FF00; // Green
260 }
261 if (expectedPixel != canvasPixel) {
262 failureFound = true;
263 ERRORF(reporter, "Wrong color at %d, %d. Got 0x%08x when we expected 0x%08x",
264 cx, cy, canvasPixel, expectedPixel);
265 }
266 }
267 }
268}
269
Greg Daniel64cc9aa2018-10-19 13:54:56 -0400270DEF_GPUTEST_FOR_VULKAN_CONTEXT(VkDrawableTest, reporter, ctxInfo) {
Robert Phillips6d344c32020-07-06 10:56:46 -0400271 draw_drawable_test(reporter, ctxInfo.directContext(), nullptr);
Greg Daniel070cbaf2019-01-03 17:35:54 -0500272}
273
274DEF_GPUTEST(VkDrawableImportTest, reporter, options) {
275 for (int typeInt = 0; typeInt < sk_gpu_test::GrContextFactory::kContextTypeCnt; ++typeInt) {
276 sk_gpu_test::GrContextFactory::ContextType contextType =
277 (sk_gpu_test::GrContextFactory::ContextType) typeInt;
278 if (contextType != sk_gpu_test::GrContextFactory::kVulkan_ContextType) {
279 continue;
280 }
281 sk_gpu_test::GrContextFactory factory(options);
Chris Daltonb3c97452019-06-25 20:07:56 -0600282 sk_gpu_test::ContextInfo ctxInfo = factory.getContextInfo(contextType);
Greg Daniel070cbaf2019-01-03 17:35:54 -0500283 skiatest::ReporterContext ctx(
284 reporter, SkString(sk_gpu_test::GrContextFactory::ContextTypeName(contextType)));
Robert Phillips6d344c32020-07-06 10:56:46 -0400285 if (ctxInfo.directContext()) {
Greg Daniel070cbaf2019-01-03 17:35:54 -0500286 sk_gpu_test::ContextInfo child =
Robert Phillips00f78de2020-07-01 16:09:43 -0400287 factory.getSharedContextInfo(ctxInfo.directContext(), 0);
Robert Phillips6d344c32020-07-06 10:56:46 -0400288 if (!child.directContext()) {
Greg Daniel070cbaf2019-01-03 17:35:54 -0500289 continue;
290 }
291
Robert Phillips6d344c32020-07-06 10:56:46 -0400292 draw_drawable_test(reporter, ctxInfo.directContext(), child.directContext());
Greg Daniel070cbaf2019-01-03 17:35:54 -0500293 }
294 }
Greg Daniel64cc9aa2018-10-19 13:54:56 -0400295}
296
297#endif