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 <bsalomon@google.com>
Reviewed-by: Greg Daniel <egdaniel@google.com>
This commit is contained in:
Brian Salomon 2020-01-23 13:37:39 -05:00 committed by Skia Commit-Bot
parent a7e557f3e3
commit 8675bcbaf9
5 changed files with 80 additions and 39 deletions

View File

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

View File

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

View File

@ -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<GrGLsync>(static_cast<intptr_t>(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<GrGLuint>(reinterpret_cast<intptr_t>(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<intptr_t>(sync));
GL_CALL(DeleteFences(1, &nvFence));
} else {
GL_CALL(DeleteSync(sync));
}
}
std::unique_ptr<GrSemaphore> GrGLGpu::prepareTextureForCrossContextUsage(GrTexture* texture) {

View File

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

View File

@ -731,8 +731,5 @@
"functions": [
"DeleteFences", "FinishFence", "GenFences", "SetFence", "TestFence",
],
"optional": [
"DeleteFences", "FinishFence", "GenFences", "SetFence", "TestFence"
]
}
]