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 <egdaniel@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
This commit is contained in:
Greg Daniel 2017-07-20 15:47:30 -04:00 committed by Skia Commit-Bot
parent c7d295ecf7
commit dba7e7ccfb
7 changed files with 122 additions and 0 deletions

View File

@ -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);

View File

@ -456,6 +456,7 @@ public:
/* ARB_sync */
GrGLFunction<GrGLFenceSyncProc> fFenceSync;
GrGLFunction<GrGLIsSyncProc> fIsSync;
GrGLFunction<GrGLClientWaitSyncProc> fClientWaitSync;
GrGLFunction<GrGLWaitSyncProc> fWaitSync;
GrGLFunction<GrGLDeleteSyncProc> fDeleteSync;

View File

@ -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);

View File

@ -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) {

View File

@ -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);

View File

@ -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) {}

View File

@ -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<SkSurface> 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<GrGLGpu*>(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<GrVkGpu*>(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