From 8675bcbaf955d586af88ef4ffdd47fe23c9f4dbc Mon Sep 17 00:00:00 2001 From: Brian Salomon Date: Thu, 23 Jan 2020 13:37:39 -0500 Subject: [PATCH] Add support for GL_NV_fence. Will be used for YUV420 readback on ANGLE ES 2 contexts in Chrome. Marks the functions as required as Chrome now adds inits these on GrGLInterface. Bug: 1040643 Change-Id: I5504d4c9209874991592c9f86aaf7987c316aa40 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/265602 Commit-Queue: Brian Salomon Reviewed-by: Greg Daniel --- src/gpu/gl/GrGLCaps.cpp | 40 ++++++++++++------------ src/gpu/gl/GrGLCaps.h | 26 +++++++++++----- src/gpu/gl/GrGLGpu.cpp | 42 ++++++++++++++++++++++---- src/gpu/gl/GrGLInterfaceAutogen.cpp | 8 ++++- tools/gpu/gl/interface/interface.json5 | 3 -- 5 files changed, 80 insertions(+), 39 deletions(-) diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp index 389bfb94de..95c5e61665 100644 --- a/src/gpu/gl/GrGLCaps.cpp +++ b/src/gpu/gl/GrGLCaps.cpp @@ -26,12 +26,6 @@ GrGLCaps::GrGLCaps(const GrContextOptions& contextOptions, const GrGLInterface* glInterface) : INHERITED(contextOptions) { fStandard = ctxInfo.standard(); - fStencilFormats.reset(); - fMSFBOType = kNone_MSFBOType; - fInvalidateFBType = kNone_InvalidateFBType; - fMapBufferType = kNone_MapBufferType; - fTransferBufferType = TransferBufferType::kNone; - fMaxFragmentUniformVectors = 0; fPackFlipYSupport = false; fTextureUsageSupport = false; fImagingSupport = false; @@ -70,9 +64,6 @@ GrGLCaps::GrGLCaps(const GrContextOptions& contextOptions, fFBFetchRequiresEnablePerSample = false; fSRGBWriteControl = false; - fBlitFramebufferFlags = kNoSupport_BlitFramebufferFlag; - fMaxInstancesPerDrawWithoutCrashing = 0; - fShaderCaps.reset(new GrShaderCaps(contextOptions)); this->init(contextOptions, ctxInfo, glInterface); @@ -647,22 +638,29 @@ void GrGLCaps::init(const GrContextOptions& contextOptions, fDrawRangeElementsSupport = version >= GR_GL_VER(2,0); } + // We prefer GL sync objects but also support NV_fence_sync. The former can be + // used to implements GrFence and GrSemaphore. The latter only implements GrFence. // TODO: support CHROMIUM_sync_point and maybe KHR_fence_sync - if (ctxInfo.hasExtension("GL_ARB_sync") || ctxInfo.hasExtension("GL_APPLE_sync")) { - fFenceSyncSupport = true; - } else if (GR_IS_GR_GL(standard)) { - fFenceSyncSupport = (version >= GR_GL_VER(3, 2)); - } else if (GR_IS_GR_GL_ES(standard)) { - fFenceSyncSupport = (version >= GR_GL_VER(3, 0)); - } else if (GR_IS_GR_WEBGL(standard)) { + if (GR_IS_GR_WEBGL(standard)) { // Only in WebGL 2.0 - fFenceSyncSupport = version >= GR_GL_VER(2, 0); + fSemaphoreSupport = fFenceSyncSupport = version >= GR_GL_VER(2, 0); + fFenceType = FenceType::kSyncObject; + } else if (ctxInfo.hasExtension("GL_ARB_sync") || ctxInfo.hasExtension("GL_APPLE_sync")) { + fSemaphoreSupport = fFenceSyncSupport = true; + fFenceType = FenceType::kSyncObject; + } else if (GR_IS_GR_GL(standard) && version >= GR_GL_VER(3, 2)) { + fSemaphoreSupport = fFenceSyncSupport = true; + fFenceType = FenceType::kSyncObject; + } else if (GR_IS_GR_GL_ES(standard) && version >= GR_GL_VER(3, 0)) { + fSemaphoreSupport = fFenceSyncSupport = true; + fFenceType = FenceType::kSyncObject; + } else if (ctxInfo.hasExtension("GL_NV_fence")) { + // This extension can exist in GL and GL ES. We have it last because we prefer the + // standard GLsync object implementation which also supports GPU semaphore semantics. + fFenceSyncSupport = true; + fFenceType = FenceType::kNVFence; } - // The same objects (GL sync objects) are used to implement GPU/CPU fence syncs and GPU/GPU - // semaphores. - fSemaphoreSupport = fFenceSyncSupport; - // Safely moving textures between contexts requires semaphores. fCrossContextTextureSupport = fSemaphoreSupport; diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h index 8a86969dd8..59818ddab1 100644 --- a/src/gpu/gl/GrGLCaps.h +++ b/src/gpu/gl/GrGLCaps.h @@ -100,6 +100,12 @@ public: kChromium, // CHROMIUM_pixel_transfer_buffer_object }; + enum class FenceType { + kNone, + kSyncObject, + kNVFence + }; + /** * Initializes the GrGLCaps to the set of features supported in the current * OpenGL context accessible via ctxInfo. @@ -267,6 +273,9 @@ public: /// What type of transfer buffer is supported? TransferBufferType transferBufferType() const { return fTransferBufferType; } + /// How are GrFences implemented? + FenceType fenceType() const { return fFenceType; } + /// The maximum number of fragment uniform vectors (GLES has min. 16). int maxFragmentUniformVectors() const { return fMaxFragmentUniformVectors; } @@ -480,16 +489,17 @@ private: SupportedRead onSupportedReadPixelsColorType(GrColorType, const GrBackendFormat&, GrColorType) const override; - GrGLStandard fStandard; + GrGLStandard fStandard = kNone_GrGLStandard; SkTArray fStencilFormats; - int fMaxFragmentUniformVectors; + int fMaxFragmentUniformVectors = 0; - MSFBOType fMSFBOType; - InvalidateFBType fInvalidateFBType; - MapBufferType fMapBufferType; - TransferBufferType fTransferBufferType; + MSFBOType fMSFBOType = kNone_MSFBOType; + InvalidateFBType fInvalidateFBType = kNone_InvalidateFBType; + MapBufferType fMapBufferType = kNone_MapBufferType; + TransferBufferType fTransferBufferType = TransferBufferType::kNone; + FenceType fFenceType = FenceType::kNone; bool fPackFlipYSupport : 1; bool fTextureUsageSupport : 1; @@ -530,9 +540,9 @@ private: bool fDetachStencilFromMSAABuffersBeforeReadPixels : 1; bool fDontSetBaseOrMaxLevelForExternalTextures : 1; bool fNeverDisableColorWrites : 1; - int fMaxInstancesPerDrawWithoutCrashing; + int fMaxInstancesPerDrawWithoutCrashing = 0; - uint32_t fBlitFramebufferFlags; + uint32_t fBlitFramebufferFlags = kNoSupport_BlitFramebufferFlag; struct ReadPixelsFormat { ReadPixelsFormat() : fFormat(0), fType(0) {} diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp index 58c255a7e3..313aaefea7 100644 --- a/src/gpu/gl/GrGLGpu.cpp +++ b/src/gpu/gl/GrGLGpu.cpp @@ -4076,16 +4076,41 @@ void GrGLGpu::submit(GrOpsRenderPass* renderPass) { GrFence SK_WARN_UNUSED_RESULT GrGLGpu::insertFence() { SkASSERT(this->caps()->fenceSyncSupport()); GrGLsync sync; - GL_CALL_RET(sync, FenceSync(GR_GL_SYNC_GPU_COMMANDS_COMPLETE, 0)); + if (this->glCaps().fenceType() == GrGLCaps::FenceType::kNVFence) { + static_assert(sizeof(GrGLsync) >= sizeof(GrGLuint)); + GrGLuint fence = 0; + GL_CALL(GenFences(1, &fence)); + GL_CALL(SetFence(fence, GR_GL_ALL_COMPLETED)); + sync = reinterpret_cast(static_cast(fence)); + } else { + GL_CALL_RET(sync, FenceSync(GR_GL_SYNC_GPU_COMMANDS_COMPLETE, 0)); + } static_assert(sizeof(GrFence) >= sizeof(GrGLsync)); return (GrFence)sync; } bool GrGLGpu::waitSync(GrGLsync sync, uint64_t timeout, bool flush) { - GrGLbitfield flags = flush ? GR_GL_SYNC_FLUSH_COMMANDS_BIT : 0; - GrGLenum result; - GL_CALL_RET(result, ClientWaitSync(sync, flags, timeout)); - return (GR_GL_CONDITION_SATISFIED == result || GR_GL_ALREADY_SIGNALED == result); + if (this->glCaps().fenceType() == GrGLCaps::FenceType::kNVFence) { + GrGLuint nvFence = static_cast(reinterpret_cast(sync)); + if (!timeout) { + if (flush) { + GL_CALL(Flush); + } + GrGLboolean result; + GL_CALL_RET(result, TestFence(nvFence)); + return result == GR_GL_TRUE; + } + // Ignore non-zero timeouts. GL_NV_fence has no timeout functionality. + // If this really becomes necessary we could poll TestFence(). + // FinishFence always flushes so no need to check flush param. + GL_CALL(FinishFence(nvFence)); + return true; + } else { + GrGLbitfield flags = flush ? GR_GL_SYNC_FLUSH_COMMANDS_BIT : 0; + GrGLenum result; + GL_CALL_RET(result, ClientWaitSync(sync, flags, timeout)); + return (GR_GL_CONDITION_SATISFIED == result || GR_GL_ALREADY_SIGNALED == result); + } } bool GrGLGpu::waitFence(GrFence fence, uint64_t timeout) { @@ -4134,7 +4159,12 @@ void GrGLGpu::checkFinishProcs() { } void GrGLGpu::deleteSync(GrGLsync sync) const { - GL_CALL(DeleteSync(sync)); + if (this->glCaps().fenceType() == GrGLCaps::FenceType::kNVFence) { + GrGLuint nvFence = SkToUInt(reinterpret_cast(sync)); + GL_CALL(DeleteFences(1, &nvFence)); + } else { + GL_CALL(DeleteSync(sync)); + } } std::unique_ptr GrGLGpu::prepareTextureForCrossContextUsage(GrTexture* texture) { diff --git a/src/gpu/gl/GrGLInterfaceAutogen.cpp b/src/gpu/gl/GrGLInterfaceAutogen.cpp index 8f5030e70a..dcc337c430 100644 --- a/src/gpu/gl/GrGLInterfaceAutogen.cpp +++ b/src/gpu/gl/GrGLInterfaceAutogen.cpp @@ -747,7 +747,13 @@ bool GrGLInterface::validate() const { fExtensions.has("GL_NV_fence"))) || (GR_IS_GR_GL_ES(fStandard) && ( fExtensions.has("GL_NV_fence")))) { - // all functions were marked optional or test_only + if (!fFunctions.fDeleteFences || + !fFunctions.fFinishFence || + !fFunctions.fGenFences || + !fFunctions.fSetFence || + !fFunctions.fTestFence) { + RETURN_FALSE_INTERFACE; + } } diff --git a/tools/gpu/gl/interface/interface.json5 b/tools/gpu/gl/interface/interface.json5 index af7274cc32..8ba26aebce 100644 --- a/tools/gpu/gl/interface/interface.json5 +++ b/tools/gpu/gl/interface/interface.json5 @@ -731,8 +731,5 @@ "functions": [ "DeleteFences", "FinishFence", "GenFences", "SetFence", "TestFence", ], - "optional": [ - "DeleteFences", "FinishFence", "GenFences", "SetFence", "TestFence" - ] } ]