void TableTicker::InplaceTick(TickSample* sample) { ThreadProfile& currThreadProfile = *sample->threadProfile; PseudoStack* stack = currThreadProfile.GetPseudoStack(); bool recordSample = true; /* Don't process the PeudoStack's markers or honour jankOnly if we're immediately sampling the current thread. */ if (!sample->isSamplingCurrentThread) { // Marker(s) come before the sample ProfilerMarkerLinkedList* pendingMarkersList = stack->getPendingMarkers(); while (pendingMarkersList && pendingMarkersList->peek()) { ProfilerMarker* marker = pendingMarkersList->popHead(); stack->addStoredMarker(marker); currThreadProfile.addTag(ProfileEntry('m', marker)); } stack->updateGeneration(currThreadProfile.GetGenerationID()); if (mJankOnly) { // if we are on a different event we can discard any temporary samples // we've kept around if (sLastSampledEventGeneration != sCurrentEventGeneration) { // XXX: we also probably want to add an entry to the profile to help // distinguish which samples are part of the same event. That, or record // the event generation in each sample currThreadProfile.erase(); } sLastSampledEventGeneration = sCurrentEventGeneration; recordSample = false; // only record the events when we have a we haven't seen a tracer event for 100ms if (!sLastTracerEvent.IsNull()) { TimeDuration delta = sample->timestamp - sLastTracerEvent; if (delta.ToMilliseconds() > 100.0) { recordSample = true; } } } } #if defined(USE_NS_STACKWALK) || defined(USE_EHABI_STACKWALK) if (mUseStackWalk) { doNativeBacktrace(currThreadProfile, sample); } else { doSampleStackTrace(stack, currThreadProfile, mAddLeafAddresses ? sample : nullptr); } #else doSampleStackTrace(stack, currThreadProfile, mAddLeafAddresses ? sample : nullptr); #endif if (recordSample) currThreadProfile.flush(); if (!sLastTracerEvent.IsNull() && sample && currThreadProfile.IsMainThread()) { TimeDuration delta = sample->timestamp - sLastTracerEvent; currThreadProfile.addTag(ProfileEntry('r', delta.ToMilliseconds())); } if (sample) { TimeDuration delta = sample->timestamp - sStartTime; currThreadProfile.addTag(ProfileEntry('t', delta.ToMilliseconds())); } if (sLastFrameNumber != sFrameNumber) { currThreadProfile.addTag(ProfileEntry('f', sFrameNumber)); sLastFrameNumber = sFrameNumber; } }
// Returns true if we captured a full interval of data bool FPSCounter::CapturedFullInterval(TimeStamp aTimestamp) { TimeDuration duration = aTimestamp - mLastInterval; return duration.ToSeconds() >= kFpsDumpInterval; }
void nsHostResolver::ThreadFunc(void *arg) { LOG(("DNS lookup thread - starting execution.\n")); static nsThreadPoolNaming naming; naming.SetThreadPoolName(NS_LITERAL_CSTRING("DNS Resolver")); #if defined(RES_RETRY_ON_FAILURE) nsResState rs; #endif nsHostResolver *resolver = (nsHostResolver *)arg; nsHostRecord *rec; PRAddrInfo *prai = nullptr; while (resolver->GetHostToLookup(&rec)) { LOG(("DNS lookup thread - Calling getaddrinfo for host [%s].\n", rec->host)); int flags = PR_AI_ADDRCONFIG; if (!(rec->flags & RES_CANON_NAME)) flags |= PR_AI_NOCANONNAME; TimeStamp startTime = TimeStamp::Now(); MOZ_EVENT_TRACER_EXEC(rec, "net::dns::resolve"); // We need to remove IPv4 records manually // because PR_GetAddrInfoByName doesn't support PR_AF_INET6. bool disableIPv4 = rec->af == PR_AF_INET6; uint16_t af = disableIPv4 ? PR_AF_UNSPEC : rec->af; prai = PR_GetAddrInfoByName(rec->host, af, flags); #if defined(RES_RETRY_ON_FAILURE) if (!prai && rs.Reset()) prai = PR_GetAddrInfoByName(rec->host, af, flags); #endif TimeDuration elapsed = TimeStamp::Now() - startTime; uint32_t millis = static_cast<uint32_t>(elapsed.ToMilliseconds()); // convert error code to nsresult nsresult status; AddrInfo *ai = nullptr; if (prai) { const char *cname = nullptr; if (rec->flags & RES_CANON_NAME) cname = PR_GetCanonNameFromAddrInfo(prai); ai = new AddrInfo(rec->host, prai, disableIPv4, cname); PR_FreeAddrInfo(prai); if (ai->mAddresses.isEmpty()) { delete ai; ai = nullptr; } } if (ai) { status = NS_OK; Telemetry::Accumulate(!rec->addr_info_gencnt ? Telemetry::DNS_LOOKUP_TIME : Telemetry::DNS_RENEWAL_TIME, millis); } else { status = NS_ERROR_UNKNOWN_HOST; Telemetry::Accumulate(Telemetry::DNS_FAILED_LOOKUP_TIME, millis); } // OnLookupComplete may release "rec", log before we lose it. LOG(("DNS lookup thread - lookup completed for host [%s]: %s.\n", rec->host, ai ? "success" : "failure: unknown host")); resolver->OnLookupComplete(rec, status, ai); } NS_RELEASE(resolver); LOG(("DNS lookup thread - queue empty, thread finished.\n")); }
void nsHostResolver::OnLookupComplete(nsHostRecord *rec, nsresult status, AddrInfo *result) { // get the list of pending callbacks for this lookup, and notify // them that the lookup is complete. PRCList cbs; PR_INIT_CLIST(&cbs); { MutexAutoLock lock(mLock); // grab list of callbacks to notify MoveCList(rec->callbacks, cbs); // update record fields. We might have a rec->addr_info already if a // previous lookup result expired and we're reresolving it.. AddrInfo *old_addr_info; { MutexAutoLock lock(rec->addr_info_lock); old_addr_info = rec->addr_info; rec->addr_info = result; rec->addr_info_gencnt++; } delete old_addr_info; rec->expiration = TimeStamp::NowLoRes(); if (result) { rec->expiration += mMaxCacheLifetime; rec->negative = false; } else { rec->expiration += TimeDuration::FromSeconds(60); /* one minute for negative cache */ rec->negative = true; } rec->resolving = false; if (rec->usingAnyThread) { mActiveAnyThreadCount--; rec->usingAnyThread = false; } if (!mShutdown) { // add to mEvictionQ PR_APPEND_LINK(rec, &mEvictionQ); NS_ADDREF(rec); if (mEvictionQSize < mMaxCacheEntries) mEvictionQSize++; else { // remove first element on mEvictionQ nsHostRecord *head = static_cast<nsHostRecord *>(PR_LIST_HEAD(&mEvictionQ)); PR_REMOVE_AND_INIT_LINK(head); PL_DHashTableOperate(&mDB, (nsHostKey *) head, PL_DHASH_REMOVE); if (!head->negative) { // record the age of the entry upon eviction. TimeDuration age = TimeStamp::NowLoRes() - (head->expiration - mMaxCacheLifetime); Telemetry::Accumulate(Telemetry::DNS_CLEANUP_AGE, static_cast<uint32_t>(age.ToSeconds() / 60)); } // release reference to rec owned by mEvictionQ NS_RELEASE(head); } } } MOZ_EVENT_TRACER_DONE(rec, "net::dns::resolve"); if (!PR_CLIST_IS_EMPTY(&cbs)) { PRCList *node = cbs.next; while (node != &cbs) { nsResolveHostCallback *callback = static_cast<nsResolveHostCallback *>(node); node = node->next; callback->OnLookupComplete(this, rec, status); // NOTE: callback must not be dereferenced after this point!! } } NS_RELEASE(rec); }
gfxFontEntry* gfxPlatformFontList::SystemFindFontForChar(uint32_t aCh, uint32_t aNextCh, int32_t aRunScript, const gfxFontStyle* aStyle) { gfxFontEntry* fontEntry = nullptr; // is codepoint with no matching font? return null immediately if (mCodepointsWithNoFonts.test(aCh)) { return nullptr; } // Try to short-circuit font fallback for U+FFFD, used to represent // encoding errors: just use cached family from last time U+FFFD was seen. // This helps speed up pages with lots of encoding errors, binary-as-text, // etc. if (aCh == 0xFFFD && mReplacementCharFallbackFamily) { bool needsBold; // ignored in the system fallback case fontEntry = mReplacementCharFallbackFamily->FindFontForStyle(*aStyle, needsBold); // this should never fail, as we must have found U+FFFD in order to set // mReplacementCharFallbackFamily at all, but better play it safe if (fontEntry && fontEntry->HasCharacter(aCh)) { return fontEntry; } } TimeStamp start = TimeStamp::Now(); // search commonly available fonts bool common = true; gfxFontFamily *fallbackFamily = nullptr; fontEntry = CommonFontFallback(aCh, aNextCh, aRunScript, aStyle, &fallbackFamily); // if didn't find a font, do system-wide fallback (except for specials) uint32_t cmapCount = 0; if (!fontEntry) { common = false; fontEntry = GlobalFontFallback(aCh, aRunScript, aStyle, cmapCount, &fallbackFamily); } TimeDuration elapsed = TimeStamp::Now() - start; PRLogModuleInfo *log = gfxPlatform::GetLog(eGfxLog_textrun); if (MOZ_UNLIKELY(MOZ_LOG_TEST(log, LogLevel::Warning))) { uint32_t unicodeRange = FindCharUnicodeRange(aCh); int32_t script = mozilla::unicode::GetScriptCode(aCh); MOZ_LOG(log, LogLevel::Warning,\ ("(textrun-systemfallback-%s) char: u+%6.6x " "unicode-range: %d script: %d match: [%s]" " time: %dus cmaps: %d\n", (common ? "common" : "global"), aCh, unicodeRange, script, (fontEntry ? NS_ConvertUTF16toUTF8(fontEntry->Name()).get() : "<none>"), int32_t(elapsed.ToMicroseconds()), cmapCount)); } // no match? add to set of non-matching codepoints if (!fontEntry) { mCodepointsWithNoFonts.set(aCh); } else if (aCh == 0xFFFD && fontEntry && fallbackFamily) { mReplacementCharFallbackFamily = fallbackFamily; } // track system fallback time static bool first = true; int32_t intElapsed = int32_t(first ? elapsed.ToMilliseconds() : elapsed.ToMicroseconds()); Telemetry::Accumulate((first ? Telemetry::SYSTEM_FONT_FALLBACK_FIRST : Telemetry::SYSTEM_FONT_FALLBACK), intElapsed); first = false; // track the script for which fallback occurred (incremented one make it // 1-based) Telemetry::Accumulate(Telemetry::SYSTEM_FONT_FALLBACK_SCRIPT, aRunScript + 1); return fontEntry; }
void nsTimerImpl::Fire() { if (mCanceled) return; TimeStamp now = TimeStamp::Now(); #ifdef DEBUG_TIMERS if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) { TimeDuration a = now - mStart; // actual delay in intervals TimeDuration b = TimeDuration::FromMilliseconds(mDelay); // expected delay in intervals TimeDuration delta = (a > b) ? a - b : b - a; PRUint32 d = delta.ToMilliseconds(); // delta in ms sDeltaSum += d; sDeltaSumSquared += double(d) * double(d); sDeltaNum++; PR_LOG(gTimerLog, PR_LOG_DEBUG, ("[this=%p] expected delay time %4ums\n", this, mDelay)); PR_LOG(gTimerLog, PR_LOG_DEBUG, ("[this=%p] actual delay time %fms\n", this, a.ToMilliseconds())); PR_LOG(gTimerLog, PR_LOG_DEBUG, ("[this=%p] (mType is %d) -------\n", this, mType)); PR_LOG(gTimerLog, PR_LOG_DEBUG, ("[this=%p] delta %4dms\n", this, (a > b) ? (PRInt32)d : -(PRInt32)d)); mStart = mStart2; mStart2 = TimeStamp(); } #endif TimeStamp timeout = mTimeout; if (IsRepeatingPrecisely()) { // Precise repeating timers advance mTimeout by mDelay without fail before // calling Fire(). timeout -= TimeDuration::FromMilliseconds(mDelay); } if (gThread) gThread->UpdateFilter(mDelay, timeout, now); if (mCallbackType == CALLBACK_TYPE_INTERFACE) mTimerCallbackWhileFiring = mCallback.i; mFiring = PR_TRUE; // Handle callbacks that re-init the timer, but avoid leaking. // See bug 330128. CallbackUnion callback = mCallback; PRUintn callbackType = mCallbackType; if (callbackType == CALLBACK_TYPE_INTERFACE) NS_ADDREF(callback.i); else if (callbackType == CALLBACK_TYPE_OBSERVER) NS_ADDREF(callback.o); ReleaseCallback(); switch (callbackType) { case CALLBACK_TYPE_FUNC: callback.c(this, mClosure); break; case CALLBACK_TYPE_INTERFACE: callback.i->Notify(this); break; case CALLBACK_TYPE_OBSERVER: callback.o->Observe(static_cast<nsITimer*>(this), NS_TIMER_CALLBACK_TOPIC, nsnull); break; default:; } // If the callback didn't re-init the timer, and it's not a one-shot timer, // restore the callback state. if (mCallbackType == CALLBACK_TYPE_UNKNOWN && mType != TYPE_ONE_SHOT && !mCanceled) { mCallback = callback; mCallbackType = callbackType; } else { // The timer was a one-shot, or the callback was reinitialized. if (callbackType == CALLBACK_TYPE_INTERFACE) NS_RELEASE(callback.i); else if (callbackType == CALLBACK_TYPE_OBSERVER) NS_RELEASE(callback.o); } mFiring = PR_FALSE; mTimerCallbackWhileFiring = nsnull; #ifdef DEBUG_TIMERS if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) { PR_LOG(gTimerLog, PR_LOG_DEBUG, ("[this=%p] Took %fms to fire timer callback\n", this, (TimeStamp::Now() - now).ToMilliseconds())); } #endif // Reschedule repeating timers, except REPEATING_PRECISE which already did // that in PostTimerEvent, but make sure that we aren't armed already (which // can happen if the callback reinitialized the timer). if (IsRepeating() && mType != TYPE_REPEATING_PRECISE && !mArmed) { if (mType == TYPE_REPEATING_SLACK) SetDelayInternal(mDelay); // force mTimeout to be recomputed. For // REPEATING_PRECISE_CAN_SKIP timers this has // already happened. if (gThread) gThread->AddTimer(this); } }
void Enemy::NormalAnimator::update(TimeDuration dt, gr::Model<gr::Transform2>& model) { model.transform().rotation() += angularVelocity * dt.toSecs(); }
void CompositorParent::CompositeToTarget(DrawTarget* aTarget, const nsIntRect* aRect) { profiler_tracing("Paint", "Composite", TRACING_INTERVAL_START); PROFILER_LABEL("CompositorParent", "Composite", js::ProfileEntry::Category::GRAPHICS); MOZ_ASSERT(IsInCompositorThread(), "Composite can only be called on the compositor thread"); #ifdef COMPOSITOR_PERFORMANCE_WARNING TimeDuration scheduleDelta = TimeStamp::Now() - mExpectedComposeStartTime; if (scheduleDelta > TimeDuration::FromMilliseconds(2) || scheduleDelta < TimeDuration::FromMilliseconds(-2)) { printf_stderr("Compositor: Compose starting off schedule by %4.1f ms\n", scheduleDelta.ToMilliseconds()); } #endif mLastCompose = TimeStamp::Now(); if (!CanComposite()) { DidComposite(); return; } AutoResolveRefLayers resolve(mCompositionManager); if (aTarget) { mLayerManager->BeginTransactionWithDrawTarget(aTarget, *aRect); } else { mLayerManager->BeginTransaction(); } if (mForceCompositionTask && !mOverrideComposeReadiness) { if (mCompositionManager->ReadyForCompose()) { mForceCompositionTask->Cancel(); mForceCompositionTask = nullptr; } else { return; } } TimeStamp time = mIsTesting ? mTestTime : mLastCompose; bool requestNextFrame = mCompositionManager->TransformShadowTree(time); if (requestNextFrame) { ScheduleComposition(); } RenderTraceLayers(mLayerManager->GetRoot(), "0000"); mCompositionManager->ComputeRotation(); #ifdef MOZ_DUMP_PAINTING static bool gDumpCompositorTree = false; if (gDumpCompositorTree) { printf_stderr("Painting --- compositing layer tree:\n"); mLayerManager->Dump(); } #endif mLayerManager->SetDebugOverlayWantsNextFrame(false); mLayerManager->EndEmptyTransaction(); if (!aTarget) { DidComposite(); } if (mLayerManager->DebugOverlayWantsNextFrame()) { ScheduleComposition(); } #ifdef COMPOSITOR_PERFORMANCE_WARNING TimeDuration executionTime = TimeStamp::Now() - mLastCompose; TimeDuration frameBudget = TimeDuration::FromMilliseconds(15); int32_t frameRate = CalculateCompositionFrameRate(); if (frameRate > 0) { frameBudget = TimeDuration::FromSeconds(1.0 / frameRate); } if (executionTime > frameBudget) { printf_stderr("Compositor: Composite execution took %4.1f ms\n", executionTime.ToMilliseconds()); } #endif // 0 -> Full-tilt composite if (gfxPrefs::LayersCompositionFrameRate() == 0 || mLayerManager->GetCompositor()->GetDiagnosticTypes() & DiagnosticTypes::FLASH_BORDERS) { // Special full-tilt composite mode for performance testing ScheduleComposition(); } profiler_tracing("Paint", "Composite", TRACING_INTERVAL_END); }
int64_t AsyncLatencyLogger::GetTimeStamp() { TimeDuration t = TimeStamp::Now() - mStart; return t.ToMilliseconds(); }
inline void sleep(TimeDuration const& rel_time) { interruptible_wait(detail::pin_to_zero(rel_time.total_milliseconds())); }
NS_IMETHODIMP CVE_2014_1482_seamonkey2_9_RasterImage::Draw(gfxContext *aContext, gfxPattern::GraphicsFilter aFilter, const gfxMatrix &aUserSpaceToImageSpace, const gfxRect &aFill, const nsIntRect &aSubimage, const nsIntSize& /*aViewportSize - ignored*/, PRUint32 aFlags) { if (mError) return NS_ERROR_FAILURE; // Disallowed in the API if (mInDecoder && (aFlags & imgIContainer::FLAG_SYNC_DECODE)) return NS_ERROR_FAILURE; // Illegal -- you can't draw with non-default decode flags. // (Disabling colorspace conversion might make sense to allow, but // we don't currently.) if ((aFlags & DECODE_FLAGS_MASK) != DECODE_FLAGS_DEFAULT) return NS_ERROR_FAILURE; NS_ENSURE_ARG_POINTER(aContext); // We can only draw with the default decode flags if (mFrameDecodeFlags != DECODE_FLAGS_DEFAULT) { if (!CanForciblyDiscard()) return NS_ERROR_NOT_AVAILABLE; ForceDiscard(); mFrameDecodeFlags = DECODE_FLAGS_DEFAULT; } // We use !mDecoded && mHasSourceData to mean discarded. if (!mDecoded && mHasSourceData) { mDrawStartTime = TimeStamp::Now(); } // If a synchronous draw is requested, flush anything that might be sitting around if (aFlags & FLAG_SYNC_DECODE) { nsresult rv = SyncDecode(); NS_ENSURE_SUCCESS(rv, rv); } imgFrame *frame = GetCurrentDrawableImgFrame(); if (!frame) { return NS_OK; // Getting the frame (above) touches the image and kicks off decoding } nsIntRect framerect = frame->GetRect(); nsIntMargin padding(framerect.x, framerect.y, mSize.width - framerect.XMost(), mSize.height - framerect.YMost()); frame->Draw(aContext, aFilter, aUserSpaceToImageSpace, aFill, padding, aSubimage); if (mDecoded && !mDrawStartTime.IsNull()) { TimeDuration drawLatency = TimeStamp::Now() - mDrawStartTime; Telemetry::Accumulate(Telemetry::IMAGE_DECODE_ON_DRAW_LATENCY, PRInt32(drawLatency.ToMicroseconds())); // clear the value of mDrawStartTime mDrawStartTime = TimeStamp(); } return NS_OK; }
FrameAnimator::RefreshResult FrameAnimator::AdvanceFrame(TimeStamp aTime) { NS_ASSERTION(aTime <= TimeStamp::Now(), "Given time appears to be in the future"); uint32_t currentFrameIndex = mCurrentAnimationFrameIndex; uint32_t nextFrameIndex = currentFrameIndex + 1; uint32_t timeout = 0; RefreshResult ret; // If we're done decoding, we know we've got everything we're going to get. // If we aren't, we only display fully-downloaded frames; everything else // gets delayed. bool canDisplay = mDoneDecoding || (mFrameBlender.RawGetFrame(nextFrameIndex) && mFrameBlender.RawGetFrame(nextFrameIndex)->ImageComplete()); if (!canDisplay) { // Uh oh, the frame we want to show is currently being decoded (partial) // Wait until the next refresh driver tick and try again return ret; } else { // If we're done decoding the next frame, go ahead and display it now and // reinit with the next frame's delay time. if (mFrameBlender.GetNumFrames() == nextFrameIndex) { // End of Animation, unless we are looping forever // If animation mode is "loop once", it's time to stop animating if (mAnimationMode == imgIContainer::kLoopOnceAnimMode || mLoopCount == 0) { ret.animationFinished = true; } nextFrameIndex = 0; if (mLoopCount > 0) { mLoopCount--; } // If we're done, exit early. if (ret.animationFinished) { return ret; } } timeout = mFrameBlender.GetFrame(nextFrameIndex)->GetTimeout(); } // Bad data if (!(timeout > 0)) { ret.animationFinished = true; ret.error = true; } if (nextFrameIndex == 0) { ret.dirtyRect = mFirstFrameRefreshArea; } else { // Change frame if (!mFrameBlender.DoBlend(&ret.dirtyRect, currentFrameIndex, nextFrameIndex)) { // something went wrong, move on to next NS_WARNING("FrameAnimator::AdvanceFrame(): Compositing of frame failed"); mFrameBlender.RawGetFrame(nextFrameIndex)->SetCompositingFailed(true); mCurrentAnimationFrameTime = GetCurrentImgFrameEndTime(); mCurrentAnimationFrameIndex = nextFrameIndex; ret.error = true; return ret; } mFrameBlender.RawGetFrame(nextFrameIndex)->SetCompositingFailed(false); } mCurrentAnimationFrameTime = GetCurrentImgFrameEndTime(); // If we can get closer to the current time by a multiple of the image's loop // time, we should. uint32_t loopTime = GetSingleLoopTime(); if (loopTime > 0) { TimeDuration delay = aTime - mCurrentAnimationFrameTime; if (delay.ToMilliseconds() > loopTime) { // Explicitly use integer division to get the floor of the number of // loops. uint32_t loops = static_cast<uint32_t>(delay.ToMilliseconds()) / loopTime; mCurrentAnimationFrameTime += TimeDuration::FromMilliseconds(loops * loopTime); } } // Set currentAnimationFrameIndex at the last possible moment mCurrentAnimationFrameIndex = nextFrameIndex; // If we're here, we successfully advanced the frame. ret.frameAdvanced = true; return ret; }
void nsTimerImpl::Fire() { if (mCanceled) { return; } PROFILER_LABEL("Timer", "Fire", js::ProfileEntry::Category::OTHER); TimeStamp now = TimeStamp::Now(); if (MOZ_LOG_TEST(GetTimerLog(), LogLevel::Debug)) { TimeDuration a = now - mStart; // actual delay in intervals TimeDuration b = TimeDuration::FromMilliseconds(mDelay); // expected delay in intervals TimeDuration delta = (a > b) ? a - b : b - a; uint32_t d = delta.ToMilliseconds(); // delta in ms sDeltaSum += d; sDeltaSumSquared += double(d) * double(d); sDeltaNum++; MOZ_LOG(GetTimerLog(), LogLevel::Debug, ("[this=%p] expected delay time %4ums\n", this, mDelay)); MOZ_LOG(GetTimerLog(), LogLevel::Debug, ("[this=%p] actual delay time %fms\n", this, a.ToMilliseconds())); MOZ_LOG(GetTimerLog(), LogLevel::Debug, ("[this=%p] (mType is %d) -------\n", this, mType)); MOZ_LOG(GetTimerLog(), LogLevel::Debug, ("[this=%p] delta %4dms\n", this, (a > b) ? (int32_t)d : -(int32_t)d)); mStart = mStart2; mStart2 = TimeStamp(); } TimeStamp timeout = mTimeout; if (IsRepeatingPrecisely()) { // Precise repeating timers advance mTimeout by mDelay without fail before // calling Fire(). timeout -= TimeDuration::FromMilliseconds(mDelay); } if (mCallbackType == CallbackType::Interface) { mTimerCallbackWhileFiring = mCallback.i; } mFiring = true; // Handle callbacks that re-init the timer, but avoid leaking. // See bug 330128. CallbackUnion callback = mCallback; CallbackType callbackType = mCallbackType; if (callbackType == CallbackType::Interface) { NS_ADDREF(callback.i); } else if (callbackType == CallbackType::Observer) { NS_ADDREF(callback.o); } ReleaseCallback(); if (MOZ_LOG_TEST(GetTimerFiringsLog(), LogLevel::Debug)) { LogFiring(callbackType, callback); } switch (callbackType) { case CallbackType::Function: callback.c(this, mClosure); break; case CallbackType::Interface: callback.i->Notify(this); break; case CallbackType::Observer: callback.o->Observe(static_cast<nsITimer*>(this), NS_TIMER_CALLBACK_TOPIC, nullptr); break; default: ; } // If the callback didn't re-init the timer, and it's not a one-shot timer, // restore the callback state. if (mCallbackType == CallbackType::Unknown && mType != TYPE_ONE_SHOT && !mCanceled) { mCallback = callback; mCallbackType = callbackType; } else { // The timer was a one-shot, or the callback was reinitialized. if (callbackType == CallbackType::Interface) { NS_RELEASE(callback.i); } else if (callbackType == CallbackType::Observer) { NS_RELEASE(callback.o); } } mFiring = false; mTimerCallbackWhileFiring = nullptr; MOZ_LOG(GetTimerLog(), LogLevel::Debug, ("[this=%p] Took %fms to fire timer callback\n", this, (TimeStamp::Now() - now).ToMilliseconds())); // Reschedule repeating timers, but make sure that we aren't armed already // (which can happen if the callback reinitialized the timer). if (IsRepeating() && !mArmed) { if (mType == TYPE_REPEATING_SLACK) { SetDelayInternal(mDelay); // force mTimeout to be recomputed. For } // REPEATING_PRECISE_CAN_SKIP timers this has // already happened. if (gThread) { gThread->AddTimer(this); } } }
void VRDisplayHost::NotifyVSync() { /** * We will trigger a new frame immediately after a successful frame texture * submission. If content fails to call VRDisplay.submitFrame after * kVRDisplayRAFMaxDuration milliseconds has elapsed since the last * VRDisplay.requestAnimationFrame, we act as a "watchdog" and kick-off * a new VRDisplay.requestAnimationFrame to avoid a render loop stall and * to give content a chance to recover. * * If the lower level VR platform API's are rejecting submitted frames, * such as when the Oculus "Health and Safety Warning" is displayed, * we will not kick off the next frame immediately after VRDisplay.submitFrame * as it would result in an unthrottled render loop that would free run at * potentially extreme frame rates. To ensure that content has a chance to * resume its presentation when the frames are accepted once again, we rely * on this "watchdog" to act as a VR refresh driver cycling at a rate defined * by kVRDisplayRAFMaxDuration. * * kVRDisplayRAFMaxDuration is the number of milliseconds since last frame * start before triggering a new frame. When content is failing to submit * frames on time or the lower level VR platform API's are rejecting frames, * kVRDisplayRAFMaxDuration determines the rate at which RAF callbacks * will be called. * * This number must be larger than the slowest expected frame time during * normal VR presentation, but small enough not to break content that * makes assumptions of reasonably minimal VSync rate. * * The slowest expected refresh rate for a VR display currently is an * Oculus CV1 when ASW (Asynchronous Space Warp) is enabled, at 45hz. * A kVRDisplayRAFMaxDuration value of 50 milliseconds results in a 20hz * rate, which avoids inadvertent triggering of the watchdog during * Oculus ASW even if every second frame is dropped. */ const double kVRDisplayRAFMaxDuration = 50; bool bShouldStartFrame = false; if (mDisplayInfo.mPresentingGroups == 0) { // If this display isn't presenting, refresh the sensors and trigger // VRDisplay.requestAnimationFrame at the normal 2d display refresh rate. bShouldStartFrame = true; } else { // If content fails to call VRDisplay.submitFrame, we must eventually // time-out and trigger a new frame. if (mLastFrameStart.IsNull()) { bShouldStartFrame = true; } else { TimeDuration duration = TimeStamp::Now() - mLastFrameStart; if (duration.ToMilliseconds() > kVRDisplayRAFMaxDuration) { bShouldStartFrame = true; } } } if (bShouldStartFrame) { VRManager *vm = VRManager::Get(); MOZ_ASSERT(vm); vm->NotifyVRVsync(mDisplayInfo.mDisplayID); } }
RasterImage::Draw(gfxContext* aContext, const IntSize& aSize, const ImageRegion& aRegion, uint32_t aWhichFrame, SamplingFilter aSamplingFilter, const Maybe<SVGImageContext>& /*aSVGContext - ignored*/, uint32_t aFlags, float aOpacity) { if (aWhichFrame > FRAME_MAX_VALUE) { return DrawResult::BAD_ARGS; } if (mError) { return DrawResult::BAD_IMAGE; } // Illegal -- you can't draw with non-default decode flags. // (Disabling colorspace conversion might make sense to allow, but // we don't currently.) if (ToSurfaceFlags(aFlags) != DefaultSurfaceFlags()) { return DrawResult::BAD_ARGS; } if (!aContext) { return DrawResult::BAD_ARGS; } if (IsUnlocked()) { SendOnUnlockedDraw(aFlags); } // If we're not using SamplingFilter::GOOD, we shouldn't high-quality scale or // downscale during decode. uint32_t flags = aSamplingFilter == SamplingFilter::GOOD ? aFlags : aFlags & ~FLAG_HIGH_QUALITY_SCALING; DrawableSurface surface = LookupFrame(aSize, flags, ToPlaybackType(aWhichFrame)); if (!surface) { // Getting the frame (above) touches the image and kicks off decoding. if (mDrawStartTime.IsNull()) { mDrawStartTime = TimeStamp::Now(); } return DrawResult::NOT_READY; } bool shouldRecordTelemetry = !mDrawStartTime.IsNull() && surface->IsFinished(); auto result = DrawInternal(Move(surface), aContext, aSize, aRegion, aSamplingFilter, flags, aOpacity); if (shouldRecordTelemetry) { TimeDuration drawLatency = TimeStamp::Now() - mDrawStartTime; Telemetry::Accumulate(Telemetry::IMAGE_DECODE_ON_DRAW_LATENCY, int32_t(drawLatency.ToMicroseconds())); mDrawStartTime = TimeStamp(); } return result; }