blob: eea6e37670c4fff2f02f7c08576320452fed2ca7 [file] [log] [blame]
Greg Daniela5cb7812017-06-16 09:45:32 -04001/*
2 * Copyright 2017 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#if SK_SUPPORT_GPU
Robert Phillipsf35fd8d2018-01-22 10:48:15 -050011#include "GrContextPriv.h"
Greg Daniela5cb7812017-06-16 09:45:32 -040012#include "GrContextFactory.h"
13#include "GrTest.h"
14#include "Test.h"
15
16#include "GrBackendSemaphore.h"
17#include "GrBackendSurface.h"
18#include "SkCanvas.h"
19#include "SkSurface.h"
20
Greg Danieldba7e7c2017-07-20 15:47:30 -040021#include "gl/GrGLGpu.h"
22#include "gl/GrGLUtil.h"
23
Greg Daniela5cb7812017-06-16 09:45:32 -040024#ifdef SK_VULKAN
Greg Danieldba7e7c2017-07-20 15:47:30 -040025#include "vk/GrVkGpu.h"
Greg Daniela5cb7812017-06-16 09:45:32 -040026#include "vk/GrVkTypes.h"
Greg Danieldba7e7c2017-07-20 15:47:30 -040027#include "vk/GrVkUtil.h"
28
29#ifdef VK_USE_PLATFORM_WIN32_KHR
30// windows wants to define this as CreateSemaphoreA or CreateSemaphoreW
Greg Daniel8761e0c2017-07-20 16:36:01 -040031#undef CreateSemaphore
32#endif
Greg Daniela5cb7812017-06-16 09:45:32 -040033#endif
34
35static const int MAIN_W = 8, MAIN_H = 16;
36static const int CHILD_W = 16, CHILD_H = 16;
37
38void check_pixels(skiatest::Reporter* reporter, const SkBitmap& bitmap) {
39 const uint32_t* canvasPixels = static_cast<const uint32_t*>(bitmap.getPixels());
40
41 bool failureFound = false;
42 SkPMColor expectedPixel;
43 for (int cy = 0; cy < CHILD_H && !failureFound; ++cy) {
44 for (int cx = 0; cx < CHILD_W && !failureFound; ++cx) {
45 SkPMColor canvasPixel = canvasPixels[cy * CHILD_W + cx];
46 if (cy < CHILD_H / 2) {
47 if (cx < CHILD_W / 2) {
48 expectedPixel = 0xFF0000FF; // Red
49 } else {
50 expectedPixel = 0xFFFF0000; // Blue
51 }
52 } else {
53 expectedPixel = 0xFF00FF00; // Green
54 }
55 if (expectedPixel != canvasPixel) {
56 failureFound = true;
57 ERRORF(reporter, "Wrong color at %d, %d. Got 0x%08x when we expected 0x%08x",
58 cx, cy, canvasPixel, expectedPixel);
59 }
60 }
61 }
62}
63
64void draw_child(skiatest::Reporter* reporter,
65 const sk_gpu_test::ContextInfo& childInfo,
66 const GrBackendObject& backendImage,
67 const GrBackendSemaphore& semaphore) {
68 GrBackendTexture backendTexture = GrTest::CreateBackendTexture(childInfo.backend(),
69 MAIN_W, MAIN_H,
70 kRGBA_8888_GrPixelConfig,
Greg Daniel177e6952017-10-12 12:27:11 -040071 GrMipMapped::kNo,
Greg Daniela5cb7812017-06-16 09:45:32 -040072 backendImage);
73
74 childInfo.testContext()->makeCurrent();
75
76 const SkImageInfo childII = SkImageInfo::Make(CHILD_W, CHILD_H, kRGBA_8888_SkColorType,
77 kPremul_SkAlphaType);
78
79 GrContext* childCtx = childInfo.grContext();
80 sk_sp<SkSurface> childSurface(SkSurface::MakeRenderTarget(childCtx, SkBudgeted::kNo,
81 childII, 0, kTopLeft_GrSurfaceOrigin,
82 nullptr));
83
84 sk_sp<SkImage> childImage = SkImage::MakeFromTexture(childCtx,
85 backendTexture,
86 kTopLeft_GrSurfaceOrigin,
Greg Danielf5d87582017-12-18 14:48:15 -050087 kRGBA_8888_SkColorType,
Greg Daniela5cb7812017-06-16 09:45:32 -040088 kPremul_SkAlphaType,
Greg Danielf5d87582017-12-18 14:48:15 -050089 nullptr,
90 nullptr,
Greg Daniela5cb7812017-06-16 09:45:32 -040091 nullptr);
92
93 SkCanvas* childCanvas = childSurface->getCanvas();
94 childCanvas->clear(SK_ColorRED);
95
96 childSurface->wait(1, &semaphore);
97
98 childCanvas->drawImage(childImage, CHILD_W/2, 0);
99
100 SkPaint paint;
101 paint.setColor(SK_ColorGREEN);
102 SkIRect rect = SkIRect::MakeLTRB(0, CHILD_H/2, CHILD_W, CHILD_H);
103 childCanvas->drawIRect(rect, paint);
104
105 // read pixels
106 SkBitmap bitmap;
107 bitmap.allocPixels(childII);
Mike Reedf1942192017-07-21 14:24:29 -0400108 childSurface->readPixels(bitmap, 0, 0);
Greg Daniela5cb7812017-06-16 09:45:32 -0400109
110 check_pixels(reporter, bitmap);
111}
112
113void surface_semaphore_test(skiatest::Reporter* reporter,
114 const sk_gpu_test::ContextInfo& mainInfo,
115 const sk_gpu_test::ContextInfo& childInfo1,
Greg Daniel51316782017-08-02 15:10:09 +0000116 const sk_gpu_test::ContextInfo& childInfo2,
117 bool flushContext) {
Greg Daniela5cb7812017-06-16 09:45:32 -0400118 GrContext* mainCtx = mainInfo.grContext();
119 if (!mainCtx->caps()->fenceSyncSupport()) {
120 return;
121 }
122
123 const SkImageInfo ii = SkImageInfo::Make(MAIN_W, MAIN_H, kRGBA_8888_SkColorType,
124 kPremul_SkAlphaType);
125
126 sk_sp<SkSurface> mainSurface(SkSurface::MakeRenderTarget(mainCtx, SkBudgeted::kNo,
127 ii, 0, kTopLeft_GrSurfaceOrigin,
128 nullptr));
129 SkCanvas* mainCanvas = mainSurface->getCanvas();
130 mainCanvas->clear(SK_ColorBLUE);
131
132 SkAutoTArray<GrBackendSemaphore> semaphores(2);
Greg Daniel8761e0c2017-07-20 16:36:01 -0400133#ifdef SK_VULKAN
134 if (kVulkan_GrBackend == mainInfo.backend()) {
135 // Initialize the secondary semaphore instead of having Ganesh create one internally
Robert Phillipsf35fd8d2018-01-22 10:48:15 -0500136 GrVkGpu* gpu = static_cast<GrVkGpu*>(mainCtx->contextPriv().getGpu());
Greg Daniel8761e0c2017-07-20 16:36:01 -0400137 const GrVkInterface* interface = gpu->vkInterface();
138 VkDevice device = gpu->device();
139
140 VkSemaphore vkSem;
141
142 VkSemaphoreCreateInfo createInfo;
143 createInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
144 createInfo.pNext = nullptr;
145 createInfo.flags = 0;
146 GR_VK_CALL_ERRCHECK(interface, CreateSemaphore(device, &createInfo, nullptr, &vkSem));
147
148 semaphores[1].initVulkan(vkSem);
149 }
150#endif
Greg Daniela5cb7812017-06-16 09:45:32 -0400151
Greg Daniel51316782017-08-02 15:10:09 +0000152 if (flushContext) {
153 mainCtx->flushAndSignalSemaphores(2, semaphores.get());
154 } else {
155 mainSurface->flushAndSignalSemaphores(2, semaphores.get());
156 }
Greg Daniela5cb7812017-06-16 09:45:32 -0400157
158 sk_sp<SkImage> mainImage = mainSurface->makeImageSnapshot();
159 GrBackendObject backendImage = mainImage->getTextureHandle(false);
160
161 draw_child(reporter, childInfo1, backendImage, semaphores[0]);
162
163#ifdef SK_VULKAN
164 if (kVulkan_GrBackend == mainInfo.backend()) {
165 // In Vulkan we need to make sure we are sending the correct VkImageLayout in with the
166 // backendImage. After the first child draw the layout gets changed to SHADER_READ, so
167 // we just manually set that here.
168 GrVkImageInfo* vkInfo = (GrVkImageInfo*)backendImage;
169 vkInfo->updateImageLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
170 }
171#endif
172
173 draw_child(reporter, childInfo2, backendImage, semaphores[1]);
174}
175
Brian Salomondcfca432017-11-15 15:48:03 -0500176DEF_GPUTEST(SurfaceSemaphores, reporter, options) {
Greg Daniela5cb7812017-06-16 09:45:32 -0400177#if defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_WIN) || defined(SK_BUILD_FOR_MAC)
178 static constexpr auto kNativeGLType = sk_gpu_test::GrContextFactory::kGL_ContextType;
179#else
180 static constexpr auto kNativeGLType = sk_gpu_test::GrContextFactory::kGLES_ContextType;
181#endif
182
183 for (int typeInt = 0; typeInt < sk_gpu_test::GrContextFactory::kContextTypeCnt; ++typeInt) {
Greg Daniel51316782017-08-02 15:10:09 +0000184 for (auto flushContext : { false, true }) {
185 sk_gpu_test::GrContextFactory::ContextType contextType =
186 (sk_gpu_test::GrContextFactory::ContextType) typeInt;
187 // Use "native" instead of explicitly trying OpenGL and OpenGL ES. Do not use GLES on
188 // desktop since tests do not account for not fixing http://skbug.com/2809
189 if (contextType == sk_gpu_test::GrContextFactory::kGL_ContextType ||
190 contextType == sk_gpu_test::GrContextFactory::kGLES_ContextType) {
191 if (contextType != kNativeGLType) {
192 continue;
193 }
194 }
Brian Salomondcfca432017-11-15 15:48:03 -0500195 sk_gpu_test::GrContextFactory factory(options);
196 sk_gpu_test::ContextInfo ctxInfo = factory.getContextInfo(
Greg Daniel51316782017-08-02 15:10:09 +0000197 contextType, sk_gpu_test::GrContextFactory::ContextOverrides::kDisableNVPR);
198 if (!sk_gpu_test::GrContextFactory::IsRenderingContext(contextType)) {
Greg Daniela5cb7812017-06-16 09:45:32 -0400199 continue;
200 }
Greg Daniel51316782017-08-02 15:10:09 +0000201 skiatest::ReporterContext ctx(
202 reporter, SkString(sk_gpu_test::GrContextFactory::ContextTypeName(contextType)));
203 if (ctxInfo.grContext()) {
Brian Salomondcfca432017-11-15 15:48:03 -0500204 sk_gpu_test::ContextInfo child1 =
205 factory.getSharedContextInfo(ctxInfo.grContext(), 0);
206 sk_gpu_test::ContextInfo child2 =
207 factory.getSharedContextInfo(ctxInfo.grContext(), 1);
Greg Daniel51316782017-08-02 15:10:09 +0000208 if (!child1.grContext() || !child2.grContext()) {
209 continue;
210 }
Yuqian Licc8eb602017-08-01 17:43:30 +0000211
Greg Daniel51316782017-08-02 15:10:09 +0000212 surface_semaphore_test(reporter, ctxInfo, child1, child2, flushContext);
213 }
Greg Daniela5cb7812017-06-16 09:45:32 -0400214 }
215 }
216}
217
Greg Danieldba7e7c2017-07-20 15:47:30 -0400218DEF_GPUTEST_FOR_RENDERING_CONTEXTS(EmptySurfaceSemaphoreTest, reporter, ctxInfo) {
219 GrContext* ctx = ctxInfo.grContext();
220 if (!ctx->caps()->fenceSyncSupport()) {
221 return;
222 }
223
224 const SkImageInfo ii = SkImageInfo::Make(MAIN_W, MAIN_H, kRGBA_8888_SkColorType,
225 kPremul_SkAlphaType);
226
227 sk_sp<SkSurface> mainSurface(SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo,
228 ii, 0, kTopLeft_GrSurfaceOrigin,
229 nullptr));
230
231 // Flush surface once without semaphores to make sure there is no peneding IO for it.
232 mainSurface->flush();
233
234 GrBackendSemaphore semaphore;
Greg Daniel51316782017-08-02 15:10:09 +0000235 GrSemaphoresSubmitted submitted = mainSurface->flushAndSignalSemaphores(1, &semaphore);
236 REPORTER_ASSERT(reporter, GrSemaphoresSubmitted::kYes == submitted);
Greg Danieldba7e7c2017-07-20 15:47:30 -0400237
238 if (kOpenGL_GrBackend == ctxInfo.backend()) {
Robert Phillipsf35fd8d2018-01-22 10:48:15 -0500239 GrGLGpu* gpu = static_cast<GrGLGpu*>(ctx->contextPriv().getGpu());
Greg Danieldba7e7c2017-07-20 15:47:30 -0400240 const GrGLInterface* interface = gpu->glInterface();
241 GrGLsync sync = semaphore.glSync();
242 REPORTER_ASSERT(reporter, sync);
243 bool result;
244 GR_GL_CALL_RET(interface, result, IsSync(sync));
245 REPORTER_ASSERT(reporter, result);
246 }
247
248#ifdef SK_VULKAN
249 if (kVulkan_GrBackend == ctxInfo.backend()) {
Robert Phillipsf35fd8d2018-01-22 10:48:15 -0500250 GrVkGpu* gpu = static_cast<GrVkGpu*>(ctx->contextPriv().getGpu());
Greg Danieldba7e7c2017-07-20 15:47:30 -0400251 const GrVkInterface* interface = gpu->vkInterface();
252 VkDevice device = gpu->device();
253 VkQueue queue = gpu->queue();
254 VkCommandPool cmdPool = gpu->cmdPool();
255 VkCommandBuffer cmdBuffer;
256
257 // Create Command Buffer
258 const VkCommandBufferAllocateInfo cmdInfo = {
259 VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // sType
260 nullptr, // pNext
261 cmdPool, // commandPool
262 VK_COMMAND_BUFFER_LEVEL_PRIMARY, // level
263 1 // bufferCount
264 };
265
266 VkResult err = GR_VK_CALL(interface, AllocateCommandBuffers(device, &cmdInfo, &cmdBuffer));
267 if (err) {
268 return;
269 }
270
271 VkCommandBufferBeginInfo cmdBufferBeginInfo;
272 memset(&cmdBufferBeginInfo, 0, sizeof(VkCommandBufferBeginInfo));
273 cmdBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
274 cmdBufferBeginInfo.pNext = nullptr;
275 cmdBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
276 cmdBufferBeginInfo.pInheritanceInfo = nullptr;
277
278 GR_VK_CALL_ERRCHECK(interface, BeginCommandBuffer(cmdBuffer, &cmdBufferBeginInfo));
279 GR_VK_CALL_ERRCHECK(interface, EndCommandBuffer(cmdBuffer));
280
281 VkFenceCreateInfo fenceInfo;
282 VkFence fence;
283
284 memset(&fenceInfo, 0, sizeof(VkFenceCreateInfo));
285 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
286 err = GR_VK_CALL(interface, CreateFence(device, &fenceInfo, nullptr, &fence));
287 SkASSERT(!err);
288
289 VkPipelineStageFlags waitStages = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
290 VkSubmitInfo submitInfo;
291 memset(&submitInfo, 0, sizeof(VkSubmitInfo));
292 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
293 submitInfo.pNext = nullptr;
294 submitInfo.waitSemaphoreCount = 1;
295 VkSemaphore vkSem = semaphore.vkSemaphore();
296 submitInfo.pWaitSemaphores = &vkSem;
297 submitInfo.pWaitDstStageMask = &waitStages;
298 submitInfo.commandBufferCount = 1;
299 submitInfo.pCommandBuffers = &cmdBuffer;
300 submitInfo.signalSemaphoreCount = 0;
301 submitInfo.pSignalSemaphores = nullptr;
302 GR_VK_CALL_ERRCHECK(interface, QueueSubmit(queue, 1, &submitInfo, fence));
303
304 err = GR_VK_CALL(interface, WaitForFences(device, 1, &fence, true, 3000000000));
305
306 REPORTER_ASSERT(reporter, err != VK_TIMEOUT);
307
308 GR_VK_CALL(interface, DestroyFence(device, fence, nullptr));
309 GR_VK_CALL(interface, DestroySemaphore(device, vkSem, nullptr));
310 // If the above test fails the wait semaphore will never be signaled which can cause the
311 // device to hang when tearing down (even if just tearing down GL). So we Fail here to
312 // kill things.
313 if (err == VK_TIMEOUT) {
Ben Wagnerb4aab9a2017-08-16 10:53:04 -0400314 SK_ABORT("Waiting on semaphore indefinitely");
Greg Danieldba7e7c2017-07-20 15:47:30 -0400315 }
316 }
317#endif
318}
319
Greg Daniela5cb7812017-06-16 09:45:32 -0400320#endif