From e8a7d9f0c29b26dd028306d27e4e6d44dd25b1fa Mon Sep 17 00:00:00 2001 From: Pixelflinger Date: Fri, 27 Mar 2020 18:16:15 -0700 Subject: [PATCH] add support for timer queries in the backends This adds a simple query API to the backend. There are 2 methods to create/destroy queries, which are essentially futures. And 3 methods to mesure elapsed time: beginTimerQuery/endTimerQuery and getTimerQueryValue. The begin/end pair is not nestable. On the GL backend side, there are 2 implementations of this, one uses arb_timer_query or disjoint_timer_query, the other uses fences. We need both implementations because on some GPUs, including qualcomm's elapsed-time timer query is useless, as it measures cpu time. Metal/Vulkan implementations will be part of subsequent PRs. Vulkan will be able to implement this with vkWriteTimestamp which is reported to be accurate. An immediate benefit is that we can now get frame times on MacOS, which should allow it to use dynamic-resolution. --- filament/backend/CMakeLists.txt | 2 + filament/backend/include/backend/Handle.h | 2 + .../include/private/backend/DriverAPI.inc | 12 ++ filament/backend/src/DriverBase.h | 3 + filament/backend/src/metal/MetalDriver.mm | 21 +- filament/backend/src/noop/NoopDriver.cpp | 13 ++ filament/backend/src/opengl/OpenGLContext.cpp | 3 + filament/backend/src/opengl/OpenGLContext.h | 45 +++++ filament/backend/src/opengl/OpenGLDriver.cpp | 107 +++++++++- filament/backend/src/opengl/OpenGLDriver.h | 25 ++- filament/backend/src/opengl/TimerQuery.cpp | 164 +++++++++++++++ filament/backend/src/opengl/TimerQuery.h | 100 ++++++++++ filament/backend/src/opengl/gl_headers.cpp | 8 + filament/backend/src/opengl/gl_headers.h | 5 + filament/backend/src/vulkan/VulkanDriver.cpp | 21 ++ filament/src/FrameInfo.cpp | 150 ++------------ filament/src/FrameInfo.h | 187 ++---------------- filament/src/Renderer.cpp | 35 +--- filament/src/details/Renderer.h | 5 - 19 files changed, 570 insertions(+), 338 deletions(-) create mode 100644 filament/backend/src/opengl/TimerQuery.cpp create mode 100644 filament/backend/src/opengl/TimerQuery.h diff --git a/filament/backend/CMakeLists.txt b/filament/backend/CMakeLists.txt index 3ede8ac097..d48a646df4 100644 --- a/filament/backend/CMakeLists.txt +++ b/filament/backend/CMakeLists.txt @@ -70,6 +70,8 @@ if (NOT FILAMENT_USE_EXTERNAL_GLES3) src/opengl/OpenGLProgram.cpp src/opengl/OpenGLProgram.h src/opengl/OpenGLPlatform.cpp + src/opengl/TimerQuery.cpp + src/opengl/TimerQuery.h include/private/backend/OpenGLPlatform.h ) if (EGL) diff --git a/filament/backend/include/backend/Handle.h b/filament/backend/include/backend/Handle.h index 279dc4340e..9616fdd382 100644 --- a/filament/backend/include/backend/Handle.h +++ b/filament/backend/include/backend/Handle.h @@ -36,6 +36,7 @@ struct HwTexture; struct HwUniformBuffer; struct HwSwapChain; struct HwStream; +struct HwTimerQuery; /* * A type handle to a h/w resource @@ -110,6 +111,7 @@ using SwapChainHandle = Handle; using TextureHandle = Handle; using UniformBufferHandle = Handle; using VertexBufferHandle = Handle; +using TimerQueryHandle = Handle; } // namespace backend } // namespace filament diff --git a/filament/backend/include/private/backend/DriverAPI.inc b/filament/backend/include/private/backend/DriverAPI.inc index d33f501a39..637929ff4d 100644 --- a/filament/backend/include/private/backend/DriverAPI.inc +++ b/filament/backend/include/private/backend/DriverAPI.inc @@ -219,6 +219,9 @@ DECL_DRIVER_API_R_N(backend::StreamHandle, createStreamFromTextureId, uint32_t, width, uint32_t, height) +DECL_DRIVER_API_R_0(backend::TimerQueryHandle, createTimerQuery) + + /* * Destroying driver objects * ------------------------- @@ -234,6 +237,7 @@ DECL_DRIVER_API_N(destroyTexture, backend::TextureHandle, th) DECL_DRIVER_API_N(destroyRenderTarget, backend::RenderTargetHandle, rth) DECL_DRIVER_API_N(destroySwapChain, backend::SwapChainHandle, sch) DECL_DRIVER_API_N(destroyStream, backend::StreamHandle, sh) +DECL_DRIVER_API_N(destroyTimerQuery, backend::TimerQueryHandle, sh) /* * Synchronous APIs @@ -256,6 +260,7 @@ DECL_DRIVER_API_SYNCHRONOUS_0(bool, isFrameTimeSupported) DECL_DRIVER_API_SYNCHRONOUS_0(bool, canGenerateMipmaps) DECL_DRIVER_API_SYNCHRONOUS_N(void, setupExternalImage, void*, image) DECL_DRIVER_API_SYNCHRONOUS_N(void, cancelExternalImage, void*, image) +DECL_DRIVER_API_SYNCHRONOUS_N(bool, getTimerQueryValue, backend::TimerQueryHandle, query, uint64_t*, elapsedTime) /* * Updating driver objects @@ -332,6 +337,13 @@ DECL_DRIVER_API_N(setRenderPrimitiveRange, uint32_t, maxIndex, uint32_t, count) +DECL_DRIVER_API_N(beginTimerQuery, + backend::TimerQueryHandle, query) + +DECL_DRIVER_API_N(endTimerQuery, + backend::TimerQueryHandle, query) + + /* * Swap chain */ diff --git a/filament/backend/src/DriverBase.h b/filament/backend/src/DriverBase.h index 2728e6b2e9..3594b71acc 100644 --- a/filament/backend/src/DriverBase.h +++ b/filament/backend/src/DriverBase.h @@ -141,6 +141,9 @@ struct HwStream : public HwBase { uint32_t height = 0; }; +struct HwTimerQuery : public HwBase { +}; + /* * Base class of all Driver implementations */ diff --git a/filament/backend/src/metal/MetalDriver.mm b/filament/backend/src/metal/MetalDriver.mm index 40b8418983..8b94753d8e 100644 --- a/filament/backend/src/metal/MetalDriver.mm +++ b/filament/backend/src/metal/MetalDriver.mm @@ -245,9 +245,12 @@ void MetalDriver::createSwapChainHeadlessR(Handle sch, void MetalDriver::createStreamFromTextureIdR(Handle, intptr_t externalTextureId, uint32_t width, uint32_t height) { - } +void MetalDriver::createTimerQueryR(Handle tqh, int) { +} + + Handle MetalDriver::createVertexBufferS() noexcept { return alloc_handle(); } @@ -304,6 +307,10 @@ Handle MetalDriver::createStreamFromTextureIdS() noexcept { return {}; } +Handle MetalDriver::createTimerQueryS() noexcept { + return {}; +} + void MetalDriver::destroyVertexBuffer(Handle vbh) { if (vbh) { destruct_handle(mHandleMap, vbh); @@ -390,6 +397,9 @@ void MetalDriver::destroyStream(Handle sh) { // no-op } +void MetalDriver::destroyTimerQuery(Handle tqh) { +} + void MetalDriver::terminate() { // Wait for all frames to finish by submitting and waiting on a dummy command buffer. // This must be done before calling bufferPool->reset() to ensure no buffers are in flight. @@ -568,7 +578,10 @@ void MetalDriver::setExternalImagePlane(Handle th, void* image, size_ } void MetalDriver::setExternalStream(Handle th, Handle sh) { +} +bool MetalDriver::getTimerQueryValue(Handle tqh, uint64_t* elapsedTime) { + return false; } void MetalDriver::generateMipmaps(Handle th) { @@ -1041,6 +1054,12 @@ void MetalDriver::draw(backend::PipelineState ps, Handle rph) indexBufferOffset:primitive->offset]; } +void MetalDriver::beginTimerQuery(Handle tqh) { +} + +void MetalDriver::endTimerQuery(Handle tqh) { +} + void MetalDriver::enumerateSamplerGroups( const MetalProgram* program, const std::function& f) { diff --git a/filament/backend/src/noop/NoopDriver.cpp b/filament/backend/src/noop/NoopDriver.cpp index 20ef782c46..531b9447fd 100644 --- a/filament/backend/src/noop/NoopDriver.cpp +++ b/filament/backend/src/noop/NoopDriver.cpp @@ -91,6 +91,9 @@ void NoopDriver::destroySwapChain(Handle sch) { void NoopDriver::destroyStream(Handle sh) { } +void NoopDriver::destroyTimerQuery(Handle tqh) { +} + Handle NoopDriver::createStreamNative(void* nativeStream) { return {}; } @@ -165,6 +168,10 @@ void NoopDriver::setupExternalImage(void* image) { void NoopDriver::cancelExternalImage(void* image) { } +bool NoopDriver::getTimerQueryValue(Handle tqh, uint64_t* elapsedTime) { + return false; +} + void NoopDriver::setExternalImage(Handle th, void* image) { } @@ -255,4 +262,10 @@ void NoopDriver::blit(TargetBufferFlags buffers, void NoopDriver::draw(PipelineState pipelineState, Handle rph) { } +void NoopDriver::beginTimerQuery(Handle tqh) { +} + +void NoopDriver::endTimerQuery(Handle tqh) { +} + } // namespace filament diff --git a/filament/backend/src/opengl/OpenGLContext.cpp b/filament/backend/src/opengl/OpenGLContext.cpp index 4e3b35db06..4c8c2f2d62 100644 --- a/filament/backend/src/opengl/OpenGLContext.cpp +++ b/filament/backend/src/opengl/OpenGLContext.cpp @@ -56,7 +56,9 @@ OpenGLContext::OpenGLContext() noexcept { #endif if (strstr(renderer, "Adreno")) { + bugs.dont_use_timer_query = true; // verified } else if (strstr(renderer, "Mali")) { + bugs.dont_use_timer_query = true; // not verified bugs.vao_doesnt_store_element_array_buffer_binding = true; if (strstr(renderer, "Mali-T")) { bugs.disable_glFlush = true; @@ -213,6 +215,7 @@ void OpenGLContext::initExtensionsGLES(GLint major, GLint minor, ExtentionSet co ext.APPLE_color_buffer_packed_float = hasExtension(exts, "GL_APPLE_color_buffer_packed_float"); ext.texture_compression_s3tc = hasExtension(exts, "WEBGL_compressed_texture_s3tc"); ext.EXT_multisampled_render_to_texture = hasExtension(exts, "GL_EXT_multisampled_render_to_texture"); + ext.EXT_disjoint_timer_query = hasExtension(exts, "GL_EXT_disjoint_timer_query"); ext.KHR_debug = hasExtension(exts, "GL_KHR_debug"); ext.EXT_texture_compression_s3tc_srgb = hasExtension(exts, "GL_EXT_texture_compression_s3tc_srgb"); // ES 3.2 implies EXT_color_buffer_float diff --git a/filament/backend/src/opengl/OpenGLContext.h b/filament/backend/src/opengl/OpenGLContext.h index 6820520843..0e403a1b46 100644 --- a/filament/backend/src/opengl/OpenGLContext.h +++ b/filament/backend/src/opengl/OpenGLContext.h @@ -85,6 +85,9 @@ public: inline void depthMask(GLboolean flag) noexcept; inline void depthFunc(GLenum func) noexcept; inline void polygonOffset(GLfloat factor, GLfloat units) noexcept; + inline void beginQuery(GLenum target, GLuint query) noexcept; + inline void endQuery(GLenum target) noexcept; + inline GLuint getQuery(GLenum target) noexcept; inline void setScissor(GLint left, GLint bottom, GLsizei width, GLsizei height) noexcept; inline void viewport(GLint left, GLint bottom, GLsizei width, GLsizei height) noexcept; @@ -120,6 +123,7 @@ public: bool KHR_debug = false; bool EXT_texture_sRGB = false; bool EXT_texture_compression_s3tc_srgb = false; + bool EXT_disjoint_timer_query = false; } ext; struct { @@ -145,6 +149,9 @@ public: // Some drivers declare GL_EXT_texture_filter_anisotropic but don't support // calling glSamplerParameter() with GL_TEXTURE_MAX_ANISOTROPY_EXT bool disable_texture_filter_anisotropic = false; + + // Some drivers don't implement timer queries correctly + bool dont_use_timer_query = false; } bugs; // state getters -- as needed. @@ -239,6 +246,10 @@ private: vec4gli scissor { 0 }; vec4gli viewport { 0 }; } window; + + struct { + GLuint timer = -1u; + } queries; } state; RenderPrimitive mDefaultVAO; @@ -524,6 +535,40 @@ void OpenGLContext::polygonOffset(GLfloat factor, GLfloat units) noexcept { }); } +void OpenGLContext::beginQuery(GLenum target, GLuint query) noexcept { + switch (target) { + case GL_TIME_ELAPSED: + if (state.queries.timer != -1u) { + // this is an error + break; + } + state.queries.timer = query; + break; + default: + return; + } + glBeginQuery(target, query); +} + +void OpenGLContext::endQuery(GLenum target) noexcept { + switch (target) { + case GL_TIME_ELAPSED: + state.queries.timer = -1u; + break; + default: + return; + } + glEndQuery(target); +} + +GLuint OpenGLContext::getQuery(GLenum target) noexcept { + switch (target) { + case GL_TIME_ELAPSED: + return state.queries.timer; + default: + return 0; + } +} } // namesapce filament #endif //TNT_FILAMENT_BACKEND_OPENGLCONTEXT_H diff --git a/filament/backend/src/opengl/OpenGLDriver.cpp b/filament/backend/src/opengl/OpenGLDriver.cpp index 09bf7a62c3..e2c4eb68f9 100644 --- a/filament/backend/src/opengl/OpenGLDriver.cpp +++ b/filament/backend/src/opengl/OpenGLDriver.cpp @@ -23,6 +23,8 @@ #include "OpenGLBlitter.h" #include "OpenGLDriverFactory.h" #include "OpenGLProgram.h" +#include "TimerQuery.h" +#include "OpenGLContext.h" #include #include @@ -74,6 +76,8 @@ Driver* OpenGLDriverFactory::create( using namespace backend; using namespace GLUtils; +// ------------------------------------------------------------------------------------------------ + UTILS_NOINLINE Driver* OpenGLDriver::create( OpenGLPlatform* const platform, void* const sharedGLContext) noexcept { @@ -148,6 +152,25 @@ OpenGLDriver::OpenGLDriver(OpenGLPlatform* platform) noexcept mOpenGLBlitter->init(); mContext.resetProgram(); } + + if (mContext.ext.EXT_disjoint_timer_query || GL41_HEADERS) { + // timer queries are available + if (mContext.bugs.dont_use_timer_query && mPlatform.canCreateFence()) { + // however, they don't work well, revert to using fences if we can. + mTimerQueryImpl = new TimerQueryFence(mPlatform); + } else { + mTimerQueryImpl = new TimerQueryNative(mContext); + } + mFrameTimeSupported = true; + } else if (mPlatform.canCreateFence()) { + // no timer queries, but we can use fences + mTimerQueryImpl = new TimerQueryFence(mPlatform); + mFrameTimeSupported = true; + } else { + // no queries, no fences -- that's a problem + mTimerQueryImpl = new TimerQueryFallback(); + mFrameTimeSupported = false; + } } OpenGLDriver::~OpenGLDriver() noexcept { @@ -176,6 +199,9 @@ void OpenGLDriver::terminate() { if (mOpenGLBlitter) { mOpenGLBlitter->terminate(); } + + delete mTimerQueryImpl; + mPlatform.terminate(); } @@ -418,6 +444,10 @@ Handle OpenGLDriver::createStreamFromTextureIdS() noexcept { return Handle( allocateHandle(sizeof(GLStream)) ); } +Handle OpenGLDriver::createTimerQueryS() noexcept { + return Handle( allocateHandle(sizeof(GLTimerQuery)) ); +} + void OpenGLDriver::createVertexBufferR( Handle vbh, uint8_t bufferCount, @@ -1002,6 +1032,14 @@ void OpenGLDriver::createStreamFromTextureIdR(Handle sh, } } +void OpenGLDriver::createTimerQueryR(Handle tqh, int) { + DEBUG_MARKER() + + GLTimerQuery* tq = construct(tqh); + glGenQueries(1u, &tq->gl.query); + CHECK_GL_ERROR(utils::slog.e) +} + // ------------------------------------------------------------------------------------------------ // Destroying driver objects // ------------------------------------------------------------------------------------------------ @@ -1159,6 +1197,16 @@ void OpenGLDriver::destroyStream(Handle sh) { } } +void OpenGLDriver::destroyTimerQuery(Handle tqh) { + DEBUG_MARKER() + + if (tqh) { + GLTimerQuery* tq = handle_cast(tqh); + glDeleteQueries(1u, &tq->gl.query); + destruct(tqh, tq); + } +} + // ------------------------------------------------------------------------------------------------ // Synchronous APIs // These are called on the application's thread @@ -1350,8 +1398,7 @@ bool OpenGLDriver::isRenderTargetFormatSupported(TextureFormat format) { } bool OpenGLDriver::isFrameTimeSupported() { - // TODO: Measuring the frame time is currently only done using fences - return mPlatform.canCreateFence(); + return mFrameTimeSupported; } // ------------------------------------------------------------------------------------------------ @@ -1857,6 +1904,39 @@ void OpenGLDriver::replaceStream(GLTexture* texture, GLStream* newStream) noexce texture->hwStream = newStream; } +void OpenGLDriver::beginTimerQuery(Handle tqh) { + GLTimerQuery* tq = handle_cast(tqh); + // reset the state of the result availability + tq->elapsed.store(0, std::memory_order_relaxed); + mTimerQueryImpl->beginTimeElapsedQuery(tq); +} + +void OpenGLDriver::endTimerQuery(Handle tqh) { + GLTimerQuery* tq = handle_cast(tqh); + mTimerQueryImpl->endTimeElapsedQuery(tq); + + whenFrameBegins([this, tq]() -> bool { + if (!mTimerQueryImpl->queryResultAvailable(tq)) { + // we need to try this one again later + return false; + } + tq->elapsed.store(mTimerQueryImpl->queryResult(tq), std::memory_order_relaxed); + return true; + }); +} + +bool OpenGLDriver::getTimerQueryValue(Handle tqh, uint64_t* elapsedTime) { + GLTimerQuery* tq = handle_cast(tqh); + uint64_t d = tq->elapsed.load(std::memory_order_relaxed); + if (!d) { + return false; + } + if (elapsedTime) { + *elapsedTime = d; + } + return true; +} + void OpenGLDriver::beginRenderPass(Handle rth, const RenderPassParams& params) { DEBUG_MARKER() @@ -2504,12 +2584,16 @@ void OpenGLDriver::readPixels(Handle src, CHECK_GL_ERROR(utils::slog.e) } -void OpenGLDriver::whenGpuCommandsComplete(std::function fn) noexcept { +void OpenGLDriver::whenGpuCommandsComplete(std::function fn) noexcept { GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); mGpuCommandCompleteOps.emplace_back(sync, std::move(fn)); CHECK_GL_ERROR(utils::slog.e) } +void OpenGLDriver::whenFrameBegins(std::function fn) noexcept { + mFrameBeginsOps.push_back(std::move(fn)); +} + void OpenGLDriver::executeGpuCommandsCompleteOps() noexcept { auto& v = mGpuCommandCompleteOps; auto it = v.begin(); @@ -2530,6 +2614,18 @@ void OpenGLDriver::executeGpuCommandsCompleteOps() noexcept { } } +void OpenGLDriver::executeFrameBeginsOps() noexcept { + auto& v = mFrameBeginsOps; + auto it = v.begin(); + while (it != v.end()) { + if ((*it)()) { + it = v.erase(it); + } else { + ++it; + } + } +} + // ------------------------------------------------------------------------------------------------ // Rendering ops // ------------------------------------------------------------------------------------------------ @@ -2539,6 +2635,7 @@ void OpenGLDriver::beginFrame(int64_t monotonic_clock_ns, uint32_t frameId, auto& gl = mContext; insertEventMarker("beginFrame"); executeGpuCommandsCompleteOps(); + executeFrameBeginsOps(); if (UTILS_UNLIKELY(!mExternalStreams.empty())) { OpenGLPlatform& platform = mPlatform; for (GLTexture const* t : mExternalStreams) { @@ -2577,6 +2674,10 @@ void OpenGLDriver::finish(int) { DEBUG_MARKER() glFinish(); executeGpuCommandsCompleteOps(); + executeFrameBeginsOps(); + // since we executed a glFinish(), all pending tasks should be done + assert(mGpuCommandCompleteOps.empty()); + assert(mFrameBeginsOps.empty()); } UTILS_NOINLINE diff --git a/filament/backend/src/opengl/OpenGLDriver.h b/filament/backend/src/opengl/OpenGLDriver.h index d6410b1d78..9659321f2c 100644 --- a/filament/backend/src/opengl/OpenGLDriver.h +++ b/filament/backend/src/opengl/OpenGLDriver.h @@ -43,6 +43,7 @@ class TargetBufferInfo; class OpenGLProgram; class OpenGLBlitter; +class TimerQueryInterface; class OpenGLDriver final : public backend::DriverBase { inline explicit OpenGLDriver(backend::OpenGLPlatform* platform) noexcept; @@ -122,6 +123,18 @@ public: ~DebugMarker() noexcept; }; + struct GLTimerQuery : public backend::HwTimerQuery { + struct { + GLuint query = 0; + struct { + uint64_t elapsed = 0; + std::atomic_bool available; + } emulation; + } gl; + // 0 means not available, otherwise query result in ns. + std::atomic elapsed{}; + }; + struct GLStream : public backend::HwStream { static constexpr size_t ROUND_ROBIN_TEXTURE_COUNT = 3; // 3 maximum using HwStream::HwStream; @@ -372,9 +385,19 @@ private: void setExternalTexture(GLTexture* t, void* image); + // tasks executed on the main thread after the fence signaled void whenGpuCommandsComplete(std::function fn) noexcept; void executeGpuCommandsCompleteOps() noexcept; - std::vector>> mGpuCommandCompleteOps; + std::vector>> mGpuCommandCompleteOps; + + // tasks regularly executed on the main thread at frame begin time until they return true + void whenFrameBegins(std::function fn) noexcept; + void executeFrameBeginsOps() noexcept; + std::vector> mFrameBeginsOps; + + // timer query implementation + TimerQueryInterface* mTimerQueryImpl = nullptr; + bool mFrameTimeSupported = false; }; // ------------------------------------------------------------------------------------------------ diff --git a/filament/backend/src/opengl/TimerQuery.cpp b/filament/backend/src/opengl/TimerQuery.cpp new file mode 100644 index 0000000000..a511066e5d --- /dev/null +++ b/filament/backend/src/opengl/TimerQuery.cpp @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "TimerQuery.h" + +#include "private/backend/OpenGLPlatform.h" + +#include +#include +#include + +namespace filament { + +using namespace backend; +using namespace GLUtils; + +// ------------------------------------------------------------------------------------------------ + +TimerQueryInterface::~TimerQueryInterface() = default; + +// ------------------------------------------------------------------------------------------------ + +TimerQueryNative::TimerQueryNative(OpenGLContext& context) + : gl(context) { +} + +TimerQueryNative::~TimerQueryNative() = default; + +void TimerQueryNative::beginTimeElapsedQuery(GLTimerQuery* query) { + gl.beginQuery(GL_TIME_ELAPSED, query->gl.query); + CHECK_GL_ERROR(utils::slog.e) +} + +void TimerQueryNative::endTimeElapsedQuery(GLTimerQuery* query) { + gl.endQuery(GL_TIME_ELAPSED); + CHECK_GL_ERROR(utils::slog.e) +} + +bool TimerQueryNative::queryResultAvailable(GLTimerQuery* query) { + GLuint available = 0; + glGetQueryObjectuiv(query->gl.query, GL_QUERY_RESULT_AVAILABLE, &available); + CHECK_GL_ERROR(utils::slog.e) + return available != 0; +} + +uint64_t TimerQueryNative::queryResult(GLTimerQuery* query) { + GLuint64 elapsedTime = 0; + // IOS doesn't have glGetQueryObjectui64v, we'll never end-up here on ios anyways +#ifndef IOS + glGetQueryObjectui64v(query->gl.query, GL_QUERY_RESULT, &elapsedTime); +#endif + CHECK_GL_ERROR(utils::slog.e) + return elapsedTime; +} + +// ------------------------------------------------------------------------------------------------ + +TimerQueryFence::TimerQueryFence(backend::OpenGLPlatform& platform) + : mPlatform(platform) { + mQueue.reserve(2); + mThread = std::thread([this]() { + auto& queue = mQueue; + bool exitRequested; + do { + std::unique_lock lock(mLock); + mCondition.wait(lock, [this, &queue]() -> bool { + return mExitRequested || !queue.empty(); + }); + exitRequested = mExitRequested; + if (!queue.empty()) { + Job job(queue.front()); + queue.erase(queue.begin()); + lock.unlock(); + job(); + } + } while (!exitRequested); + }); +} + +TimerQueryFence::~TimerQueryFence() { + if (mThread.joinable()) { + std::unique_lock lock(mLock); + mExitRequested = true; + lock.unlock(); + mCondition.notify_one(); + mThread.join(); + } +} + +void TimerQueryFence::enqueue(TimerQueryFence::Job&& job) { + std::unique_lock lock(mLock); + mQueue.push_back(std::forward(job)); + lock.unlock(); + mCondition.notify_one(); +} + +void TimerQueryFence::beginTimeElapsedQuery(GLTimerQuery* query) { + Platform::Fence* fence = mPlatform.createFence(); + query->gl.emulation.available.store(false); + push([this, fence, query]() { + mPlatform.waitFence(fence, FENCE_WAIT_FOR_EVER); + query->gl.emulation.elapsed = clock::now().time_since_epoch().count(); + mPlatform.destroyFence(fence); + }); +} + +void TimerQueryFence::endTimeElapsedQuery(GLTimerQuery* query) { + Platform::Fence* fence = mPlatform.createFence(); + push([this, fence, query]() { + mPlatform.waitFence(fence, FENCE_WAIT_FOR_EVER); + query->gl.emulation.elapsed = clock::now().time_since_epoch().count() - query->gl.emulation.elapsed; + query->gl.emulation.available.store(true); + mPlatform.destroyFence(fence); + }); +} + +bool TimerQueryFence::queryResultAvailable(GLTimerQuery* query) { + return query->gl.emulation.available.load(); +} + +uint64_t TimerQueryFence::queryResult(GLTimerQuery* query) { + return query->gl.emulation.elapsed; +} + +// ------------------------------------------------------------------------------------------------ + +TimerQueryFallback::TimerQueryFallback() = default; + +TimerQueryFallback::~TimerQueryFallback() = default; + +void TimerQueryFallback::beginTimeElapsedQuery(TimerQueryInterface::GLTimerQuery* query) { + // this implementation clearly doesn't work at all, but we have no h/w support + query->gl.emulation.available.store(false, std::memory_order_relaxed); + query->gl.emulation.elapsed = clock::now().time_since_epoch().count(); +} + +void TimerQueryFallback::endTimeElapsedQuery(TimerQueryInterface::GLTimerQuery* query) { + // this implementation clearly doesn't work at all, but we have no h/w support + query->gl.emulation.elapsed = clock::now().time_since_epoch().count() - query->gl.emulation.elapsed; + query->gl.emulation.available.store(true, std::memory_order_relaxed); +} + +bool TimerQueryFallback::queryResultAvailable(TimerQueryInterface::GLTimerQuery* query) { + return query->gl.emulation.available.load(std::memory_order_relaxed); +} + +uint64_t TimerQueryFallback::queryResult(TimerQueryInterface::GLTimerQuery* query) { + return query->gl.emulation.elapsed; +} + +} // namespace filament diff --git a/filament/backend/src/opengl/TimerQuery.h b/filament/backend/src/opengl/TimerQuery.h new file mode 100644 index 0000000000..45a9a87d43 --- /dev/null +++ b/filament/backend/src/opengl/TimerQuery.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TNT_FILAMENT_DRIVER_TIMERQUERY_H +#define TNT_FILAMENT_DRIVER_TIMERQUERY_H + +#include "OpenGLDriver.h" + +#include + +#include +#include + +namespace filament { + +/* + * we need two implementation of timer queries (only elapsed time), because + * on some gpu disjoint_timer_queyr/arb_timer_query is much less accurate than + * using fences. + * + * These classes implement the various strategies... + */ + +class TimerQueryInterface { +protected: + using GLTimerQuery = OpenGLDriver::GLTimerQuery; + using clock = std::chrono::steady_clock; + +public: + virtual ~TimerQueryInterface(); + virtual void beginTimeElapsedQuery(GLTimerQuery* query) = 0; + virtual void endTimeElapsedQuery(GLTimerQuery* query) = 0; + virtual bool queryResultAvailable(GLTimerQuery* query) = 0; + virtual uint64_t queryResult(GLTimerQuery* query) = 0; +}; + +class TimerQueryNative : public TimerQueryInterface { +public: + explicit TimerQueryNative(OpenGLContext& context); + ~TimerQueryNative() override; +private: + void beginTimeElapsedQuery(GLTimerQuery* query) override; + void endTimeElapsedQuery(GLTimerQuery* query) override; + bool queryResultAvailable(GLTimerQuery* query) override; + uint64_t queryResult(GLTimerQuery* query) override; + OpenGLContext& gl; +}; + +class TimerQueryFence : public TimerQueryInterface { +public: + explicit TimerQueryFence(backend::OpenGLPlatform& platform); + ~TimerQueryFence() override; +private: + using Job = std::function; + void beginTimeElapsedQuery(GLTimerQuery* query) override; + void endTimeElapsedQuery(GLTimerQuery* query) override; + bool queryResultAvailable(GLTimerQuery* query) override; + uint64_t queryResult(GLTimerQuery* query) override; + void enqueue(Job&& job); + + template + void push(CALLABLE&& func, ARGS&& ... args) { + enqueue(Job(std::bind(std::forward(func), std::forward(args)...))); + } + + backend::OpenGLPlatform& mPlatform; + std::thread mThread; + mutable utils::Mutex mLock; + mutable utils::Condition mCondition; + std::vector mQueue; + bool mExitRequested = false; +}; + +class TimerQueryFallback : public TimerQueryInterface { +public: + explicit TimerQueryFallback(); + ~TimerQueryFallback() override; +private: + void beginTimeElapsedQuery(GLTimerQuery* query) override; + void endTimeElapsedQuery(GLTimerQuery* query) override; + bool queryResultAvailable(GLTimerQuery* query) override; + uint64_t queryResult(GLTimerQuery* query) override; +}; + +} // namespace filament + +#endif //TNT_FILAMENT_DRIVER_TIMERQUERY_H diff --git a/filament/backend/src/opengl/gl_headers.cpp b/filament/backend/src/opengl/gl_headers.cpp index 8c6148afd5..0258f556a4 100644 --- a/filament/backend/src/opengl/gl_headers.cpp +++ b/filament/backend/src/opengl/gl_headers.cpp @@ -42,6 +42,9 @@ PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC glFramebufferTexture2DMultisampleEXT PFNGLDEBUGMESSAGECALLBACKKHRPROC glDebugMessageCallbackKHR; PFNGLGETDEBUGMESSAGELOGKHRPROC glGetDebugMessageLogKHR; #endif +#ifdef GL_EXT_disjoint_timer_query +PFNGLGETQUERYOBJECTUI64VEXTPROC glGetQueryObjectui64v; +#endif static std::once_flag sGlExtInitialized; @@ -91,6 +94,11 @@ void importGLESExtensionsEntryPoints() { glGetDebugMessageLogKHR = (PFNGLGETDEBUGMESSAGELOGKHRPROC)eglGetProcAddress( "glGetDebugMessageLogKHR"); +#endif +#ifdef GL_EXT_disjoint_timer_query + glGetQueryObjectui64v = + (PFNGLGETQUERYOBJECTUI64VEXTPROC)eglGetProcAddress( + "glGetQueryObjectui64vEXT"); #endif }); } diff --git a/filament/backend/src/opengl/gl_headers.h b/filament/backend/src/opengl/gl_headers.h index 06e2a500b9..e5a0229539 100644 --- a/filament/backend/src/opengl/gl_headers.h +++ b/filament/backend/src/opengl/gl_headers.h @@ -47,6 +47,10 @@ #ifdef GL_KHR_debug extern PFNGLDEBUGMESSAGECALLBACKKHRPROC glDebugMessageCallbackKHR; extern PFNGLGETDEBUGMESSAGELOGKHRPROC glGetDebugMessageLogKHR; +#endif +#ifdef GL_EXT_disjoint_timer_query + extern PFNGLGETQUERYOBJECTUI64VEXTPROC glGetQueryObjectui64v; + #define GL_TIME_ELAPSED 0x88BF #endif } @@ -82,6 +86,7 @@ * requires the following 3.1 define in order to compile. */ #define GL_TEXTURE_2D_MULTISAMPLE 0x9100 + #define GL_TIME_ELAPSED 0x88BF #else #include diff --git a/filament/backend/src/vulkan/VulkanDriver.cpp b/filament/backend/src/vulkan/VulkanDriver.cpp index ded60c5d1f..8862a5683b 100644 --- a/filament/backend/src/vulkan/VulkanDriver.cpp +++ b/filament/backend/src/vulkan/VulkanDriver.cpp @@ -457,6 +457,9 @@ void VulkanDriver::createStreamFromTextureIdR(Handle sh, intptr_t exte uint32_t width, uint32_t height) { } +void VulkanDriver::createTimerQueryR(Handle tqh, int) { +} + Handle VulkanDriver::createVertexBufferS() noexcept { return alloc_handle(); } @@ -513,6 +516,10 @@ Handle VulkanDriver::createStreamFromTextureIdS() noexcept { return {}; } +Handle VulkanDriver::createTimerQueryS() noexcept { + return {}; +} + void VulkanDriver::destroySamplerGroup(Handle sbh) { if (sbh) { // Unlike most of the other "Hw" handles, the sampler buffer is an abstract concept and does @@ -559,6 +566,9 @@ void VulkanDriver::destroySwapChain(Handle sch) { void VulkanDriver::destroyStream(Handle sh) { } +void VulkanDriver::destroyTimerQuery(Handle tqh) { +} + Handle VulkanDriver::createStreamNative(void* nativeStream) { return {}; } @@ -684,6 +694,10 @@ void VulkanDriver::setupExternalImage(void* image) { void VulkanDriver::cancelExternalImage(void* image) { } +bool VulkanDriver::getTimerQueryValue(Handle tqh, uint64_t* elapsedTime) { + return false; +} + void VulkanDriver::setExternalImage(Handle th, void* image) { } @@ -1182,6 +1196,13 @@ void VulkanDriver::draw(PipelineState pipelineState, Handle r vkCmdDrawIndexed(cmdbuffer, indexCount, instanceCount, firstIndex, vertexOffset, firstInstId); } + +void VulkanDriver::beginTimerQuery(Handle tqh) { +} + +void VulkanDriver::endTimerQuery(Handle tqh) { +} + #ifndef NDEBUG void VulkanDriver::debugCommand(const char* methodName) { static const std::set OUTSIDE_COMMANDS = { diff --git a/filament/src/FrameInfo.cpp b/filament/src/FrameInfo.cpp index d7cc600fbf..89084725b2 100644 --- a/filament/src/FrameInfo.cpp +++ b/filament/src/FrameInfo.cpp @@ -16,11 +16,7 @@ #include "FrameInfo.h" -#include "details/Fence.h" - -#include #include -#include #include @@ -28,145 +24,39 @@ namespace filament { using namespace utils; +using namespace details; -// ------------------------------------------------------------------------------------------------ - -FrameInfoManager::FrameInfoManager(FEngine& engine) - : mEngine(engine), - mPoolArena("FrameInfo", sizeof(FrameInfo) * POOL_COUNT) { - mFrameInfoHistory.resize(HISTORY_COUNT); +FrameInfoManager::FrameInfoManager(FEngine& engine) : mEngine(engine) { + backend::DriverApi& driver = mEngine.getDriverApi(); + for (auto& query : mQueries) { + query = driver.createTimerQuery(); + } } FrameInfoManager::~FrameInfoManager() noexcept = default; -void FrameInfo::beginFrame(FrameInfoManager* mgr) { - Fence* fence = mgr->getEngine().createFence(FFence::Type::HARD); - mgr->push([this, fence]() { - Fence::waitAndDestroy(fence, Fence::Mode::DONT_FLUSH); - laps[START] = clock::now(); - }); +void FrameInfoManager::terminate() { + backend::DriverApi& driver = mEngine.getDriverApi(); + for (auto& query : mQueries) { + driver.destroyTimerQuery(query); + } } -void FrameInfo::lap(FrameInfoManager* mgr, lap_id id) { - Fence* fence = mgr->getEngine().createFence(FFence::Type::HARD); - mgr->push([this, fence, id]() { - Fence::waitAndDestroy(fence, Fence::Mode::DONT_FLUSH); - laps[id] = clock::now(); - }); -} - -void FrameInfo::endFrame(FrameInfoManager* mgr) { - Fence* fence = mgr->getEngine().createFence(FFence::Type::HARD); - mgr->push([this, mgr, fence]() { - char buf[256]; - snprintf(buf, 256, "GPU time [id=%u]", frame); - SYSTRACE_NAME(buf); - - Fence::waitAndDestroy(fence, Fence::Mode::DONT_FLUSH); - laps[FINISH] = clock::now(); - mgr->finish(this); - }); -} - -// ------------------------------------------------------------------------------------------------ - void FrameInfoManager::beginFrame(uint32_t frameId) { - SYSTRACE_CONTEXT(); - SYSTRACE_ASYNC_BEGIN("frame latency", frameId); - - FrameInfo* info = obtain(); - mCurrentFrameInfo = info; - if (info) { - info->frame = frameId; - info->beginFrame(this); + backend::DriverApi& driver = mEngine.getDriverApi(); + driver.beginTimerQuery(mQueries[mIndex]); + uint64_t elapsed = 0; + if (driver.getTimerQueryValue(mQueries[mLast], &elapsed)) { + mLast = (mLast + 1) % POOL_COUNT; + mFrameTime = std::chrono::duration(elapsed); } } void FrameInfoManager::endFrame() { - FrameInfo* const info = mCurrentFrameInfo; - if (info) { - mCurrentFrameInfo = nullptr; - info->endFrame(this); - } + backend::DriverApi& driver = mEngine.getDriverApi(); + driver.endTimerQuery(mQueries[mIndex]); + mIndex = (mIndex + 1) % POOL_COUNT; } -void FrameInfoManager::cancelFrame() { - FrameInfo* info = mCurrentFrameInfo; - if (info) { - mCurrentFrameInfo = nullptr; - push([this, info]() { - mPoolArena.free(info); - }); - } -} - -UTILS_ALWAYS_INLINE -inline FrameInfo* FrameInfoManager::obtain() noexcept { - return mPoolArena.alloc(1); -} - -void FrameInfoManager::finish(FrameInfo* info) noexcept { - SYSTRACE_CONTEXT(); - SYSTRACE_ASYNC_END("frame latency", info->frame); - - // store the new frame info into the history array - std::unique_lock lock(mLock); - auto& history = mFrameInfoHistory; - if (history.size() >= HISTORY_COUNT) { - // if the history has grown enough, remove the oldest element - history.erase(history.begin()); - } - // add a copy of the new element to the history - history.push_back(*info); - lock.unlock(); - - // return the item to the pool without the lock held - mPoolArena.free(info); -} - -// ------------------------------------------------------------------------------------------------ - -FrameInfoManager::SyncThread::~SyncThread() { - if (mThread.joinable()) { - requestExitAndWait(); - } -} - -void FrameInfoManager::SyncThread::run() { - mThread = std::thread(&SyncThread::loop, this); -} - -void FrameInfoManager::SyncThread::requestExitAndWait() { - std::unique_lock lock(mLock); - mExitRequested = true; - lock.unlock(); - mCondition.notify_one(); - mThread.join(); -} - -void FrameInfoManager::SyncThread::enqueue(SyncThread::Job&& job) { - std::unique_lock lock(mLock); - mQueue.push_back(std::forward(job)); - lock.unlock(); - mCondition.notify_one(); -} - -void FrameInfoManager::SyncThread::loop() { - JobSystem::setThreadPriority(JobSystem::Priority::URGENT_DISPLAY); - JobSystem::setThreadName("SyncThread"); - auto& queue = mQueue; - bool exitRequested; - do { - std::unique_lock lock(mLock); - mCondition.wait(lock, [this, &queue]() -> bool { return mExitRequested || !queue.empty(); }); - exitRequested = mExitRequested; - if (!queue.empty()) { - Job job(queue.front()); - queue.pop_front(); - lock.unlock(); - job(); - } - } while (!exitRequested); -} } // namespace filament diff --git a/filament/src/FrameInfo.h b/filament/src/FrameInfo.h index f002a9ce70..d8b3b2f5dd 100644 --- a/filament/src/FrameInfo.h +++ b/filament/src/FrameInfo.h @@ -19,195 +19,40 @@ #include "details/Engine.h" -#include +#include "backend/Handle.h" -#include - -#include #include -#include -#include -#include -#include #include -#include - -// set EXTRA_TIMING_INFO to enable and print extra timing info about the render loop -#define EXTRA_TIMING_INFO false +#include namespace filament { - -using namespace details; - -class FrameInfoManager; - -class FrameInfo { -public: - friend class FrameInfoManager; - using clock = std::chrono::steady_clock; - using time_point = clock::time_point; - using duration = std::chrono::duration; - - enum lap_id { - START = 0, // don't use for FrameInfo::lap() - FINISH = 1, // don't use for FrameInfo::lap() - LAP_0, - LAP_1, - LAP_2, - LAP_3, - LAP_4, - LAP_5, - }; - - void beginFrame(FrameInfoManager* mgr); - void lap(FrameInfoManager* mgr, lap_id id); - void endFrame(FrameInfoManager* mgr); - - static constexpr size_t MAX_LAPS_IDS = 8; - - uint32_t frame = 0; - time_point laps[MAX_LAPS_IDS] = { time_point::max() }; -}; +namespace details { +class FEngine; +} // namespace details class FrameInfoManager { - friend class FrameInfo; - static constexpr size_t HISTORY_COUNT = 5; static constexpr size_t POOL_COUNT = 8; - // set this to true to enable extra timing info - static constexpr bool mLapRecordsEnabled = EXTRA_TIMING_INFO; - public: - using clock = FrameInfo::clock; - using time_point = FrameInfo::time_point; - using duration = FrameInfo::duration; + using duration = std::chrono::duration; - explicit FrameInfoManager(FEngine& engine); + explicit FrameInfoManager(details::FEngine& engine); ~FrameInfoManager() noexcept; - - FEngine& getEngine() { return mEngine; } - - void run() { - mSyncThread.run(); - } - - void terminate() { - mSyncThread.requestExitAndWait(); - } - - // call this immediately after "make current" - void beginFrame(uint32_t frameId); - - // call this between beginFrame and endFrame to record a time - void lap(FrameInfo::lap_id id) { - if (mLapRecordsEnabled) { - FrameInfo* const info = mCurrentFrameInfo; - assert(info); - info->lap(this, id); - } - } - - // call this immediately before "swap buffers" - void endFrame(); - - void cancelFrame(); - - constexpr bool isLapRecordsEnabled() const noexcept { - return mLapRecordsEnabled; - } + void terminate(); + void beginFrame(uint32_t frameId); // call this immediately after "make current" + void endFrame(); // call this immediately before "swap buffers" duration getLastFrameTime() const noexcept { - std::unique_lock lock(mLock); - FrameInfo const& info = mFrameInfoHistory.front(); - return info.laps[FrameInfo::FINISH] - info.laps[FrameInfo::START]; - } - - std::vector getHistory() const noexcept { - std::unique_lock lock(mLock); - return mFrameInfoHistory; - } - - // no user serviceable part below... - - template - void push(CALLABLE&& func, ARGS&&... args) { - mSyncThread.push(std::forward(func), std::forward(args)...); - } - - static constexpr size_t getHistorySize() noexcept { - return HISTORY_COUNT; + return mFrameTime; } private: - - class SyncThread { - public: - using Job = std::function; - - SyncThread() = default; - ~SyncThread(); - - void run(); - void requestExitAndWait(); - - template - void push(CALLABLE&& func, ARGS&&... args) { - enqueue(Job(std::bind(std::forward(func), std::forward(args)...))); - } - - private: - void enqueue(SyncThread::Job&& job); - void loop(); - std::thread mThread; - mutable std::mutex mLock; - mutable std::condition_variable mCondition; - std::deque mQueue; - bool mExitRequested = false; - }; - - FrameInfo* obtain() noexcept; - void finish(FrameInfo* info) noexcept; - - using PoolArena = utils::Arena, utils::LockingPolicy::SpinLock>; - FEngine& mEngine; - PoolArena mPoolArena; - SyncThread mSyncThread; - FrameInfo* mCurrentFrameInfo = nullptr; - - mutable std::mutex mLock; - std::vector mFrameInfoHistory; -}; - - -template -class Series { -public: - Series() { - mIn.resize(MEDIAN); - mOut.resize(HISTORY); - } - - void push(T value, float b = 1.0f - math::fast::exp(-0.125f)) noexcept { - mIn.push_back(value); - mIn.pop_front(); - std::array median; - std::copy_n(mIn.begin(), median.size(), median.begin()); - std::sort(median.begin(), median.end()); - mLowPass += b * (median[median.size() / 2] - mLowPass); - mOut.push_back(mLowPass); - mOut.pop_front(); - } - - T operator[](size_t i) const noexcept { return mOut[i]; } - typename std::deque::iterator begin() const { return mOut.begin(); } - typename std::deque::iterator end() const { return mOut.end(); } - T const& oldest() const noexcept { return mOut.front(); } - T const& latest() const noexcept { return mOut.back(); } - - std::deque mIn; - std::deque mOut; - T mLowPass = {}; + details::FEngine& mEngine; + backend::Handle mQueries[POOL_COUNT]; + duration mFrameTime{}; + uint32_t mIndex = 0; + uint32_t mLast = 0; }; diff --git a/filament/src/Renderer.cpp b/filament/src/Renderer.cpp index b9ff91a779..af0fd97929 100644 --- a/filament/src/Renderer.cpp +++ b/filament/src/Renderer.cpp @@ -97,10 +97,6 @@ void FRenderer::init() noexcept { // this will clip all HDR data, but we don't have a choice mHdrQualityHigh = TextureFormat::RGB8; } - - if (UTILS_HAS_THREADING) { - mFrameInfoManager.run(); - } } FRenderer::~FRenderer() noexcept { @@ -716,19 +712,18 @@ bool FRenderer::beginFrame(FSwapChain* swapChain, backend::FrameFinishedCallback int64_t monotonic_clock_ns (std::chrono::steady_clock::now().time_since_epoch().count()); driver.beginFrame(monotonic_clock_ns, mFrameId, callback, user); + if (!mFrameSkipper.beginFrame()) { + driver.endFrame(mFrameId); + engine.flush(); + return false; + } + // This need to occur after the backend beginFrame() because some backends need to start // a command buffer before creating a fence. if (UTILS_HAS_THREADING) { mFrameInfoManager.beginFrame(mFrameId); } - if (!mFrameSkipper.beginFrame()) { - mFrameInfoManager.cancelFrame(); - driver.endFrame(mFrameId); - engine.flush(); - return false; - } - // latch the frame time std::chrono::duration time{ getUserTime() }; float h = float(time.count()); @@ -747,16 +742,15 @@ void FRenderer::endFrame() { FEngine& engine = getEngine(); FEngine::DriverApi& driver = engine.getDriverApi(); - FrameInfoManager& frameInfoManager = mFrameInfoManager; - if (UTILS_HAS_THREADING) { // on debug builds this helps catching cases where we're writing to // the buffer form another thread, which is currently not allowed. driver.debugThreading(); - frameInfoManager.endFrame(); + mFrameInfoManager.endFrame(); } + mFrameSkipper.endFrame(); if (mSwapChain) { @@ -779,19 +773,6 @@ void FRenderer::endFrame() { // make sure we're done with the gcs js.waitAndRelease(job); - -#if EXTRA_TIMING_INFO - if (UTILS_UNLIKELY(frameInfoManager.isLapRecordsEnabled())) { - auto history = frameInfoManager.getHistory(); - FrameInfo const& info = history.back(); - FrameInfo::duration rendering = info.laps[FrameInfo::LAP_0] - info.laps[FrameInfo::START]; - FrameInfo::duration postprocess = info.laps[FrameInfo::FINISH] - info.laps[FrameInfo::LAP_0]; - mRendering.push(rendering.count()); - mPostProcess.push(postprocess.count()); - slog.d << mRendering.latest() << ", " - << mPostProcess.latest() << io::endl; - } -#endif } void FRenderer::readPixels(uint32_t xoffset, uint32_t yoffset, uint32_t width, uint32_t height, diff --git a/filament/src/details/Renderer.h b/filament/src/details/Renderer.h index 5454b3cbc0..5ddc2215f0 100644 --- a/filament/src/details/Renderer.h +++ b/filament/src/details/Renderer.h @@ -156,11 +156,6 @@ private: // per-frame arena for this Renderer LinearAllocatorArena& mPerRenderPassArena; - -#if EXTRA_TIMING_INFO - Series mRendering; - Series mPostProcess; -#endif }; FILAMENT_UPCAST(Renderer)