1/*
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 "include/core/SkBitmap.h"
9#include "include/core/SkCanvas.h"
10#include "include/core/SkSurface.h"
11#include "include/gpu/GrBackendSemaphore.h"
12#include "include/gpu/GrBackendSurface.h"
13#include "include/gpu/GrDirectContext.h"
14#include "src/gpu/GrCaps.h"
15#include "src/gpu/GrDirectContextPriv.h"
16#include "tests/Test.h"
17#include "tools/gpu/GrContextFactory.h"
18
19#ifdef SK_GL
20#include "src/gpu/gl/GrGLGpu.h"
21#include "src/gpu/gl/GrGLUtil.h"
22#endif
23
24#ifdef SK_VULKAN
25#include "include/gpu/vk/GrVkTypes.h"
26#include "include/gpu/vk/GrVkVulkan.h"
27#include "src/gpu/vk/GrVkCommandPool.h"
28#include "src/gpu/vk/GrVkGpu.h"
29#include "src/gpu/vk/GrVkUtil.h"
30
31#ifdef VK_USE_PLATFORM_WIN32_KHR
32// windows wants to define this as CreateSemaphoreA or CreateSemaphoreW
33#undef CreateSemaphore
34#endif
35#endif
36
37static const int MAIN_W = 8, MAIN_H = 16;
38static const int CHILD_W = 16, CHILD_H = 16;
39
40void check_pixels(skiatest::Reporter* reporter, const SkBitmap& bitmap) {
41    const uint32_t* canvasPixels = static_cast<const uint32_t*>(bitmap.getPixels());
42
43    bool failureFound = false;
44    SkPMColor expectedPixel;
45    for (int cy = 0; cy < CHILD_H && !failureFound; ++cy) {
46        for (int cx = 0; cx < CHILD_W && !failureFound; ++cx) {
47            SkPMColor canvasPixel = canvasPixels[cy * CHILD_W + cx];
48            if (cy < CHILD_H / 2) {
49                if (cx < CHILD_W / 2) {
50                    expectedPixel = 0xFF0000FF; // Red
51                } else {
52                    expectedPixel = 0xFFFF0000; // Blue
53                }
54            } else {
55                expectedPixel = 0xFF00FF00; // Green
56            }
57            if (expectedPixel != canvasPixel) {
58                failureFound = true;
59                ERRORF(reporter, "Wrong color at %d, %d. Got 0x%08x when we expected 0x%08x",
60                       cx, cy, canvasPixel, expectedPixel);
61            }
62        }
63    }
64}
65
66void draw_child(skiatest::Reporter* reporter,
67                const sk_gpu_test::ContextInfo& childInfo,
68                const GrBackendTexture& backendTexture,
69                const GrBackendSemaphore& semaphore) {
70
71    childInfo.testContext()->makeCurrent();
72
73    const SkImageInfo childII = SkImageInfo::Make(CHILD_W, CHILD_H, kRGBA_8888_SkColorType,
74                                                  kPremul_SkAlphaType);
75
76    auto childDContext = childInfo.directContext();
77    sk_sp<SkSurface> childSurface(SkSurface::MakeRenderTarget(childDContext, SkBudgeted::kNo,
78                                                              childII, 0, kTopLeft_GrSurfaceOrigin,
79                                                              nullptr));
80
81    sk_sp<SkImage> childImage = SkImage::MakeFromTexture(childDContext,
82                                                         backendTexture,
83                                                         kTopLeft_GrSurfaceOrigin,
84                                                         kRGBA_8888_SkColorType,
85                                                         kPremul_SkAlphaType,
86                                                         nullptr,
87                                                         nullptr,
88                                                         nullptr);
89
90    SkCanvas* childCanvas = childSurface->getCanvas();
91    childCanvas->clear(SK_ColorRED);
92
93    childSurface->wait(1, &semaphore);
94
95    childCanvas->drawImage(childImage, CHILD_W/2, 0);
96
97    SkPaint paint;
98    paint.setColor(SK_ColorGREEN);
99    SkIRect rect = SkIRect::MakeLTRB(0, CHILD_H/2, CHILD_W, CHILD_H);
100    childCanvas->drawIRect(rect, paint);
101
102    // read pixels
103    SkBitmap bitmap;
104    bitmap.allocPixels(childII);
105    childSurface->readPixels(bitmap, 0, 0);
106
107    check_pixels(reporter, bitmap);
108}
109
110enum class FlushType { kSurface, kImage, kContext };
111
112void surface_semaphore_test(skiatest::Reporter* reporter,
113                            const sk_gpu_test::ContextInfo& mainInfo,
114                            const sk_gpu_test::ContextInfo& childInfo1,
115                            const sk_gpu_test::ContextInfo& childInfo2,
116                            FlushType flushType) {
117    auto mainCtx = mainInfo.directContext();
118    if (!mainCtx->priv().caps()->semaphoreSupport()) {
119        return;
120    }
121
122    const SkImageInfo ii = SkImageInfo::Make(MAIN_W, MAIN_H, kRGBA_8888_SkColorType,
123                                             kPremul_SkAlphaType);
124
125    sk_sp<SkSurface> mainSurface(SkSurface::MakeRenderTarget(mainCtx, SkBudgeted::kNo,
126                                                             ii, 0, kTopLeft_GrSurfaceOrigin,
127                                                             nullptr));
128    SkCanvas* mainCanvas = mainSurface->getCanvas();
129    auto blueSurface = mainSurface->makeSurface(ii);
130    blueSurface->getCanvas()->clear(SK_ColorBLUE);
131    auto blueImage = blueSurface->makeImageSnapshot();
132    blueSurface.reset();
133    mainCanvas->drawImage(blueImage, 0, 0);
134
135    SkAutoTArray<GrBackendSemaphore> semaphores(2);
136#ifdef SK_VULKAN
137    if (GrBackendApi::kVulkan == mainInfo.backend()) {
138        // Initialize the secondary semaphore instead of having Ganesh create one internally
139        GrVkGpu* gpu = static_cast<GrVkGpu*>(mainCtx->priv().getGpu());
140        VkDevice device = gpu->device();
141
142        VkSemaphore vkSem;
143
144        VkSemaphoreCreateInfo createInfo;
145        createInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
146        createInfo.pNext = nullptr;
147        createInfo.flags = 0;
148        GR_VK_CALL_ERRCHECK(gpu, CreateSemaphore(device, &createInfo, nullptr, &vkSem));
149
150        semaphores[1].initVulkan(vkSem);
151    }
152#endif
153
154    GrFlushInfo info;
155    info.fNumSemaphores = 2;
156    info.fSignalSemaphores = semaphores.get();
157    switch (flushType) {
158        case FlushType::kSurface:
159            mainSurface->flush(SkSurface::BackendSurfaceAccess::kNoAccess, info);
160            break;
161        case FlushType::kImage:
162            blueImage->flush(mainCtx, info);
163            break;
164        case FlushType::kContext:
165            mainCtx->flush(info);
166            break;
167    }
168    mainCtx->submit();
169
170    GrBackendTexture backendTexture = mainSurface->getBackendTexture(
171            SkSurface::BackendHandleAccess::kFlushRead_BackendHandleAccess);
172
173    draw_child(reporter, childInfo1, backendTexture, semaphores[0]);
174
175#ifdef SK_VULKAN
176    if (GrBackendApi::kVulkan == mainInfo.backend()) {
177        // In Vulkan we need to make sure we are sending the correct VkImageLayout in with the
178        // backendImage. After the first child draw the layout gets changed to SHADER_READ, so
179        // we just manually set that here.
180        backendTexture.setVkImageLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
181    }
182#endif
183
184    draw_child(reporter, childInfo2, backendTexture, semaphores[1]);
185}
186
187#ifdef SK_GL
188DEF_GPUTEST(SurfaceSemaphores, reporter, options) {
189#if defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_WIN) || defined(SK_BUILD_FOR_MAC)
190    static constexpr auto kNativeGLType = sk_gpu_test::GrContextFactory::kGL_ContextType;
191#else
192    static constexpr auto kNativeGLType = sk_gpu_test::GrContextFactory::kGLES_ContextType;
193#endif
194
195    for (int typeInt = 0; typeInt < sk_gpu_test::GrContextFactory::kContextTypeCnt; ++typeInt) {
196        for (auto flushType : {FlushType::kSurface, FlushType::kImage, FlushType::kContext}) {
197            sk_gpu_test::GrContextFactory::ContextType contextType =
198                    (sk_gpu_test::GrContextFactory::ContextType) typeInt;
199            // Use "native" instead of explicitly trying OpenGL and OpenGL ES. Do not use GLES on
200            // desktop since tests do not account for not fixing http://skbug.com/2809
201            if (contextType == sk_gpu_test::GrContextFactory::kGL_ContextType ||
202                contextType == sk_gpu_test::GrContextFactory::kGLES_ContextType) {
203                if (contextType != kNativeGLType) {
204                    continue;
205                }
206            }
207            sk_gpu_test::GrContextFactory factory(options);
208            sk_gpu_test::ContextInfo ctxInfo = factory.getContextInfo(contextType);
209            if (!sk_gpu_test::GrContextFactory::IsRenderingContext(contextType)) {
210                continue;
211            }
212            skiatest::ReporterContext ctx(
213                   reporter, SkString(sk_gpu_test::GrContextFactory::ContextTypeName(contextType)));
214            if (ctxInfo.directContext()) {
215                sk_gpu_test::ContextInfo child1 =
216                        factory.getSharedContextInfo(ctxInfo.directContext(), 0);
217                sk_gpu_test::ContextInfo child2 =
218                        factory.getSharedContextInfo(ctxInfo.directContext(), 1);
219                if (!child1.directContext() || !child2.directContext()) {
220                    continue;
221                }
222
223                surface_semaphore_test(reporter, ctxInfo, child1, child2, flushType);
224            }
225        }
226    }
227}
228#endif
229
230DEF_GPUTEST_FOR_RENDERING_CONTEXTS(EmptySurfaceSemaphoreTest, reporter, ctxInfo) {
231    auto ctx = ctxInfo.directContext();
232    if (!ctx->priv().caps()->semaphoreSupport()) {
233        return;
234    }
235
236    const SkImageInfo ii = SkImageInfo::Make(MAIN_W, MAIN_H, kRGBA_8888_SkColorType,
237                                             kPremul_SkAlphaType);
238
239    sk_sp<SkSurface> mainSurface(SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo,
240                                                             ii, 0, kTopLeft_GrSurfaceOrigin,
241                                                             nullptr));
242
243    // Flush surface once without semaphores to make sure there is no peneding IO for it.
244    mainSurface->flushAndSubmit();
245
246    GrBackendSemaphore semaphore;
247    GrFlushInfo flushInfo;
248    flushInfo.fNumSemaphores = 1;
249    flushInfo.fSignalSemaphores = &semaphore;
250    GrSemaphoresSubmitted submitted =
251            mainSurface->flush(SkSurface::BackendSurfaceAccess::kNoAccess, flushInfo);
252    REPORTER_ASSERT(reporter, GrSemaphoresSubmitted::kYes == submitted);
253    ctx->submit();
254
255#ifdef SK_GL
256    if (GrBackendApi::kOpenGL == ctxInfo.backend()) {
257        GrGLGpu* gpu = static_cast<GrGLGpu*>(ctx->priv().getGpu());
258        const GrGLInterface* interface = gpu->glInterface();
259        GrGLsync sync = semaphore.glSync();
260        REPORTER_ASSERT(reporter, sync);
261        bool result;
262        GR_GL_CALL_RET(interface, result, IsSync(sync));
263        REPORTER_ASSERT(reporter, result);
264    }
265#endif
266
267#ifdef SK_VULKAN
268    if (GrBackendApi::kVulkan == ctxInfo.backend()) {
269        GrVkGpu* gpu = static_cast<GrVkGpu*>(ctx->priv().getGpu());
270        const GrVkInterface* interface = gpu->vkInterface();
271        VkDevice device = gpu->device();
272        VkQueue queue = gpu->queue();
273        GrVkCommandPool* cmdPool = gpu->cmdPool();
274        VkCommandBuffer cmdBuffer;
275
276        // Create Command Buffer
277        const VkCommandBufferAllocateInfo cmdInfo = {
278            VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,   // sType
279            nullptr,                                          // pNext
280            cmdPool->vkCommandPool(),                         // commandPool
281            VK_COMMAND_BUFFER_LEVEL_PRIMARY,                  // level
282            1                                                 // bufferCount
283        };
284
285        VkResult err = GR_VK_CALL(interface, AllocateCommandBuffers(device, &cmdInfo, &cmdBuffer));
286        if (err) {
287            return;
288        }
289
290        VkCommandBufferBeginInfo cmdBufferBeginInfo;
291        memset(&cmdBufferBeginInfo, 0, sizeof(VkCommandBufferBeginInfo));
292        cmdBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
293        cmdBufferBeginInfo.pNext = nullptr;
294        cmdBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
295        cmdBufferBeginInfo.pInheritanceInfo = nullptr;
296
297        GR_VK_CALL_ERRCHECK(gpu, BeginCommandBuffer(cmdBuffer, &cmdBufferBeginInfo));
298        GR_VK_CALL_ERRCHECK(gpu, EndCommandBuffer(cmdBuffer));
299
300        VkFenceCreateInfo fenceInfo;
301        VkFence fence;
302
303        memset(&fenceInfo, 0, sizeof(VkFenceCreateInfo));
304        fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
305        err = GR_VK_CALL(interface, CreateFence(device, &fenceInfo, nullptr, &fence));
306        SkASSERT(!err);
307
308        VkPipelineStageFlags waitStages = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
309        VkSubmitInfo submitInfo;
310        memset(&submitInfo, 0, sizeof(VkSubmitInfo));
311        submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
312        submitInfo.pNext = nullptr;
313        submitInfo.waitSemaphoreCount = 1;
314        VkSemaphore vkSem = semaphore.vkSemaphore();
315        submitInfo.pWaitSemaphores = &vkSem;
316        submitInfo.pWaitDstStageMask = &waitStages;
317        submitInfo.commandBufferCount = 1;
318        submitInfo.pCommandBuffers = &cmdBuffer;
319        submitInfo.signalSemaphoreCount = 0;
320        submitInfo.pSignalSemaphores = nullptr;
321        GR_VK_CALL_ERRCHECK(gpu, QueueSubmit(queue, 1, &submitInfo, fence));
322
323        err = GR_VK_CALL(interface, WaitForFences(device, 1, &fence, true, 3000000000));
324
325        REPORTER_ASSERT(reporter, err != VK_TIMEOUT);
326
327        GR_VK_CALL(interface, DestroyFence(device, fence, nullptr));
328        GR_VK_CALL(interface, DestroySemaphore(device, vkSem, nullptr));
329        // If the above test fails the wait semaphore will never be signaled which can cause the
330        // device to hang when tearing down (even if just tearing down GL). So we Fail here to
331        // kill things.
332        if (err == VK_TIMEOUT) {
333            SK_ABORT("Waiting on semaphore indefinitely");
334        }
335    }
336#endif
337}
338