|  | /* | 
|  | * Copyright 2019 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 "PhaseOffsets.h" | 
|  |  | 
|  | #include <cutils/properties.h> | 
|  |  | 
|  | #include "SurfaceFlingerProperties.h" | 
|  |  | 
|  | namespace android { | 
|  | using namespace android::sysprop; | 
|  |  | 
|  | namespace scheduler { | 
|  |  | 
|  | using RefreshRateType = RefreshRateConfigs::RefreshRateType; | 
|  | PhaseOffsets::~PhaseOffsets() = default; | 
|  |  | 
|  | namespace impl { | 
|  | PhaseOffsets::PhaseOffsets() { | 
|  | int64_t vsyncPhaseOffsetNs = vsync_event_phase_offset_ns(1000000); | 
|  |  | 
|  | int64_t sfVsyncPhaseOffsetNs = vsync_sf_event_phase_offset_ns(1000000); | 
|  |  | 
|  | char value[PROPERTY_VALUE_MAX]; | 
|  | property_get("debug.sf.early_phase_offset_ns", value, "-1"); | 
|  | const int earlySfOffsetNs = atoi(value); | 
|  |  | 
|  | property_get("debug.sf.early_gl_phase_offset_ns", value, "-1"); | 
|  | const int earlyGlSfOffsetNs = atoi(value); | 
|  |  | 
|  | property_get("debug.sf.early_app_phase_offset_ns", value, "-1"); | 
|  | const int earlyAppOffsetNs = atoi(value); | 
|  |  | 
|  | property_get("debug.sf.early_gl_app_phase_offset_ns", value, "-1"); | 
|  | const int earlyGlAppOffsetNs = atoi(value); | 
|  |  | 
|  | property_get("debug.sf.high_fps_early_phase_offset_ns", value, "-1"); | 
|  | const int highFpsEarlySfOffsetNs = atoi(value); | 
|  |  | 
|  | property_get("debug.sf.high_fps_early_gl_phase_offset_ns", value, "-1"); | 
|  | const int highFpsEarlyGlSfOffsetNs = atoi(value); | 
|  |  | 
|  | property_get("debug.sf.high_fps_early_app_phase_offset_ns", value, "-1"); | 
|  | const int highFpsEarlyAppOffsetNs = atoi(value); | 
|  |  | 
|  | property_get("debug.sf.high_fps_early_gl_app_phase_offset_ns", value, "-1"); | 
|  | const int highFpsEarlyGlAppOffsetNs = atoi(value); | 
|  |  | 
|  | // TODO(b/122905996): Define these in device.mk. | 
|  | property_get("debug.sf.high_fps_late_app_phase_offset_ns", value, "2000000"); | 
|  | const int highFpsLateAppOffsetNs = atoi(value); | 
|  |  | 
|  | property_get("debug.sf.high_fps_late_sf_phase_offset_ns", value, "1000000"); | 
|  | const int highFpsLateSfOffsetNs = atoi(value); | 
|  |  | 
|  | // Below defines the threshold when an offset is considered to be negative, i.e. targeting | 
|  | // for the N+2 vsync instead of N+1. This means that: | 
|  | // For offset < threshold, SF wake up (vsync_duration - offset) before HW vsync. | 
|  | // For offset >= threshold, SF wake up (2 * vsync_duration - offset) before HW vsync. | 
|  | property_get("debug.sf.phase_offset_threshold_for_next_vsync_ns", value, "-1"); | 
|  | const int phaseOffsetThresholdForNextVsyncNs = atoi(value); | 
|  |  | 
|  | Offsets defaultOffsets; | 
|  | Offsets highFpsOffsets; | 
|  | defaultOffsets.early = {RefreshRateType::DEFAULT, | 
|  | earlySfOffsetNs != -1 ? earlySfOffsetNs : sfVsyncPhaseOffsetNs, | 
|  | earlyAppOffsetNs != -1 ? earlyAppOffsetNs : vsyncPhaseOffsetNs}; | 
|  | defaultOffsets.earlyGl = {RefreshRateType::DEFAULT, | 
|  | earlyGlSfOffsetNs != -1 ? earlyGlSfOffsetNs : sfVsyncPhaseOffsetNs, | 
|  | earlyGlAppOffsetNs != -1 ? earlyGlAppOffsetNs : vsyncPhaseOffsetNs}; | 
|  | defaultOffsets.late = {RefreshRateType::DEFAULT, sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs}; | 
|  |  | 
|  | highFpsOffsets.early = {RefreshRateType::PERFORMANCE, | 
|  | highFpsEarlySfOffsetNs != -1 ? highFpsEarlySfOffsetNs | 
|  | : highFpsLateSfOffsetNs, | 
|  | highFpsEarlyAppOffsetNs != -1 ? highFpsEarlyAppOffsetNs | 
|  | : highFpsLateAppOffsetNs}; | 
|  | highFpsOffsets.earlyGl = {RefreshRateType::PERFORMANCE, | 
|  | highFpsEarlyGlSfOffsetNs != -1 ? highFpsEarlyGlSfOffsetNs | 
|  | : highFpsLateSfOffsetNs, | 
|  | highFpsEarlyGlAppOffsetNs != -1 ? highFpsEarlyGlAppOffsetNs | 
|  | : highFpsLateAppOffsetNs}; | 
|  | highFpsOffsets.late = {RefreshRateType::PERFORMANCE, highFpsLateSfOffsetNs, | 
|  | highFpsLateAppOffsetNs}; | 
|  |  | 
|  | mOffsets.insert({RefreshRateType::POWER_SAVING, defaultOffsets}); | 
|  | mOffsets.insert({RefreshRateType::DEFAULT, defaultOffsets}); | 
|  | mOffsets.insert({RefreshRateType::PERFORMANCE, highFpsOffsets}); | 
|  |  | 
|  | mOffsetThresholdForNextVsync = phaseOffsetThresholdForNextVsyncNs != -1 | 
|  | ? phaseOffsetThresholdForNextVsyncNs | 
|  | : std::numeric_limits<nsecs_t>::max(); | 
|  | } | 
|  |  | 
|  | PhaseOffsets::Offsets PhaseOffsets::getOffsetsForRefreshRate( | 
|  | android::scheduler::RefreshRateConfigs::RefreshRateType refreshRateType) const { | 
|  | return mOffsets.at(refreshRateType); | 
|  | } | 
|  |  | 
|  | void PhaseOffsets::dump(std::string& result) const { | 
|  | const auto [early, earlyGl, late] = getCurrentOffsets(); | 
|  | base::StringAppendF(&result, | 
|  | "         app phase: %9" PRId64 " ns\t         SF phase: %9" PRId64 " ns\n" | 
|  | "   early app phase: %9" PRId64 " ns\t   early SF phase: %9" PRId64 " ns\n" | 
|  | "GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64 " ns\n", | 
|  | late.app, late.sf, early.app, early.sf, earlyGl.app, earlyGl.sf); | 
|  | } | 
|  |  | 
|  | nsecs_t PhaseOffsets::getCurrentAppOffset() { | 
|  | return getCurrentOffsets().late.app; | 
|  | } | 
|  |  | 
|  | nsecs_t PhaseOffsets::getCurrentSfOffset() { | 
|  | return getCurrentOffsets().late.sf; | 
|  | } | 
|  |  | 
|  | } // namespace impl | 
|  | } // namespace scheduler | 
|  | } // namespace android |