Remove wrapping of GL sync objects around EGL syncs in EGL test contexts

We did this to allow pipelining of GPU/CPU work in nanobench on devices
that don't have GL sync objects (or NV fence). However, we've found
that on the AndroidOne/Mali400 and Nexus7/Tegra3 devices that the
majority of a frame's work can be reordered to complete before an
earlier EGL sync. This makes the results unreliable, especially the
min_ms result. Just accept that we will sync the CPU and GPU on these
devices.

Change-Id: I04d168cbb05504d367f6a06b7b4903163ab2aa79
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/414897
Commit-Queue: Brian Salomon <bsalomon@google.com>
Commit-Queue: Adlai Holler <adlai@google.com>
Auto-Submit: Brian Salomon <bsalomon@google.com>
Reviewed-by: Adlai Holler <adlai@google.com>
This commit is contained in:
Brian Salomon 2021-06-02 11:35:56 -04:00 committed by Skia Commit-Bot
parent 5e6a1fec93
commit 7db0e2f942

View File

@ -43,8 +43,6 @@ private:
std::function<void()> onPlatformGetAutoContextRestore() const override;
GrGLFuncPtr onPlatformGetProcAddress(const char*) const override;
void setupFenceSync(sk_sp<const GrGLInterface>);
PFNEGLCREATEIMAGEKHRPROC fEglCreateImageProc = nullptr;
PFNEGLDESTROYIMAGEKHRPROC fEglDestroyImageProc = nullptr;
@ -184,8 +182,6 @@ EGLGLTestContext::EGLGLTestContext(GrGLStandard forcedGpuAPI, EGLGLTestContext*
continue;
}
this->setupFenceSync(gl);
if (!gl->validate()) {
SkDebugf("Failed to validate gl interface.\n");
this->destroyGLContext();
@ -209,134 +205,6 @@ EGLGLTestContext::EGLGLTestContext(GrGLStandard forcedGpuAPI, EGLGLTestContext*
}
}
static bool supports_egl_extension(EGLDisplay display, const char* extension) {
size_t extensionLength = strlen(extension);
const char* extensionsStr = eglQueryString(display, EGL_EXTENSIONS);
while (const char* match = strstr(extensionsStr, extension)) {
// Ensure the string we found is its own extension, not a substring of a larger extension
// (e.g. GL_ARB_occlusion_query / GL_ARB_occlusion_query2).
if ((match == extensionsStr || match[-1] == ' ') &&
(match[extensionLength] == ' ' || match[extensionLength] == '\0')) {
return true;
}
extensionsStr = match + extensionLength;
}
return false;
}
void EGLGLTestContext::setupFenceSync(sk_sp<const GrGLInterface> interface) {
GrGLInterface* glInt = const_cast<GrGLInterface*>(interface.get());
if (kGL_GrGLStandard == glInt->fStandard) {
if (GrGLGetVersion(glInt) >= GR_GL_VER(3,2) || glInt->hasExtension("GL_ARB_sync")) {
return;
}
} else {
if (glInt->hasExtension("GL_APPLE_sync") || glInt->hasExtension("GL_NV_fence") ||
GrGLGetVersion(glInt) >= GR_GL_VER(3, 0)) {
return;
}
}
if (!supports_egl_extension(fDisplay, "EGL_KHR_fence_sync")) {
return;
}
auto grEGLCreateSyncKHR = (PFNEGLCREATESYNCKHRPROC) eglGetProcAddress("eglCreateSyncKHR");
auto grEGLClientWaitSyncKHR =
(PFNEGLCLIENTWAITSYNCKHRPROC) eglGetProcAddress("eglClientWaitSyncKHR");
auto grEGLDestroySyncKHR = (PFNEGLDESTROYSYNCKHRPROC) eglGetProcAddress("eglDestroySyncKHR");
auto grEGLGetSyncAttribKHR =
(PFNEGLGETSYNCATTRIBKHRPROC) eglGetProcAddress("eglGetSyncAttribKHR");
SkASSERT(grEGLCreateSyncKHR && grEGLClientWaitSyncKHR && grEGLDestroySyncKHR &&
grEGLGetSyncAttribKHR);
PFNEGLWAITSYNCKHRPROC grEGLWaitSyncKHR = nullptr;
if (supports_egl_extension(fDisplay, "EGL_KHR_wait_sync")) {
grEGLWaitSyncKHR = (PFNEGLWAITSYNCKHRPROC)eglGetProcAddress("eglWaitSyncKHR");
SkASSERT(grEGLWaitSyncKHR);
}
// Fake out glSync using eglSync
glInt->fExtensions.add("GL_APPLE_sync");
glInt->fFunctions.fFenceSync =
[grEGLCreateSyncKHR, display = fDisplay, surface = fSurface](GrGLenum condition,
GrGLbitfield flags) {
SkASSERT(condition == GR_GL_SYNC_GPU_COMMANDS_COMPLETE);
SkASSERT(flags == 0);
EGLSyncKHR sync = grEGLCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr);
// It seems that, at least on the 2012 N7, later render passes will be reordered before a
// fence. This really messes up benchmark timings where a large fraction of the work for
// sample N can occur before the fence for sample N-1 signals. This causes sample N-1 to be
// artificially slow and N artificially fast. Inserting a swap buffers (to the unused
// display surface) blocks that reordering.
eglSwapBuffers(display, surface);
return reinterpret_cast<GrGLsync>(sync);
};
glInt->fFunctions.fDeleteSync = [grEGLDestroySyncKHR, display = fDisplay](GrGLsync sync) {
EGLSyncKHR eglSync = reinterpret_cast<EGLSyncKHR>(sync);
grEGLDestroySyncKHR(display, eglSync);
};
glInt->fFunctions.fClientWaitSync =
[grEGLClientWaitSyncKHR, display = fDisplay] (GrGLsync sync, GrGLbitfield flags,
GrGLuint64 timeout) -> GrGLenum {
EGLSyncKHR eglSync = reinterpret_cast<EGLSyncKHR>(sync);
EGLint egl_flags = 0;
if (flags & GR_GL_SYNC_FLUSH_COMMANDS_BIT) {
egl_flags |= EGL_SYNC_FLUSH_COMMANDS_BIT_KHR;
}
EGLint result = grEGLClientWaitSyncKHR(display, eglSync, egl_flags, timeout);
switch (result) {
case EGL_CONDITION_SATISFIED_KHR:
return GR_GL_CONDITION_SATISFIED;
case EGL_TIMEOUT_EXPIRED_KHR:
return GR_GL_TIMEOUT_EXPIRED;
case EGL_FALSE:
return GR_GL_WAIT_FAILED;
}
SkUNREACHABLE;
};
glInt->fFunctions.fWaitSync =
[grEGLClientWaitSyncKHR, grEGLWaitSyncKHR, display = fDisplay](GrGLsync sync,
GrGLbitfield flags,
GrGLuint64 timeout) {
EGLSyncKHR eglSync = reinterpret_cast<EGLSyncKHR>(sync);
SkASSERT(timeout == GR_GL_TIMEOUT_IGNORED);
SkASSERT(flags == 0);
if (!grEGLWaitSyncKHR) {
grEGLClientWaitSyncKHR(display, eglSync, 0, EGL_FOREVER_KHR);
return;
}
SkDEBUGCODE(EGLint result =) grEGLWaitSyncKHR(display, eglSync, 0);
SkASSERT(result);
};
glInt->fFunctions.fIsSync =
[grEGLGetSyncAttribKHR, display = fDisplay](GrGLsync sync) -> GrGLboolean {
EGLSyncKHR eglSync = reinterpret_cast<EGLSyncKHR>(sync);
EGLint value;
if (grEGLGetSyncAttribKHR(display, eglSync, EGL_SYNC_TYPE_KHR, &value)) {
return true;
}
return false;
};
}
EGLGLTestContext::~EGLGLTestContext() {
this->teardown();
this->destroyGLContext();