blob: cd3b8e587b17e2b7de7056bf537e5bb434f45260 [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
11#include "GrContextFactory.h"
12#include "GrTest.h"
13#include "Test.h"
14
15#include "GrBackendSemaphore.h"
16#include "GrBackendSurface.h"
17#include "SkCanvas.h"
18#include "SkSurface.h"
19
Greg Danieldba7e7c2017-07-20 15:47:30 -040020#include "gl/GrGLGpu.h"
21#include "gl/GrGLUtil.h"
22
Greg Daniela5cb7812017-06-16 09:45:32 -040023#ifdef SK_VULKAN
Greg Danieldba7e7c2017-07-20 15:47:30 -040024#include "vk/GrVkGpu.h"
Greg Daniela5cb7812017-06-16 09:45:32 -040025#include "vk/GrVkTypes.h"
Greg Danieldba7e7c2017-07-20 15:47:30 -040026#include "vk/GrVkUtil.h"
27
28#ifdef VK_USE_PLATFORM_WIN32_KHR
29// windows wants to define this as CreateSemaphoreA or CreateSemaphoreW
Greg Daniel8761e0c2017-07-20 16:36:01 -040030#undef CreateSemaphore
31#endif
Greg Daniela5cb7812017-06-16 09:45:32 -040032#endif
33
34static const int MAIN_W = 8, MAIN_H = 16;
35static const int CHILD_W = 16, CHILD_H = 16;
36
37void check_pixels(skiatest::Reporter* reporter, const SkBitmap& bitmap) {
38 const uint32_t* canvasPixels = static_cast<const uint32_t*>(bitmap.getPixels());
39
40 bool failureFound = false;
41 SkPMColor expectedPixel;
42 for (int cy = 0; cy < CHILD_H && !failureFound; ++cy) {
43 for (int cx = 0; cx < CHILD_W && !failureFound; ++cx) {
44 SkPMColor canvasPixel = canvasPixels[cy * CHILD_W + cx];
45 if (cy < CHILD_H / 2) {
46 if (cx < CHILD_W / 2) {
47 expectedPixel = 0xFF0000FF; // Red
48 } else {
49 expectedPixel = 0xFFFF0000; // Blue
50 }
51 } else {
52 expectedPixel = 0xFF00FF00; // Green
53 }
54 if (expectedPixel != canvasPixel) {
55 failureFound = true;
56 ERRORF(reporter, "Wrong color at %d, %d. Got 0x%08x when we expected 0x%08x",
57 cx, cy, canvasPixel, expectedPixel);
58 }
59 }
60 }
61}
62
63void draw_child(skiatest::Reporter* reporter,
64 const sk_gpu_test::ContextInfo& childInfo,
65 const GrBackendObject& backendImage,
66 const GrBackendSemaphore& semaphore) {
67 GrBackendTexture backendTexture = GrTest::CreateBackendTexture(childInfo.backend(),
68 MAIN_W, MAIN_H,
69 kRGBA_8888_GrPixelConfig,
70 backendImage);
71
72 childInfo.testContext()->makeCurrent();
73
74 const SkImageInfo childII = SkImageInfo::Make(CHILD_W, CHILD_H, kRGBA_8888_SkColorType,
75 kPremul_SkAlphaType);
76
77 GrContext* childCtx = childInfo.grContext();
78 sk_sp<SkSurface> childSurface(SkSurface::MakeRenderTarget(childCtx, SkBudgeted::kNo,
79 childII, 0, kTopLeft_GrSurfaceOrigin,
80 nullptr));
81
82 sk_sp<SkImage> childImage = SkImage::MakeFromTexture(childCtx,
83 backendTexture,
84 kTopLeft_GrSurfaceOrigin,
85 kPremul_SkAlphaType,
86 nullptr);
87
88 SkCanvas* childCanvas = childSurface->getCanvas();
89 childCanvas->clear(SK_ColorRED);
90
91 childSurface->wait(1, &semaphore);
92
93 childCanvas->drawImage(childImage, CHILD_W/2, 0);
94
95 SkPaint paint;
96 paint.setColor(SK_ColorGREEN);
97 SkIRect rect = SkIRect::MakeLTRB(0, CHILD_H/2, CHILD_W, CHILD_H);
98 childCanvas->drawIRect(rect, paint);
99
100 // read pixels
101 SkBitmap bitmap;
102 bitmap.allocPixels(childII);
Mike Reedf1942192017-07-21 14:24:29 -0400103 childSurface->readPixels(bitmap, 0, 0);
Greg Daniela5cb7812017-06-16 09:45:32 -0400104
105 check_pixels(reporter, bitmap);
106}
107
108void surface_semaphore_test(skiatest::Reporter* reporter,
109 const sk_gpu_test::ContextInfo& mainInfo,
110 const sk_gpu_test::ContextInfo& childInfo1,
Mike Reed8724b462017-07-22 17:33:48 +0000111 const sk_gpu_test::ContextInfo& childInfo2) {
Greg Daniela5cb7812017-06-16 09:45:32 -0400112 GrContext* mainCtx = mainInfo.grContext();
113 if (!mainCtx->caps()->fenceSyncSupport()) {
114 return;
115 }
116
117 const SkImageInfo ii = SkImageInfo::Make(MAIN_W, MAIN_H, kRGBA_8888_SkColorType,
118 kPremul_SkAlphaType);
119
120 sk_sp<SkSurface> mainSurface(SkSurface::MakeRenderTarget(mainCtx, SkBudgeted::kNo,
121 ii, 0, kTopLeft_GrSurfaceOrigin,
122 nullptr));
123 SkCanvas* mainCanvas = mainSurface->getCanvas();
124 mainCanvas->clear(SK_ColorBLUE);
125
126 SkAutoTArray<GrBackendSemaphore> semaphores(2);
Greg Daniel8761e0c2017-07-20 16:36:01 -0400127#ifdef SK_VULKAN
128 if (kVulkan_GrBackend == mainInfo.backend()) {
129 // Initialize the secondary semaphore instead of having Ganesh create one internally
130 GrVkGpu* gpu = static_cast<GrVkGpu*>(mainCtx->getGpu());
131 const GrVkInterface* interface = gpu->vkInterface();
132 VkDevice device = gpu->device();
133
134 VkSemaphore vkSem;
135
136 VkSemaphoreCreateInfo createInfo;
137 createInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
138 createInfo.pNext = nullptr;
139 createInfo.flags = 0;
140 GR_VK_CALL_ERRCHECK(interface, CreateSemaphore(device, &createInfo, nullptr, &vkSem));
141
142 semaphores[1].initVulkan(vkSem);
143 }
144#endif
Greg Daniela5cb7812017-06-16 09:45:32 -0400145
Mike Reed8724b462017-07-22 17:33:48 +0000146 mainSurface->flushAndSignalSemaphores(2, semaphores.get());
Greg Daniela5cb7812017-06-16 09:45:32 -0400147
148 sk_sp<SkImage> mainImage = mainSurface->makeImageSnapshot();
149 GrBackendObject backendImage = mainImage->getTextureHandle(false);
150
151 draw_child(reporter, childInfo1, backendImage, semaphores[0]);
152
153#ifdef SK_VULKAN
154 if (kVulkan_GrBackend == mainInfo.backend()) {
155 // In Vulkan we need to make sure we are sending the correct VkImageLayout in with the
156 // backendImage. After the first child draw the layout gets changed to SHADER_READ, so
157 // we just manually set that here.
158 GrVkImageInfo* vkInfo = (GrVkImageInfo*)backendImage;
159 vkInfo->updateImageLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
160 }
161#endif
162
163 draw_child(reporter, childInfo2, backendImage, semaphores[1]);
164}
165
166DEF_GPUTEST(SurfaceSemaphores, reporter, factory) {
167#if defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_WIN) || defined(SK_BUILD_FOR_MAC)
168 static constexpr auto kNativeGLType = sk_gpu_test::GrContextFactory::kGL_ContextType;
169#else
170 static constexpr auto kNativeGLType = sk_gpu_test::GrContextFactory::kGLES_ContextType;
171#endif
172
173 for (int typeInt = 0; typeInt < sk_gpu_test::GrContextFactory::kContextTypeCnt; ++typeInt) {
Mike Reed8724b462017-07-22 17:33:48 +0000174 sk_gpu_test::GrContextFactory::ContextType contextType =
175 (sk_gpu_test::GrContextFactory::ContextType) typeInt;
176 // Use "native" instead of explicitly trying OpenGL and OpenGL ES. Do not use GLES on
177 // desktop since tests do not account for not fixing http://skbug.com/2809
178 if (contextType == sk_gpu_test::GrContextFactory::kGL_ContextType ||
179 contextType == sk_gpu_test::GrContextFactory::kGLES_ContextType) {
180 if (contextType != kNativeGLType) {
Greg Daniela5cb7812017-06-16 09:45:32 -0400181 continue;
182 }
Mike Reed8724b462017-07-22 17:33:48 +0000183 }
184 sk_gpu_test::ContextInfo ctxInfo = factory->getContextInfo(
185 contextType, sk_gpu_test::GrContextFactory::ContextOverrides::kDisableNVPR);
186 if (!sk_gpu_test::GrContextFactory::IsRenderingContext(contextType)) {
187 continue;
188 }
189 skiatest::ReporterContext ctx(
190 reporter, SkString(sk_gpu_test::GrContextFactory::ContextTypeName(contextType)));
191 if (ctxInfo.grContext()) {
192 sk_gpu_test::ContextInfo child1 = factory->getSharedContextInfo(ctxInfo.grContext(), 0);
193 sk_gpu_test::ContextInfo child2 = factory->getSharedContextInfo(ctxInfo.grContext(), 1);
194 if (!child1.grContext() || !child2.grContext()) {
195 continue;
Greg Danielcd1416e2017-07-21 14:27:57 -0400196 }
Mike Reed8724b462017-07-22 17:33:48 +0000197
198 surface_semaphore_test(reporter, ctxInfo, child1, child2);
Greg Daniela5cb7812017-06-16 09:45:32 -0400199 }
200 }
201}
202
Greg Danieldba7e7c2017-07-20 15:47:30 -0400203DEF_GPUTEST_FOR_RENDERING_CONTEXTS(EmptySurfaceSemaphoreTest, reporter, ctxInfo) {
204 GrContext* ctx = ctxInfo.grContext();
205 if (!ctx->caps()->fenceSyncSupport()) {
206 return;
207 }
208
209 const SkImageInfo ii = SkImageInfo::Make(MAIN_W, MAIN_H, kRGBA_8888_SkColorType,
210 kPremul_SkAlphaType);
211
212 sk_sp<SkSurface> mainSurface(SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo,
213 ii, 0, kTopLeft_GrSurfaceOrigin,
214 nullptr));
215
216 // Flush surface once without semaphores to make sure there is no peneding IO for it.
217 mainSurface->flush();
218
219 GrBackendSemaphore semaphore;
Mike Reed8724b462017-07-22 17:33:48 +0000220 REPORTER_ASSERT(reporter, mainSurface->flushAndSignalSemaphores(1, &semaphore));
Greg Danieldba7e7c2017-07-20 15:47:30 -0400221
222 if (kOpenGL_GrBackend == ctxInfo.backend()) {
223 GrGLGpu* gpu = static_cast<GrGLGpu*>(ctx->getGpu());
224 const GrGLInterface* interface = gpu->glInterface();
225 GrGLsync sync = semaphore.glSync();
226 REPORTER_ASSERT(reporter, sync);
227 bool result;
228 GR_GL_CALL_RET(interface, result, IsSync(sync));
229 REPORTER_ASSERT(reporter, result);
230 }
231
232#ifdef SK_VULKAN
233 if (kVulkan_GrBackend == ctxInfo.backend()) {
234 GrVkGpu* gpu = static_cast<GrVkGpu*>(ctx->getGpu());
235 const GrVkInterface* interface = gpu->vkInterface();
236 VkDevice device = gpu->device();
237 VkQueue queue = gpu->queue();
238 VkCommandPool cmdPool = gpu->cmdPool();
239 VkCommandBuffer cmdBuffer;
240
241 // Create Command Buffer
242 const VkCommandBufferAllocateInfo cmdInfo = {
243 VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // sType
244 nullptr, // pNext
245 cmdPool, // commandPool
246 VK_COMMAND_BUFFER_LEVEL_PRIMARY, // level
247 1 // bufferCount
248 };
249
250 VkResult err = GR_VK_CALL(interface, AllocateCommandBuffers(device, &cmdInfo, &cmdBuffer));
251 if (err) {
252 return;
253 }
254
255 VkCommandBufferBeginInfo cmdBufferBeginInfo;
256 memset(&cmdBufferBeginInfo, 0, sizeof(VkCommandBufferBeginInfo));
257 cmdBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
258 cmdBufferBeginInfo.pNext = nullptr;
259 cmdBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
260 cmdBufferBeginInfo.pInheritanceInfo = nullptr;
261
262 GR_VK_CALL_ERRCHECK(interface, BeginCommandBuffer(cmdBuffer, &cmdBufferBeginInfo));
263 GR_VK_CALL_ERRCHECK(interface, EndCommandBuffer(cmdBuffer));
264
265 VkFenceCreateInfo fenceInfo;
266 VkFence fence;
267
268 memset(&fenceInfo, 0, sizeof(VkFenceCreateInfo));
269 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
270 err = GR_VK_CALL(interface, CreateFence(device, &fenceInfo, nullptr, &fence));
271 SkASSERT(!err);
272
273 VkPipelineStageFlags waitStages = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
274 VkSubmitInfo submitInfo;
275 memset(&submitInfo, 0, sizeof(VkSubmitInfo));
276 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
277 submitInfo.pNext = nullptr;
278 submitInfo.waitSemaphoreCount = 1;
279 VkSemaphore vkSem = semaphore.vkSemaphore();
280 submitInfo.pWaitSemaphores = &vkSem;
281 submitInfo.pWaitDstStageMask = &waitStages;
282 submitInfo.commandBufferCount = 1;
283 submitInfo.pCommandBuffers = &cmdBuffer;
284 submitInfo.signalSemaphoreCount = 0;
285 submitInfo.pSignalSemaphores = nullptr;
286 GR_VK_CALL_ERRCHECK(interface, QueueSubmit(queue, 1, &submitInfo, fence));
287
288 err = GR_VK_CALL(interface, WaitForFences(device, 1, &fence, true, 3000000000));
289
290 REPORTER_ASSERT(reporter, err != VK_TIMEOUT);
291
292 GR_VK_CALL(interface, DestroyFence(device, fence, nullptr));
293 GR_VK_CALL(interface, DestroySemaphore(device, vkSem, nullptr));
294 // If the above test fails the wait semaphore will never be signaled which can cause the
295 // device to hang when tearing down (even if just tearing down GL). So we Fail here to
296 // kill things.
297 if (err == VK_TIMEOUT) {
298 SkFAIL("Waiting on semaphore indefinitely");
299 }
300 }
301#endif
302}
303
Greg Daniela5cb7812017-06-16 09:45:32 -0400304#endif