Home | History | Annotate | Download | only in tests
      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 "vk/GrVkVulkan.h"
      9 
     10 #include "GrContextPriv.h"
     11 #include "GrContextFactory.h"
     12 #include "Test.h"
     13 
     14 #include "GrBackendSemaphore.h"
     15 #include "GrBackendSurface.h"
     16 #include "SkCanvas.h"
     17 #include "SkSurface.h"
     18 
     19 #include "gl/GrGLGpu.h"
     20 #include "gl/GrGLUtil.h"
     21 
     22 #ifdef SK_VULKAN
     23 #include "vk/GrVkCommandPool.h"
     24 #include "vk/GrVkGpu.h"
     25 #include "vk/GrVkTypes.h"
     26 #include "vk/GrVkUtil.h"
     27 
     28 #ifdef VK_USE_PLATFORM_WIN32_KHR
     29 // windows wants to define this as CreateSemaphoreA or CreateSemaphoreW
     30 #undef CreateSemaphore
     31 #endif
     32 #endif
     33 
     34 static const int MAIN_W = 8, MAIN_H = 16;
     35 static const int CHILD_W = 16, CHILD_H = 16;
     36 
     37 void 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 
     63 void draw_child(skiatest::Reporter* reporter,
     64                 const sk_gpu_test::ContextInfo& childInfo,
     65                 const GrBackendTexture& backendTexture,
     66                 const GrBackendSemaphore& semaphore) {
     67 
     68     childInfo.testContext()->makeCurrent();
     69 
     70     const SkImageInfo childII = SkImageInfo::Make(CHILD_W, CHILD_H, kRGBA_8888_SkColorType,
     71                                                   kPremul_SkAlphaType);
     72 
     73     GrContext* childCtx = childInfo.grContext();
     74     sk_sp<SkSurface> childSurface(SkSurface::MakeRenderTarget(childCtx, SkBudgeted::kNo,
     75                                                               childII, 0, kTopLeft_GrSurfaceOrigin,
     76                                                               nullptr));
     77 
     78     sk_sp<SkImage> childImage = SkImage::MakeFromTexture(childCtx,
     79                                                          backendTexture,
     80                                                          kTopLeft_GrSurfaceOrigin,
     81                                                          kRGBA_8888_SkColorType,
     82                                                          kPremul_SkAlphaType,
     83                                                          nullptr,
     84                                                          nullptr,
     85                                                          nullptr);
     86 
     87     SkCanvas* childCanvas = childSurface->getCanvas();
     88     childCanvas->clear(SK_ColorRED);
     89 
     90     childSurface->wait(1, &semaphore);
     91 
     92     childCanvas->drawImage(childImage, CHILD_W/2, 0);
     93 
     94     SkPaint paint;
     95     paint.setColor(SK_ColorGREEN);
     96     SkIRect rect = SkIRect::MakeLTRB(0, CHILD_H/2, CHILD_W, CHILD_H);
     97     childCanvas->drawIRect(rect, paint);
     98 
     99     // read pixels
    100     SkBitmap bitmap;
    101     bitmap.allocPixels(childII);
    102     childSurface->readPixels(bitmap, 0, 0);
    103 
    104     check_pixels(reporter, bitmap);
    105 }
    106 
    107 void surface_semaphore_test(skiatest::Reporter* reporter,
    108                             const sk_gpu_test::ContextInfo& mainInfo,
    109                             const sk_gpu_test::ContextInfo& childInfo1,
    110                             const sk_gpu_test::ContextInfo& childInfo2,
    111                             bool flushContext) {
    112     GrContext* mainCtx = mainInfo.grContext();
    113     if (!mainCtx->priv().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);
    127 #ifdef SK_VULKAN
    128     if (GrBackendApi::kVulkan == mainInfo.backend()) {
    129         // Initialize the secondary semaphore instead of having Ganesh create one internally
    130         GrVkGpu* gpu = static_cast<GrVkGpu*>(mainCtx->priv().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
    145 
    146     if (flushContext) {
    147         mainCtx->flush(kNone_GrFlushFlags, 2, semaphores.get());
    148     } else {
    149         mainSurface->flushAndSignalSemaphores(2, semaphores.get());
    150     }
    151 
    152     sk_sp<SkImage> mainImage = mainSurface->makeImageSnapshot();
    153     GrBackendTexture backendTexture = mainImage->getBackendTexture(false);
    154 
    155     draw_child(reporter, childInfo1, backendTexture, semaphores[0]);
    156 
    157 #ifdef SK_VULKAN
    158     if (GrBackendApi::kVulkan == mainInfo.backend()) {
    159         // In Vulkan we need to make sure we are sending the correct VkImageLayout in with the
    160         // backendImage. After the first child draw the layout gets changed to SHADER_READ, so
    161         // we just manually set that here.
    162         GrVkImageInfo vkInfo;
    163         SkAssertResult(backendTexture.getVkImageInfo(&vkInfo));
    164         vkInfo.updateImageLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
    165     }
    166 #endif
    167 
    168     draw_child(reporter, childInfo2, backendTexture, semaphores[1]);
    169 }
    170 
    171 DEF_GPUTEST(SurfaceSemaphores, reporter, options) {
    172 #if defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_WIN) || defined(SK_BUILD_FOR_MAC)
    173     static constexpr auto kNativeGLType = sk_gpu_test::GrContextFactory::kGL_ContextType;
    174 #else
    175     static constexpr auto kNativeGLType = sk_gpu_test::GrContextFactory::kGLES_ContextType;
    176 #endif
    177 
    178     for (int typeInt = 0; typeInt < sk_gpu_test::GrContextFactory::kContextTypeCnt; ++typeInt) {
    179         for (auto flushContext : { false, true }) {
    180             sk_gpu_test::GrContextFactory::ContextType contextType =
    181                     (sk_gpu_test::GrContextFactory::ContextType) typeInt;
    182             // Use "native" instead of explicitly trying OpenGL and OpenGL ES. Do not use GLES on
    183             // desktop since tests do not account for not fixing http://skbug.com/2809
    184             if (contextType == sk_gpu_test::GrContextFactory::kGL_ContextType ||
    185                 contextType == sk_gpu_test::GrContextFactory::kGLES_ContextType) {
    186                 if (contextType != kNativeGLType) {
    187                     continue;
    188                 }
    189             }
    190             sk_gpu_test::GrContextFactory factory(options);
    191             sk_gpu_test::ContextInfo ctxInfo = factory.getContextInfo(
    192                     contextType, sk_gpu_test::GrContextFactory::ContextOverrides::kDisableNVPR);
    193             if (!sk_gpu_test::GrContextFactory::IsRenderingContext(contextType)) {
    194                 continue;
    195             }
    196             skiatest::ReporterContext ctx(
    197                    reporter, SkString(sk_gpu_test::GrContextFactory::ContextTypeName(contextType)));
    198             if (ctxInfo.grContext()) {
    199                 sk_gpu_test::ContextInfo child1 =
    200                         factory.getSharedContextInfo(ctxInfo.grContext(), 0);
    201                 sk_gpu_test::ContextInfo child2 =
    202                         factory.getSharedContextInfo(ctxInfo.grContext(), 1);
    203                 if (!child1.grContext() || !child2.grContext()) {
    204                     continue;
    205                 }
    206 
    207                 surface_semaphore_test(reporter, ctxInfo, child1, child2, flushContext);
    208             }
    209         }
    210     }
    211 }
    212 
    213 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(EmptySurfaceSemaphoreTest, reporter, ctxInfo) {
    214     GrContext* ctx = ctxInfo.grContext();
    215     if (!ctx->priv().caps()->fenceSyncSupport()) {
    216         return;
    217     }
    218 
    219     const SkImageInfo ii = SkImageInfo::Make(MAIN_W, MAIN_H, kRGBA_8888_SkColorType,
    220                                              kPremul_SkAlphaType);
    221 
    222     sk_sp<SkSurface> mainSurface(SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo,
    223                                                              ii, 0, kTopLeft_GrSurfaceOrigin,
    224                                                              nullptr));
    225 
    226     // Flush surface once without semaphores to make sure there is no peneding IO for it.
    227     mainSurface->flush();
    228 
    229     GrBackendSemaphore semaphore;
    230     GrSemaphoresSubmitted submitted = mainSurface->flushAndSignalSemaphores(1, &semaphore);
    231     REPORTER_ASSERT(reporter, GrSemaphoresSubmitted::kYes == submitted);
    232 
    233     if (GrBackendApi::kOpenGL == ctxInfo.backend()) {
    234         GrGLGpu* gpu = static_cast<GrGLGpu*>(ctx->priv().getGpu());
    235         const GrGLInterface* interface = gpu->glInterface();
    236         GrGLsync sync = semaphore.glSync();
    237         REPORTER_ASSERT(reporter, sync);
    238         bool result;
    239         GR_GL_CALL_RET(interface, result, IsSync(sync));
    240         REPORTER_ASSERT(reporter, result);
    241     }
    242 
    243 #ifdef SK_VULKAN
    244     if (GrBackendApi::kVulkan == ctxInfo.backend()) {
    245         GrVkGpu* gpu = static_cast<GrVkGpu*>(ctx->priv().getGpu());
    246         const GrVkInterface* interface = gpu->vkInterface();
    247         VkDevice device = gpu->device();
    248         VkQueue queue = gpu->queue();
    249         GrVkCommandPool* cmdPool = gpu->cmdPool();
    250         VkCommandBuffer cmdBuffer;
    251 
    252         // Create Command Buffer
    253         const VkCommandBufferAllocateInfo cmdInfo = {
    254             VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,   // sType
    255             nullptr,                                          // pNext
    256             cmdPool->vkCommandPool(),                         // commandPool
    257             VK_COMMAND_BUFFER_LEVEL_PRIMARY,                  // level
    258             1                                                 // bufferCount
    259         };
    260 
    261         VkResult err = GR_VK_CALL(interface, AllocateCommandBuffers(device, &cmdInfo, &cmdBuffer));
    262         if (err) {
    263             return;
    264         }
    265 
    266         VkCommandBufferBeginInfo cmdBufferBeginInfo;
    267         memset(&cmdBufferBeginInfo, 0, sizeof(VkCommandBufferBeginInfo));
    268         cmdBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
    269         cmdBufferBeginInfo.pNext = nullptr;
    270         cmdBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
    271         cmdBufferBeginInfo.pInheritanceInfo = nullptr;
    272 
    273         GR_VK_CALL_ERRCHECK(interface, BeginCommandBuffer(cmdBuffer, &cmdBufferBeginInfo));
    274         GR_VK_CALL_ERRCHECK(interface, EndCommandBuffer(cmdBuffer));
    275 
    276         VkFenceCreateInfo fenceInfo;
    277         VkFence fence;
    278 
    279         memset(&fenceInfo, 0, sizeof(VkFenceCreateInfo));
    280         fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
    281         err = GR_VK_CALL(interface, CreateFence(device, &fenceInfo, nullptr, &fence));
    282         SkASSERT(!err);
    283 
    284         VkPipelineStageFlags waitStages = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
    285         VkSubmitInfo submitInfo;
    286         memset(&submitInfo, 0, sizeof(VkSubmitInfo));
    287         submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
    288         submitInfo.pNext = nullptr;
    289         submitInfo.waitSemaphoreCount = 1;
    290         VkSemaphore vkSem = semaphore.vkSemaphore();
    291         submitInfo.pWaitSemaphores = &vkSem;
    292         submitInfo.pWaitDstStageMask = &waitStages;
    293         submitInfo.commandBufferCount = 1;
    294         submitInfo.pCommandBuffers = &cmdBuffer;
    295         submitInfo.signalSemaphoreCount = 0;
    296         submitInfo.pSignalSemaphores = nullptr;
    297         GR_VK_CALL_ERRCHECK(interface, QueueSubmit(queue, 1, &submitInfo, fence));
    298 
    299         err = GR_VK_CALL(interface, WaitForFences(device, 1, &fence, true, 3000000000));
    300 
    301         REPORTER_ASSERT(reporter, err != VK_TIMEOUT);
    302 
    303         GR_VK_CALL(interface, DestroyFence(device, fence, nullptr));
    304         GR_VK_CALL(interface, DestroySemaphore(device, vkSem, nullptr));
    305         // If the above test fails the wait semaphore will never be signaled which can cause the
    306         // device to hang when tearing down (even if just tearing down GL). So we Fail here to
    307         // kill things.
    308         if (err == VK_TIMEOUT) {
    309             SK_ABORT("Waiting on semaphore indefinitely");
    310         }
    311     }
    312 #endif
    313 }
    314