From 60c18f93a1430ca7b368b9ec37bf04c919f501ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 16 Oct 2019 18:33:34 +0200 Subject: [PATCH] GL: implement time queries for WebGL 2, and workarounds, and ... There's a new firefox-fake-disjoint-timer-query-webgl2 workaround and a half-page of text listing various caveats and issues you might run into. Also exposing them in the OpenGLTester (although quite shitty at this point). --- doc/changelog.dox | 6 ++ doc/platforms-html5.dox | 22 +++++++ src/Magnum/GL/AbstractQuery.cpp | 10 +-- src/Magnum/GL/AbstractQuery.h | 9 --- src/Magnum/GL/CMakeLists.txt | 17 ++--- src/Magnum/GL/Context.cpp | 3 + src/Magnum/GL/Extensions.h | 9 ++- src/Magnum/GL/GL.h | 2 - src/Magnum/GL/Implementation/QueryState.h | 4 -- src/Magnum/GL/Implementation/State.cpp | 4 -- src/Magnum/GL/Implementation/State.h | 4 -- .../GL/Implementation/driverSpecific.cpp | 23 +++++++ src/Magnum/GL/OpenGLTester.cpp | 2 - src/Magnum/GL/OpenGLTester.h | 64 +++++++++++++------ src/Magnum/GL/Test/CMakeLists.txt | 11 ++-- src/Magnum/GL/Test/TimeQueryGLTest.cpp | 14 +++- src/Magnum/GL/TimeQuery.h | 13 +--- .../OpenGL/GLES3/Emscripten/extensions.txt | 1 + 18 files changed, 134 insertions(+), 84 deletions(-) diff --git a/doc/changelog.dox b/doc/changelog.dox index 775439413..d1cfa9187 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -194,6 +194,12 @@ See also: shell (as opposed to an APK) because using it causes the @ref GL::Renderer::Error::OutOfMemory error. See @ref opengl-workarounds for more information. +- Implemented @webgl_extension{EXT,disjoint_timer_query} and + @webgl_extension{EXT,disjoint_timer_query_webgl2} for WebGL, together with + a new @cpp "firefox-fake-disjoint-timer-query-webgl2" @ce workaround. See + @ref opengl-workarounds, @ref platforms-html5-webgl-timer-queries and + @ref platforms-html5-webgl-queries-zero for more information about various + caveats. - New `--magnum-gpu-validation` @ref GL-Context-command-line "command-line option" and a corresponding environment variable to conveniently enable @gl_extension{KHR,debug} debug output. This flag also causes diff --git a/doc/platforms-html5.dox b/doc/platforms-html5.dox index 42c6d186c..b5edf62b7 100644 --- a/doc/platforms-html5.dox +++ b/doc/platforms-html5.dox @@ -438,6 +438,28 @@ WebGL specification provide even more detail: - [Differences Between WebGL and OpenGL ES 2.0](http://www.khronos.org/registry/webgl/specs/latest/1.0/#6) - [Differences Between WebGL and OpenGL ES 3.0](https://www.khronos.org/registry/webgl/specs/latest/2.0/#5) +@subsection platforms-html5-webgl-timer-queries Timer queries not available in the browser + +Similarly to [Rowhammer](https://en.wikipedia.org/wiki/Row_hammer), GPU timer +queries could be abused to do a bit-flip attack, which is the reason why +@webgl_extension{EXT,disjoint_timer_query} / @webgl_extension{EXT,disjoint_timer_query_webgl2} might not be available in +your browser. Recent versions of Chrome [expose it again](https://bugs.chromium.org/p/chromium/issues/detail?id=823863), +and Firefox exposes it if you enable `webgl.enable-privileged-extensions` in +`about:config` ([source](https://www.khronos.org/webgl/public-mailing-list/public_webgl/1803/msg00017.php)). +[More details about the GLitch vulnerability.](https://www.vusec.net/wp-content/uploads/2018/05/glitch.pdf) + +@subsection platforms-html5-webgl-queries-zero Queries always report zero results + +Compared to OpenGL ES, WebGL [has an additional restriction](https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.12) +where it's not guaranteed for a @ref GL::PrimitiveQuery, @ref GL::SampleQuery +or @ref GL::TimeQuery to return a result in the same frame, which in practice +means that the queries will return zero. This is particularly problematic in +headless tests / benchmarks and currently there's no builtin way in Magnum to +circumvent this limitation. + +If you're on Firefox, you can enable the `webgl.allow-immediate-queries` option +in `about:flags`, which will make these working. + @section platforms-html5-code-size Compilation time / code size tradeoffs By default, the toolchain configures the compiler and linker to use `-O3` in diff --git a/src/Magnum/GL/AbstractQuery.cpp b/src/Magnum/GL/AbstractQuery.cpp index 46dd624f6..3ef51876c 100644 --- a/src/Magnum/GL/AbstractQuery.cpp +++ b/src/Magnum/GL/AbstractQuery.cpp @@ -46,10 +46,8 @@ AbstractQuery::~AbstractQuery() { #ifndef MAGNUM_TARGET_GLES2 glDeleteQueries(1, &_id); - #elif !defined(CORRADE_TARGET_EMSCRIPTEN) - glDeleteQueriesEXT(1, &_id); #else - CORRADE_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ + glDeleteQueriesEXT(1, &_id); #endif _flags |= ObjectFlag::Created; } @@ -57,10 +55,8 @@ AbstractQuery::~AbstractQuery() { void AbstractQuery::createImplementationDefault() { #ifndef MAGNUM_TARGET_GLES2 glGenQueries(1, &_id); - #elif !defined(CORRADE_TARGET_EMSCRIPTEN) - glGenQueriesEXT(1, &_id); #else - CORRADE_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ + glGenQueriesEXT(1, &_id); #endif } @@ -112,7 +108,6 @@ template<> UnsignedInt AbstractQuery::result() { template<> bool AbstractQuery::result() { return result() != 0; } -#ifndef MAGNUM_TARGET_WEBGL template<> Int AbstractQuery::result() { Int result; #ifndef MAGNUM_TARGET_GLES @@ -143,7 +138,6 @@ template<> Long AbstractQuery::result() { return result; } #endif -#endif void AbstractQuery::begin() { #ifndef MAGNUM_TARGET_GLES2 diff --git a/src/Magnum/GL/AbstractQuery.h b/src/Magnum/GL/AbstractQuery.h index e5d6c0200..2e808602c 100644 --- a/src/Magnum/GL/AbstractQuery.h +++ b/src/Magnum/GL/AbstractQuery.h @@ -25,11 +25,9 @@ DEALINGS IN THE SOFTWARE. */ -#if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) /** @file * @brief Class @ref Magnum::GL::AbstractQuery */ -#endif #include #include @@ -39,7 +37,6 @@ #include "Magnum/configure.h" -#if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) namespace Magnum { namespace GL { namespace Implementation { struct QueryState; } @@ -49,7 +46,6 @@ namespace Implementation { struct QueryState; } See @ref PrimitiveQuery, @ref SampleQuery and @ref TimeQuery documentation for more information. -@requires_webgl20 Queries are not available in WebGL 1.0. @todo `QUERY_COUNTER_BITS` (not sure since when this is supported) */ class MAGNUM_GL_EXPORT AbstractQuery: public AbstractObject { @@ -203,11 +199,9 @@ class MAGNUM_GL_EXPORT AbstractQuery: public AbstractObject { template<> bool MAGNUM_GL_EXPORT AbstractQuery::result(); template<> UnsignedInt MAGNUM_GL_EXPORT AbstractQuery::result(); template<> Int MAGNUM_GL_EXPORT AbstractQuery::result(); -#ifndef MAGNUM_TARGET_WEBGL template<> UnsignedLong MAGNUM_GL_EXPORT AbstractQuery::result(); template<> Long MAGNUM_GL_EXPORT AbstractQuery::result(); #endif -#endif inline AbstractQuery::AbstractQuery(AbstractQuery&& other) noexcept: _id(other._id), _target(other._target) { other._id = 0; @@ -227,8 +221,5 @@ inline GLuint AbstractQuery::release() { } }} -#else -#error this header is not available in WebGL 1.0 build -#endif #endif diff --git a/src/Magnum/GL/CMakeLists.txt b/src/Magnum/GL/CMakeLists.txt index fe276ae6f..1e61c5cda 100644 --- a/src/Magnum/GL/CMakeLists.txt +++ b/src/Magnum/GL/CMakeLists.txt @@ -25,6 +25,7 @@ set(MagnumGL_SRCS AbstractObject.cpp + AbstractQuery.cpp AbstractShaderProgram.cpp Attribute.cpp Buffer.cpp @@ -43,6 +44,7 @@ set(MagnumGL_SRCS Implementation/ContextState.cpp Implementation/FramebufferState.cpp Implementation/MeshState.cpp + Implementation/QueryState.cpp Implementation/RendererState.cpp Implementation/ShaderProgramState.cpp Implementation/ShaderState.cpp @@ -63,6 +65,7 @@ set(MagnumGL_GracefulAssert_SRCS set(MagnumGL_HEADERS AbstractFramebuffer.h AbstractObject.h + AbstractQuery.h AbstractShaderProgram.h AbstractTexture.h Attribute.h @@ -84,6 +87,7 @@ set(MagnumGL_HEADERS Shader.h Texture.h TextureFormat.h + TimeQuery.h Version.h visibility.h) @@ -95,6 +99,7 @@ set(MagnumGL_PRIVATE_HEADERS Implementation/FramebufferState.h Implementation/maxTextureSize.h Implementation/MeshState.h + Implementation/QueryState.h Implementation/RendererState.h Implementation/ShaderProgramState.h Implementation/ShaderState.h @@ -137,8 +142,7 @@ if(NOT TARGET_WEBGL) Implementation/DebugState.cpp) list(APPEND MagnumGL_HEADERS - DebugOutput.h - TimeQuery.h) + DebugOutput.h) list(APPEND MagnumGL_PRIVATE_HEADERS Implementation/DebugState.h) @@ -160,17 +164,8 @@ endif() # Desktop, OpenGL ES and WebGL 2.0 stuff that is not available in WebGL 1.0 if(NOT (TARGET_WEBGL AND TARGET_GLES2)) - list(APPEND MagnumGL_SRCS - AbstractQuery.cpp - - Implementation/QueryState.cpp) - list(APPEND MagnumGL_HEADERS - AbstractQuery.h SampleQuery.h) - - list(APPEND MagnumGL_PRIVATE_HEADERS - Implementation/QueryState.h) endif() # Objects shared between main and test library diff --git a/src/Magnum/GL/Context.cpp b/src/Magnum/GL/Context.cpp index 35ea111c9..cac04a3ee 100644 --- a/src/Magnum/GL/Context.cpp +++ b/src/Magnum/GL/Context.cpp @@ -247,9 +247,12 @@ constexpr Extension ExtensionList460[]{ #elif defined(MAGNUM_TARGET_WEBGL) constexpr Extension ExtensionList[]{ _extension(EXT,texture_filter_anisotropic), + #ifdef MAGNUM_TARGET_GLES2 _extension(EXT,disjoint_timer_query), + #endif #ifndef MAGNUM_TARGET_GLES2 _extension(EXT,color_buffer_float), + _extension(EXT,disjoint_timer_query_webgl2), #endif _extension(EXT,texture_compression_rgtc), _extension(EXT,texture_compression_bptc), diff --git a/src/Magnum/GL/Extensions.h b/src/Magnum/GL/Extensions.h index e47cba50f..64d59d54d 100644 --- a/src/Magnum/GL/Extensions.h +++ b/src/Magnum/GL/Extensions.h @@ -274,16 +274,21 @@ namespace ANGLE { _extension( 4,EXT,sRGB, GLES200, GLES300) // #17 _extension( 5,EXT,blend_minmax, GLES200, GLES300) // #25 #endif + #ifdef MAGNUM_TARGET_GLES2 + /* Replaced by EXT_disjoint_timer_query_webgl2 in WebGL 2 */ _extension( 6,EXT,disjoint_timer_query, GLES200, None) // #26 + #endif #ifdef MAGNUM_TARGET_GLES2 _extension( 7,EXT,shader_texture_lod, GLES200, GLES300) // #27 #endif #ifndef MAGNUM_TARGET_GLES2 /* Replaces WEBGL_color_buffer_float from WebGL 1 */ _extension( 8,EXT,color_buffer_float, GLES300, None) // #31 + /* Replaces WEBGL_disjoint_timer_query from WebGL 1 */ + _extension( 9,EXT,disjoint_timer_query_webgl2, GLES300, None) // #33 #endif - _extension( 9,EXT,texture_compression_rgtc, GLES200, None) // #38 - _extension(10,EXT,texture_compression_bptc, GLES200, None) // #39 + _extension(10,EXT,texture_compression_rgtc, GLES200, None) // #38 + _extension(11,EXT,texture_compression_bptc, GLES200, None) // #39 } namespace OES { #ifdef MAGNUM_TARGET_GLES2 _extension(15,OES,texture_float, GLES200, GLES300) // #1 diff --git a/src/Magnum/GL/GL.h b/src/Magnum/GL/GL.h index 1b19560b4..b1051b422 100644 --- a/src/Magnum/GL/GL.h +++ b/src/Magnum/GL/GL.h @@ -44,9 +44,7 @@ namespace Magnum { namespace GL { FramebufferTarget enums used only directly with framebuffer instance */ class AbstractFramebuffer; -#if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) class AbstractQuery; -#endif class AbstractShaderProgram; class AbstractTexture; diff --git a/src/Magnum/GL/Implementation/QueryState.h b/src/Magnum/GL/Implementation/QueryState.h index e794c3992..75a5c7a98 100644 --- a/src/Magnum/GL/Implementation/QueryState.h +++ b/src/Magnum/GL/Implementation/QueryState.h @@ -37,10 +37,6 @@ #include "Magnum/GL/AbstractQuery.h" #endif -#if defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2) -#error this header is not available in WebGL 1.0 build -#endif - namespace Magnum { namespace GL { namespace Implementation { struct QueryState { diff --git a/src/Magnum/GL/Implementation/State.cpp b/src/Magnum/GL/Implementation/State.cpp index 78bfd3bcd..5e45b8942 100644 --- a/src/Magnum/GL/Implementation/State.cpp +++ b/src/Magnum/GL/Implementation/State.cpp @@ -37,9 +37,7 @@ #endif #include "Magnum/GL/Implementation/FramebufferState.h" #include "Magnum/GL/Implementation/MeshState.h" -#if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) #include "Magnum/GL/Implementation/QueryState.h" -#endif #include "Magnum/GL/Implementation/RendererState.h" #include "Magnum/GL/Implementation/ShaderState.h" #include "Magnum/GL/Implementation/ShaderProgramState.h" @@ -67,9 +65,7 @@ State::State(Context& context, std::ostream* const out) { #endif framebuffer.reset(new FramebufferState{context, extensions}); mesh.reset(new MeshState{context, *this->context, extensions}); - #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) query.reset(new QueryState{context, extensions}); - #endif renderer.reset(new RendererState{context, extensions}); shader.reset(new ShaderState(context, extensions)); shaderProgram.reset(new ShaderProgramState{context, extensions}); diff --git a/src/Magnum/GL/Implementation/State.h b/src/Magnum/GL/Implementation/State.h index 240e3cbe1..149f12e40 100644 --- a/src/Magnum/GL/Implementation/State.h +++ b/src/Magnum/GL/Implementation/State.h @@ -39,9 +39,7 @@ struct DebugState; #endif struct FramebufferState; struct MeshState; -#if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) struct QueryState; -#endif struct RendererState; struct ShaderState; struct ShaderProgramState; @@ -65,9 +63,7 @@ struct State { #endif Containers::Pointer framebuffer; Containers::Pointer mesh; - #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) Containers::Pointer query; - #endif Containers::Pointer renderer; Containers::Pointer shader; Containers::Pointer shaderProgram; diff --git a/src/Magnum/GL/Implementation/driverSpecific.cpp b/src/Magnum/GL/Implementation/driverSpecific.cpp index 29c5f7043..26d315029 100644 --- a/src/Magnum/GL/Implementation/driverSpecific.cpp +++ b/src/Magnum/GL/Implementation/driverSpecific.cpp @@ -280,6 +280,19 @@ namespace { framebuffer size, otherwise it assumes it's zero-sized. */ "apitrace-zero-initial-viewport", #endif + +#if defined(MAGNUM_TARGET_WEBGL) && !defined(MAGNUM_TARGET_GLES2) +/* While the EXT_disjoint_timer_query extension should be only on WebGL 1 and + EXT_disjoint_timer_query_webgl2 only on WebGL 2, Firefox reports + EXT_disjoint_timer_query on both. The entry points work correctly however, + so this workaround makes Magnum pretend EXT_disjoint_timer_query_webgl2 is + available when it detects EXT_disjoint_timer_query on WebGL 2 builds on + Firefox. See also https://bugzilla.mozilla.org/show_bug.cgi?id=1328882, + https://www.khronos.org/webgl/public-mailing-list/public_webgl/1705/msg00015.php + and https://github.com/emscripten-core/emscripten/pull/9652 for the + Emscripten-side part of this workaround. */ +"firefox-fake-disjoint-timer-query-webgl2", +#endif /* [workarounds] */ }; } @@ -470,6 +483,16 @@ void Context::setupDriverWorkarounds() { glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); } #endif + + #if defined(MAGNUM_TARGET_WEBGL) && !defined(MAGNUM_TARGET_GLES2) + if(rendererString() == "Mozilla") { + for(const auto& extension: extensionStrings()) { + if(extension == "GL_EXT_disjoint_timer_query" && !isDriverWorkaroundDisabled("firefox-fake-disjoint-timer-query-webgl2")) { + _extensionStatus.set(Extensions::EXT::disjoint_timer_query_webgl2::Index, true); + } + } + } + #endif } }} diff --git a/src/Magnum/GL/OpenGLTester.cpp b/src/Magnum/GL/OpenGLTester.cpp index 5f703cd27..3445965e7 100644 --- a/src/Magnum/GL/OpenGLTester.cpp +++ b/src/Magnum/GL/OpenGLTester.cpp @@ -39,7 +39,6 @@ OpenGLTester::OpenGLTester(): TestSuite::Tester{TestSuite::Tester::TesterConfigu OpenGLTester::~OpenGLTester() = default; -#ifndef MAGNUM_TARGET_WEBGL void OpenGLTester::gpuTimeBenchmarkBegin() { setBenchmarkName("GPU time"); @@ -53,6 +52,5 @@ std::uint64_t OpenGLTester::gpuTimeBenchmarkEnd() { _gpuTimeQuery.end(); return _gpuTimeQuery.result(); } -#endif }} diff --git a/src/Magnum/GL/OpenGLTester.h b/src/Magnum/GL/OpenGLTester.h index 68649d1ef..3f9de5941 100644 --- a/src/Magnum/GL/OpenGLTester.h +++ b/src/Magnum/GL/OpenGLTester.h @@ -35,6 +35,7 @@ #include #include "Magnum/GL/Renderer.h" +#include "Magnum/GL/TimeQuery.h" #if defined(MAGNUM_TARGET_HEADLESS) || defined(CORRADE_TARGET_EMSCRIPTEN) || defined(CORRADE_TARGET_ANDROID) #include "Magnum/Platform/WindowlessEglApplication.h" @@ -58,10 +59,6 @@ #error cannot run OpenGL tests on this platform #endif -#ifndef MAGNUM_TARGET_WEBGL -#include "Magnum/GL/TimeQuery.h" -#endif - namespace Magnum { namespace GL { /** @@ -134,7 +131,12 @@ which is supported here as well as in all other application implementations. This class adds @ref BenchmarkType::GpuTime to the benchmark type enum, allowing you to measure time spent on GPU as opposed to CPU or wall clock time. -@requires_gles GPU time benchmarking is not available on WebGL. +If @gl_extension{ARB,timer_query} desktop extension (part of OpenGL 3.3), +@gl_extension{EXT,disjoint_timer_query} OpenGL ES extension, +@webgl_extension{EXT,disjoint_timer_query} WebGL 1 extension or +@gl_extension{EXT,disjoint_timer_query_webgl2} WebGL 2 extension is not +available, GPU time benchmarks will get automatically skipped, producing a +@cb{.ansi} SKIP @ce message on the output. @note This class is available only if Magnum is compiled with @ref MAGNUM_TARGET_GL enabled (done by default). See @ref building-features @@ -142,7 +144,6 @@ allowing you to measure time spent on GPU as opposed to CPU or wall clock time. */ class OpenGLTester: public TestSuite::Tester { public: - #ifndef MAGNUM_TARGET_WEBGL /** * @brief Benchmark type * @@ -178,14 +179,19 @@ class OpenGLTester: public TestSuite::Tester { /** * GPU time, measured using @ref TimeQuery::Target::TimeElapsed. * Note that the result of the query is retrieved synchronously and - * thus may cause pipeline bubble. Increase number of iterations + * thus may cause a pipeline bubble. Increase number of iterations * passed to @ref CORRADE_BENCHMARK() to amortize the measurement * error. - * @requires_gles GPU time benchmarking is not available on WebGL. + * + * If @gl_extension{ARB,timer_query} desktop extension (part of + * OpenGL 3.3), @gl_extension{EXT,disjoint_timer_query} OpenGL ES + * extension, @webgl_extension{EXT,disjoint_timer_query} WebGL 1 + * extension or @gl_extension{EXT,disjoint_timer_query_webgl2} + * WebGL 2 extension is not available, GPU time benchmarks will get + * automatically skipped. */ GpuTime = 32 }; - #endif /** * @brief Constructor @@ -196,13 +202,18 @@ class OpenGLTester: public TestSuite::Tester { ~OpenGLTester(); - #ifndef MAGNUM_TARGET_WEBGL /** * @brief Add benchmarks * * Extends @ref Corrade::TestSuite::Tester::addBenchmarks(std::initializer_list, std::size_t, BenchmarkType) with support * for GPU benchmark types. - * @requires_gles GPU time benchmarking is not available on WebGL. + * + * If @gl_extension{ARB,timer_query} desktop extension (part of OpenGL + * 3.3), @gl_extension{EXT,disjoint_timer_query} OpenGL ES extension, + * @webgl_extension{EXT,disjoint_timer_query} WebGL 1 extension or + * @gl_extension{EXT,disjoint_timer_query_webgl2} WebGL 2 extension is + * not available, @ref BenchmarkType::GpuTime benchmarks will get + * automatically skipped. */ template void addBenchmarks(std::initializer_list benchmarks, std::size_t batchCount, BenchmarkType benchmarkType = BenchmarkType::Default) { if(benchmarkType == BenchmarkType::GpuTime) @@ -216,7 +227,13 @@ class OpenGLTester: public TestSuite::Tester { * * Extends @ref Corrade::TestSuite::Tester::addBenchmarks(std::initializer_list, std::size_t, void(Derived::*)(), void(Derived::*)(), BenchmarkType) with support * for GPU benchmark types. - * @requires_gles GPU time benchmarking is not available on WebGL. + * + * If @gl_extension{ARB,timer_query} desktop extension (part of OpenGL + * 3.3), @gl_extension{EXT,disjoint_timer_query} OpenGL ES extension, + * @webgl_extension{EXT,disjoint_timer_query} WebGL 1 extension or + * @gl_extension{EXT,disjoint_timer_query_webgl2} WebGL 2 extension is + * not available, @ref BenchmarkType::GpuTime benchmarks will get + * automatically skipped. */ template void addBenchmarks(std::initializer_list benchmarks, std::size_t batchCount, void(Derived::*setup)(), void(Derived::*teardown)(), BenchmarkType benchmarkType = BenchmarkType::Default) { if(benchmarkType == BenchmarkType::GpuTime) @@ -230,7 +247,13 @@ class OpenGLTester: public TestSuite::Tester { * * Extends @ref Corrade::TestSuite::Tester::addInstancedBenchmarks(std::initializer_list, std::size_t, std::size_t, BenchmarkType) with support for GPU * benchmark types. - * @requires_gles GPU time benchmarking is not available on WebGL. + * + * If @gl_extension{ARB,timer_query} desktop extension (part of OpenGL + * 3.3), @gl_extension{EXT,disjoint_timer_query} OpenGL ES extension, + * @webgl_extension{EXT,disjoint_timer_query} WebGL 1 extension or + * @gl_extension{EXT,disjoint_timer_query_webgl2} WebGL 2 extension is + * not available, @ref BenchmarkType::GpuTime benchmarks will get + * automatically skipped. */ template void addInstancedBenchmarks(std::initializer_list benchmarks, std::size_t batchCount, std::size_t instanceCount, BenchmarkType benchmarkType = BenchmarkType::Default) { if(benchmarkType == BenchmarkType::GpuTime) @@ -244,30 +267,31 @@ class OpenGLTester: public TestSuite::Tester { * * Extends @ref Corrade::TestSuite::Tester::addInstancedBenchmarks(std::initializer_list, std::size_t, std::size_t, void(Derived::*)(), void(Derived::*)(), BenchmarkType) * with support for GPU benchmark types. - * @requires_gles GPU time benchmarking is not available on WebGL. + * + * If @gl_extension{ARB,timer_query} desktop extension (part of OpenGL + * 3.3), @gl_extension{EXT,disjoint_timer_query} OpenGL ES extension, + * @webgl_extension{EXT,disjoint_timer_query} WebGL 1 extension or + * @gl_extension{EXT,disjoint_timer_query_webgl2} WebGL 2 extension is + * not available, @ref BenchmarkType::GpuTime benchmarks will get + * automatically skipped. */ template void addInstancedBenchmarks(std::initializer_list benchmarks, std::size_t batchCount, std::size_t instanceCount, void(Derived::*setup)(), void(Derived::*teardown)(), BenchmarkType benchmarkType = BenchmarkType::Default) { if(benchmarkType == BenchmarkType::GpuTime) - addCustomInstancedBenchmarks(benchmarks, batchCount, instanceCount, &OpenGLTester::gpuTimeBenchmarkBegin, &OpenGLTester::gpuTimeBenchmarkEnd, setup, teardown, BenchmarkUnits::Nanoseconds); + addCustomInstancedBenchmarks(benchmarks, batchCount, instanceCount, setup, teardown, &OpenGLTester::gpuTimeBenchmarkBegin, &OpenGLTester::gpuTimeBenchmarkEnd, BenchmarkUnits::Nanoseconds); else Tester::addInstancedBenchmarks(benchmarks, batchCount, instanceCount, setup, teardown, Tester::BenchmarkType(Int(benchmarkType))); } - #endif private: - #ifndef MAGNUM_TARGET_WEBGL void gpuTimeBenchmarkBegin(); std::uint64_t gpuTimeBenchmarkEnd(); - #endif struct WindowlessApplication: Platform::WindowlessApplication { explicit WindowlessApplication(const Arguments& arguments): Platform::WindowlessApplication{arguments} {} int exec() override final { return 0; } } _windowlessApplication; - #ifndef MAGNUM_TARGET_WEBGL TimeQuery _gpuTimeQuery{NoCreate}; - #endif }; /** @hideinitializer diff --git a/src/Magnum/GL/Test/CMakeLists.txt b/src/Magnum/GL/Test/CMakeLists.txt index 803a6b9dc..4a620cec2 100644 --- a/src/Magnum/GL/Test/CMakeLists.txt +++ b/src/Magnum/GL/Test/CMakeLists.txt @@ -37,6 +37,7 @@ corrade_add_test(GLRenderbufferTest RenderbufferTest.cpp LIBRARIES MagnumGL) corrade_add_test(GLSamplerTest SamplerTest.cpp LIBRARIES MagnumGLTestLib) corrade_add_test(GLShaderTest ShaderTest.cpp LIBRARIES MagnumGL) corrade_add_test(GLTextureTest TextureTest.cpp LIBRARIES MagnumGL) +corrade_add_test(GLTimeQueryTest TimeQueryTest.cpp LIBRARIES MagnumGL) corrade_add_test(GLVersionTest VersionTest.cpp LIBRARIES MagnumGL) set_target_properties( @@ -54,6 +55,7 @@ set_target_properties( GLSamplerTest GLShaderTest GLTextureTest + GLTimeQueryTest GLVersionTest PROPERTIES FOLDER "Magnum/GL/Test") @@ -93,11 +95,6 @@ if(NOT (MAGNUM_TARGET_WEBGL AND MAGNUM_TARGET_GLES2)) set_target_properties(GLSampleQueryTest PROPERTIES FOLDER "Magnum/GL/Test") endif() -if(NOT MAGNUM_TARGET_WEBGL) - corrade_add_test(GLTimeQueryTest TimeQueryTest.cpp LIBRARIES MagnumGL) - set_target_properties(GLTimeQueryTest PROPERTIES FOLDER "Magnum/GL/Test") -endif() - if(NOT MAGNUM_TARGET_GLES) corrade_add_test(GLRectangleTextureTest RectangleTextureTest.cpp LIBRARIES MagnumGL) set_target_properties(GLRectangleTextureTest PROPERTIES FOLDER "Magnum/GL/Test") @@ -112,6 +109,7 @@ if(BUILD_GL_TESTS) corrade_add_test(GLRendererGLTest RendererGLTest.cpp LIBRARIES MagnumOpenGLTester) corrade_add_test(GLRenderbufferGLTest RenderbufferGLTest.cpp LIBRARIES MagnumOpenGLTester) corrade_add_test(GLTextureGLTest TextureGLTest.cpp LIBRARIES MagnumOpenGLTesterTestLib) + corrade_add_test(GLTimeQueryGLTest TimeQueryGLTest.cpp LIBRARIES MagnumOpenGLTester) corrade_add_resource(GLAbstractShaderProgramGLTest_RES AbstractShaderProgramGLTestFiles/resources.conf) corrade_add_test(GLAbstractShaderProgramGLTest @@ -147,6 +145,7 @@ if(BUILD_GL_TESTS) GLMeshGLTest GLRenderbufferGLTest GLTextureGLTest + GLTimeQueryGLTest GLAbstractShaderProgramGLTest GLAbstractShaderProgramGLTest_RES-dependencies @@ -157,12 +156,10 @@ if(BUILD_GL_TESTS) if(NOT MAGNUM_TARGET_WEBGL) corrade_add_test(GLAbstractObjectGLTest AbstractObjectGLTest.cpp LIBRARIES MagnumOpenGLTester) corrade_add_test(GLDebugOutputGLTest DebugOutputGLTest.cpp LIBRARIES MagnumOpenGLTester) - corrade_add_test(GLTimeQueryGLTest TimeQueryGLTest.cpp LIBRARIES MagnumOpenGLTester) set_target_properties( GLAbstractObjectGLTest GLDebugOutputGLTest - GLTimeQueryGLTest PROPERTIES FOLDER "Magnum/GL/Test") endif() diff --git a/src/Magnum/GL/Test/TimeQueryGLTest.cpp b/src/Magnum/GL/Test/TimeQueryGLTest.cpp index 1c353801b..e6efcb9b1 100644 --- a/src/Magnum/GL/Test/TimeQueryGLTest.cpp +++ b/src/Magnum/GL/Test/TimeQueryGLTest.cpp @@ -52,6 +52,9 @@ void TimeQueryGLTest::wrap() { #ifndef MAGNUM_TARGET_GLES if(!Context::current().isExtensionSupported()) CORRADE_SKIP(Extensions::ARB::timer_query::string() + std::string(" is not available")); + #elif defined(MAGNUM_TARGET_WEBGL) && !defined(MAGNUM_TARGET_GLES2) + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::EXT::disjoint_timer_query_webgl2::string() + std::string(" is not available")); #else if(!Context::current().isExtensionSupported()) CORRADE_SKIP(Extensions::EXT::disjoint_timer_query::string() + std::string(" is not available")); @@ -83,6 +86,9 @@ void TimeQueryGLTest::queryTime() { #ifndef MAGNUM_TARGET_GLES if(!Context::current().isExtensionSupported()) CORRADE_SKIP(Extensions::ARB::timer_query::string() + std::string(" is not available")); + #elif defined(MAGNUM_TARGET_WEBGL) && !defined(MAGNUM_TARGET_GLES2) + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::EXT::disjoint_timer_query_webgl2::string() + std::string(" is not available")); #else if(!Context::current().isExtensionSupported()) CORRADE_SKIP(Extensions::EXT::disjoint_timer_query::string() + std::string(" is not available")); @@ -107,7 +113,13 @@ void TimeQueryGLTest::queryTime() { } void TimeQueryGLTest::queryTimestamp() { - #ifdef MAGNUM_TARGET_GLES + #ifndef MAGNUM_TARGET_GLES + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::ARB::timer_query::string() + std::string(" is not available")); + #elif defined(MAGNUM_TARGET_WEBGL) && !defined(MAGNUM_TARGET_GLES2) + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::EXT::disjoint_timer_query_webgl2::string() + std::string(" is not available")); + #else if(!Context::current().isExtensionSupported()) CORRADE_SKIP(Extensions::EXT::disjoint_timer_query::string() + std::string(" is not available")); #endif diff --git a/src/Magnum/GL/TimeQuery.h b/src/Magnum/GL/TimeQuery.h index 60f8e46ba..483cea675 100644 --- a/src/Magnum/GL/TimeQuery.h +++ b/src/Magnum/GL/TimeQuery.h @@ -25,15 +25,12 @@ DEALINGS IN THE SOFTWARE. */ -#ifndef MAGNUM_TARGET_WEBGL /** @file * @brief Class @ref Magnum::GL::TimeQuery */ -#endif #include "Magnum/GL/AbstractQuery.h" -#ifndef MAGNUM_TARGET_WEBGL namespace Magnum { namespace GL { /** @@ -52,7 +49,8 @@ times are reported in nanoseconds. @requires_gl33 Extension @gl_extension{ARB,timer_query} @requires_es_extension Extension @gl_extension{EXT,disjoint_timer_query} -@requires_gles Time query is not available in WebGL. +@requires_webgl_extension Extension @webgl_extension{EXT,disjoint_timer_query} + on WebGL 1, @gl_extension{EXT,disjoint_timer_query_webgl2} on WebGL 2 @see @ref PrimitiveQuery, @ref SampleQuery @todo timestamp with glGet + example usage @@ -163,10 +161,8 @@ class TimeQuery: public AbstractQuery { void timestamp() { #ifndef MAGNUM_TARGET_GLES glQueryCounter(id(), GL_TIMESTAMP); - #elif !defined(CORRADE_TARGET_EMSCRIPTEN) - glQueryCounterEXT(id(), GL_TIMESTAMP_EXT); #else - CORRADE_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ + glQueryCounterEXT(id(), GL_TIMESTAMP_EXT); #endif } @@ -175,8 +171,5 @@ class TimeQuery: public AbstractQuery { }; }} -#else -#error this header is not available in WebGL build -#endif #endif diff --git a/src/MagnumExternal/OpenGL/GLES3/Emscripten/extensions.txt b/src/MagnumExternal/OpenGL/GLES3/Emscripten/extensions.txt index a33c26d8a..d5bbec529 100644 --- a/src/MagnumExternal/OpenGL/GLES3/Emscripten/extensions.txt +++ b/src/MagnumExternal/OpenGL/GLES3/Emscripten/extensions.txt @@ -5,6 +5,7 @@ version 3.0 es extension EXT_texture_filter_anisotropic optional +# It's actually EXT_disjoint_timer_query_webgl2, but that's not known to gl.xml extension EXT_disjoint_timer_query optional extension EXT_color_buffer_float optional extension EXT_texture_compression_rgtc optional