From dba7e7ccfbab1c99b8a3f81156cecdb630d7d03a Mon Sep 17 00:00:00 2001 From: Greg Daniel Date: Thu, 20 Jul 2017 15:47:30 -0400 Subject: Add test for flushing empty surface with semaphores Bug: skia: Change-Id: I8d7dcb29c5b4c460aa5137842caf6563448ba5d3 Reviewed-on: https://skia-review.googlesource.com/25181 Commit-Queue: Greg Daniel Reviewed-by: Robert Phillips --- include/gpu/gl/GrGLFunctions.h | 1 + include/gpu/gl/GrGLInterface.h | 1 + src/gpu/gl/GrGLAssembleInterface.cpp | 3 + src/gpu/gl/GrGLInterface.cpp | 4 ++ src/gpu/gl/GrGLTestInterface.cpp | 1 + src/gpu/gl/GrGLTestInterface.h | 1 + tests/SurfaceSemaphoreTest.cpp | 111 +++++++++++++++++++++++++++++++++++ 7 files changed, 122 insertions(+) diff --git a/include/gpu/gl/GrGLFunctions.h b/include/gpu/gl/GrGLFunctions.h index 5166a4b099..c1b3d0dd68 100644 --- a/include/gpu/gl/GrGLFunctions.h +++ b/include/gpu/gl/GrGLFunctions.h @@ -353,6 +353,7 @@ typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLTextureBufferProc)(GrGLuint texture, /* ARB_sync */ typedef GrGLsync (GR_GL_FUNCTION_TYPE* GrGLFenceSyncProc)(GrGLenum condition, GrGLbitfield flags); +typedef GrGLboolean (GR_GL_FUNCTION_TYPE* GrGLIsSyncProc)(GrGLsync sync); typedef GrGLenum (GR_GL_FUNCTION_TYPE* GrGLClientWaitSyncProc)(GrGLsync sync, GrGLbitfield flags, GrGLuint64 timeout); typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLWaitSyncProc)(GrGLsync sync, GrGLbitfield flags, GrGLuint64 timeout); typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDeleteSyncProc)(GrGLsync sync); diff --git a/include/gpu/gl/GrGLInterface.h b/include/gpu/gl/GrGLInterface.h index 10880471ce..56e655d887 100644 --- a/include/gpu/gl/GrGLInterface.h +++ b/include/gpu/gl/GrGLInterface.h @@ -456,6 +456,7 @@ public: /* ARB_sync */ GrGLFunction fFenceSync; + GrGLFunction fIsSync; GrGLFunction fClientWaitSync; GrGLFunction fWaitSync; GrGLFunction fDeleteSync; diff --git a/src/gpu/gl/GrGLAssembleInterface.cpp b/src/gpu/gl/GrGLAssembleInterface.cpp index 64bed32136..6b0234abb7 100644 --- a/src/gpu/gl/GrGLAssembleInterface.cpp +++ b/src/gpu/gl/GrGLAssembleInterface.cpp @@ -516,6 +516,7 @@ const GrGLInterface* GrGLAssembleGLInterface(void* ctx, GrGLGetProc get) { if (glVer >= GR_GL_VER(3, 2) || extensions.has("GL_ARB_sync")) { GET_PROC(FenceSync); + GET_PROC(IsSync); GET_PROC(ClientWaitSync); GET_PROC(WaitSync); GET_PROC(DeleteSync); @@ -940,11 +941,13 @@ const GrGLInterface* GrGLAssembleGLESInterface(void* ctx, GrGLGetProc get) { if (version >= GR_GL_VER(3, 0)) { GET_PROC(FenceSync); + GET_PROC(IsSync); GET_PROC(ClientWaitSync); GET_PROC(WaitSync); GET_PROC(DeleteSync); } else if (extensions.has("GL_APPLE_sync")) { GET_PROC_SUFFIX(FenceSync, APPLE); + GET_PROC_SUFFIX(IsSync, APPLE); GET_PROC_SUFFIX(ClientWaitSync, APPLE); GET_PROC_SUFFIX(WaitSync, APPLE); GET_PROC_SUFFIX(DeleteSync, APPLE); diff --git a/src/gpu/gl/GrGLInterface.cpp b/src/gpu/gl/GrGLInterface.cpp index 09d7a4fad3..dcad07e1f2 100644 --- a/src/gpu/gl/GrGLInterface.cpp +++ b/src/gpu/gl/GrGLInterface.cpp @@ -757,6 +757,8 @@ bool GrGLInterface::validate() const { if (kGL_GrGLStandard == fStandard) { if (glVer >= GR_GL_VER(3, 2) || fExtensions.has("GL_ARB_sync")) { if (nullptr == fFunctions.fFenceSync || + // Is sync needs to be added to chrome before uncommenting + // nullptr == fFunctions.fIsSync || nullptr == fFunctions.fClientWaitSync || nullptr == fFunctions.fWaitSync || nullptr == fFunctions.fDeleteSync) { @@ -766,6 +768,8 @@ bool GrGLInterface::validate() const { } else if (kGLES_GrGLStandard == fStandard) { if (glVer >= GR_GL_VER(3, 0) || fExtensions.has("GL_APPLE_sync")) { if (nullptr == fFunctions.fFenceSync || + // Is sync needs to be added to chrome before uncommenting + // nullptr == fFunctions.fIsSync || nullptr == fFunctions.fClientWaitSync || nullptr == fFunctions.fWaitSync || nullptr == fFunctions.fDeleteSync) { diff --git a/src/gpu/gl/GrGLTestInterface.cpp b/src/gpu/gl/GrGLTestInterface.cpp index ef86ea71b9..45482e0066 100644 --- a/src/gpu/gl/GrGLTestInterface.cpp +++ b/src/gpu/gl/GrGLTestInterface.cpp @@ -314,6 +314,7 @@ GrGLTestInterface::GrGLTestInterface() { fFunctions.fFlushMappedNamedBufferRange = bind_to_member(this, &GrGLTestInterface::flushMappedNamedBufferRange); fFunctions.fTextureBuffer = bind_to_member(this, &GrGLTestInterface::textureBuffer); fFunctions.fFenceSync = bind_to_member(this, &GrGLTestInterface::fenceSync); + fFunctions.fIsSync = bind_to_member(this, &GrGLTestInterface::isSync); fFunctions.fClientWaitSync = bind_to_member(this, &GrGLTestInterface::clientWaitSync); fFunctions.fWaitSync = bind_to_member(this, &GrGLTestInterface::waitSync); fFunctions.fDeleteSync = bind_to_member(this, &GrGLTestInterface::deleteSync); diff --git a/src/gpu/gl/GrGLTestInterface.h b/src/gpu/gl/GrGLTestInterface.h index 69427f8d5a..1ebf90b7cf 100644 --- a/src/gpu/gl/GrGLTestInterface.h +++ b/src/gpu/gl/GrGLTestInterface.h @@ -319,6 +319,7 @@ public: virtual GrGLvoid flushMappedNamedBufferRange(GrGLuint buffer, GrGLintptr offset, GrGLsizeiptr length) {} virtual GrGLvoid textureBuffer(GrGLuint texture, GrGLenum target, GrGLenum internalformat, GrGLuint buffer) {} virtual GrGLsync fenceSync(GrGLenum condition, GrGLbitfield flags) { return nullptr; } + virtual GrGLboolean isSync(GrGLsync) { return false; } virtual GrGLenum clientWaitSync(GrGLsync sync, GrGLbitfield flags, GrGLuint64 timeout) { return GR_GL_WAIT_FAILED; } virtual GrGLvoid waitSync(GrGLsync sync, GrGLbitfield flags, GrGLuint64 timeout) {} virtual GrGLvoid deleteSync(GrGLsync sync) {} diff --git a/tests/SurfaceSemaphoreTest.cpp b/tests/SurfaceSemaphoreTest.cpp index 72e8e05401..7b22e1cf33 100644 --- a/tests/SurfaceSemaphoreTest.cpp +++ b/tests/SurfaceSemaphoreTest.cpp @@ -17,8 +17,18 @@ #include "SkCanvas.h" #include "SkSurface.h" +#include "gl/GrGLGpu.h" +#include "gl/GrGLUtil.h" + #ifdef SK_VULKAN +#include "vk/GrVkGpu.h" #include "vk/GrVkTypes.h" +#include "vk/GrVkUtil.h" + +#ifdef VK_USE_PLATFORM_WIN32_KHR +// windows wants to define this as CreateSemaphoreA or CreateSemaphoreW + #undef CreateSemaphore + #endif #endif static const int MAIN_W = 8, MAIN_H = 16; @@ -172,4 +182,105 @@ DEF_GPUTEST(SurfaceSemaphores, reporter, factory) { } } +DEF_GPUTEST_FOR_RENDERING_CONTEXTS(EmptySurfaceSemaphoreTest, reporter, ctxInfo) { + GrContext* ctx = ctxInfo.grContext(); + if (!ctx->caps()->fenceSyncSupport()) { + return; + } + + const SkImageInfo ii = SkImageInfo::Make(MAIN_W, MAIN_H, kRGBA_8888_SkColorType, + kPremul_SkAlphaType); + + sk_sp mainSurface(SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, + ii, 0, kTopLeft_GrSurfaceOrigin, + nullptr)); + + // Flush surface once without semaphores to make sure there is no peneding IO for it. + mainSurface->flush(); + + GrBackendSemaphore semaphore; + REPORTER_ASSERT(reporter, mainSurface->flushAndSignalSemaphores(1, &semaphore)); + + if (kOpenGL_GrBackend == ctxInfo.backend()) { + GrGLGpu* gpu = static_cast(ctx->getGpu()); + const GrGLInterface* interface = gpu->glInterface(); + GrGLsync sync = semaphore.glSync(); + REPORTER_ASSERT(reporter, sync); + bool result; + GR_GL_CALL_RET(interface, result, IsSync(sync)); + REPORTER_ASSERT(reporter, result); + } + +#ifdef SK_VULKAN + if (kVulkan_GrBackend == ctxInfo.backend()) { + GrVkGpu* gpu = static_cast(ctx->getGpu()); + const GrVkInterface* interface = gpu->vkInterface(); + VkDevice device = gpu->device(); + VkQueue queue = gpu->queue(); + VkCommandPool cmdPool = gpu->cmdPool(); + VkCommandBuffer cmdBuffer; + + // Create Command Buffer + const VkCommandBufferAllocateInfo cmdInfo = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // sType + nullptr, // pNext + cmdPool, // commandPool + VK_COMMAND_BUFFER_LEVEL_PRIMARY, // level + 1 // bufferCount + }; + + VkResult err = GR_VK_CALL(interface, AllocateCommandBuffers(device, &cmdInfo, &cmdBuffer)); + if (err) { + return; + } + + VkCommandBufferBeginInfo cmdBufferBeginInfo; + memset(&cmdBufferBeginInfo, 0, sizeof(VkCommandBufferBeginInfo)); + cmdBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + cmdBufferBeginInfo.pNext = nullptr; + cmdBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + cmdBufferBeginInfo.pInheritanceInfo = nullptr; + + GR_VK_CALL_ERRCHECK(interface, BeginCommandBuffer(cmdBuffer, &cmdBufferBeginInfo)); + GR_VK_CALL_ERRCHECK(interface, EndCommandBuffer(cmdBuffer)); + + VkFenceCreateInfo fenceInfo; + VkFence fence; + + memset(&fenceInfo, 0, sizeof(VkFenceCreateInfo)); + fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + err = GR_VK_CALL(interface, CreateFence(device, &fenceInfo, nullptr, &fence)); + SkASSERT(!err); + + VkPipelineStageFlags waitStages = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; + VkSubmitInfo submitInfo; + memset(&submitInfo, 0, sizeof(VkSubmitInfo)); + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.pNext = nullptr; + submitInfo.waitSemaphoreCount = 1; + VkSemaphore vkSem = semaphore.vkSemaphore(); + submitInfo.pWaitSemaphores = &vkSem; + submitInfo.pWaitDstStageMask = &waitStages; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &cmdBuffer; + submitInfo.signalSemaphoreCount = 0; + submitInfo.pSignalSemaphores = nullptr; + GR_VK_CALL_ERRCHECK(interface, QueueSubmit(queue, 1, &submitInfo, fence)); + + err = GR_VK_CALL(interface, WaitForFences(device, 1, &fence, true, 3000000000)); + + REPORTER_ASSERT(reporter, err != VK_TIMEOUT); + + GR_VK_CALL(interface, DestroyFence(device, fence, nullptr)); + GR_VK_CALL(interface, DestroySemaphore(device, vkSem, nullptr)); + // If the above test fails the wait semaphore will never be signaled which can cause the + // device to hang when tearing down (even if just tearing down GL). So we Fail here to + // kill things. + if (err == VK_TIMEOUT) { + SkFAIL("Waiting on semaphore indefinitely"); + } + } +#endif +} + #endif -- cgit v1.2.3