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:
parent
c7d295ecf7
commit
dba7e7ccfb
@ -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);
|
||||
|
@ -456,6 +456,7 @@ public:
|
||||
|
||||
/* ARB_sync */
|
||||
GrGLFunction<GrGLFenceSyncProc> fFenceSync;
|
||||
GrGLFunction<GrGLIsSyncProc> fIsSync;
|
||||
GrGLFunction<GrGLClientWaitSyncProc> fClientWaitSync;
|
||||
GrGLFunction<GrGLWaitSyncProc> fWaitSync;
|
||||
GrGLFunction<GrGLDeleteSyncProc> fDeleteSync;
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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) {}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user