/*
 * 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.
 */

syntax = "proto2";
package perfetto.protos;

// Generated by SurfaceFlinger's FrameTimeline (go/adaptive-scheduling-fr).
// Used in comparing the expected timeline of a frame to the actual timeline.
// Key terms:
//    1) DisplayFrame - represents SurfaceFlinger's work on a frame(composited)
//    2) SurfaceFrame - represents App's work on its frame
//    3) Timeline = start to end of a component's(app/SF) work on a frame.
// SurfaceFlinger composites frames from many apps together, so
//    One DisplayFrame can map to N SurfaceFrame(s)
// This relationship can be reconstructed by using
//    DisplayFrame.token = SurfaceFrame.display_frame_token
message FrameTimelineEvent {
  // Specifies the reason(s) most likely to have caused the jank.
  // Used as a bitmask.
  enum JankType {
    JANK_UNSPECIFIED = 0;
    JANK_NONE = 1;
    JANK_SF_SCHEDULING = 2;
    JANK_PREDICTION_ERROR = 4;
    JANK_DISPLAY_HAL = 8;
    JANK_SF_CPU_DEADLINE_MISSED = 16;
    JANK_SF_GPU_DEADLINE_MISSED = 32;
    JANK_APP_DEADLINE_MISSED = 64;
    JANK_BUFFER_STUFFING = 128;
    JANK_UNKNOWN = 256;
    JANK_SF_STUFFING = 512;
  };

  // Specifies how a frame was presented on screen w.r.t. timing.
  // Can be different for SurfaceFrame and DisplayFrame.
  enum PresentType {
    PRESENT_UNSPECIFIED = 0;
    PRESENT_ON_TIME = 1;
    PRESENT_LATE = 2;
    PRESENT_EARLY = 3;
    PRESENT_DROPPED = 4;
    PRESENT_UNKNOWN = 5;
  };

  // Specifies if the predictions for the frame are still valid, expired or
  // unknown.
  enum PredictionType {
    PREDICTION_UNSPECIFIED = 0;
    PREDICTION_VALID = 1;
    PREDICTION_EXPIRED = 2;
    PREDICTION_UNKNOWN = 3;
  };

  // Indicates the start of expected timeline slice for SurfaceFrames.
  message ExpectedSurfaceFrameStart {
    // Cookie used to correlate between the start and end messages of the same
    // frame. Since all values except the ts are same for start and end, cookie
    // helps in preventing redundant data transmission.
    // The same cookie is used only by start and end messages of a single frame
    // and is otherwise unique.
    optional int64 cookie = 1;

    // Token received by the app for its work. Can be shared between multiple
    // layers of the same app (example: pip mode).
    optional int64 token = 2;
    // The corresponding DisplayFrame token is required to link the App's work
    // with SurfaceFlinger's work. Many SurfaceFrames can be mapped to a single
    // DisplayFrame.
    // this.display_frame_token = DisplayFrame.token
    optional int64 display_frame_token = 3;

    // Pid of the app. Used in creating the timeline tracks (and slices) inside
    // the respective process track group.
    optional int32 pid = 4;
    optional string layer_name = 5;
  };

  // Indicates the start of actual timeline slice for SurfaceFrames. Also
  // includes the jank information.
  message ActualSurfaceFrameStart {
    // Cookie used to correlate between the start and end messages of the same
    // frame. Since all values except the ts are same for start and end, cookie
    // helps in preventing redundant data transmission.
    // The same cookie is used only by start and end messages of a single frame
    // and is otherwise unique.
    optional int64 cookie = 1;

    // Token received by the app for its work. Can be shared between multiple
    // layers of the same app (example: pip mode).
    optional int64 token = 2;
    // The corresponding DisplayFrame token is required to link the App's work
    // with SurfaceFlinger's work. Many SurfaceFrames can be mapped to a single
    // DisplayFrame.
    // this.display_frame_token = DisplayFrame.token
    optional int64 display_frame_token = 3;

    // Pid of the app. Used in creating the timeline tracks (and slices) inside
    // the respective process track group.
    optional int32 pid = 4;
    optional string layer_name = 5;

    optional PresentType present_type = 6;
    optional bool on_time_finish = 7;
    optional bool gpu_composition = 8;
    // A bitmask of JankType. More than one reason can be attributed to a janky
    // frame.
    optional int32 jank_type = 9;
    optional PredictionType prediction_type = 10;
    optional bool is_buffer = 11;
  };

  // Indicates the start of expected timeline slice for DisplayFrames.
  message ExpectedDisplayFrameStart {
    // Cookie used to correlate between the start and end messages of the same
    // frame. Since all values except the ts are same for start and end, cookie
    // helps in preventing redundant data transmission.
    // The same cookie is used only by start and end messages of a single frame
    // and is otherwise unique.
    optional int64 cookie = 1;

    // Token received by SurfaceFlinger for its work
    // this.token = SurfaceFrame.display_frame_token
    optional int64 token = 2;

    // Pid of SurfaceFlinger. Used in creating the timeline tracks (and slices)
    // inside the SurfaceFlinger process group.
    optional int32 pid = 3;
  };

  // Indicates the start of actual timeline slice for DisplayFrames. Also
  // includes the jank information.
  message ActualDisplayFrameStart {
    // Cookie used to correlate between the start and end messages of the same
    // frame. Since all values except the ts are same for start and end, cookie
    // helps in preventing redundant data transmission.
    // The same cookie is used only by start and end messages of a single frame
    // and is otherwise unique.
    optional int64 cookie = 1;

    // Token received by SurfaceFlinger for its work
    // this.token = SurfaceFrame.display_frame_token
    optional int64 token = 2;

    // Pid of SurfaceFlinger. Used in creating the timeline tracks (and slices)
    // inside the SurfaceFlinger process group.
    optional int32 pid = 3;

    optional PresentType present_type = 4;
    optional bool on_time_finish = 5;
    optional bool gpu_composition = 6;
    // A bitmask of JankType. More than one reason can be attributed to a janky
    // frame.
    optional int32 jank_type = 7;
    optional PredictionType prediction_type = 8;
  };

  // FrameEnd just sends the cookie to indicate that the corresponding
  // <display/surface>frame slice's end.
  message FrameEnd { optional int64 cookie = 1; };

  oneof event {
    ExpectedDisplayFrameStart expected_display_frame_start = 1;
    ActualDisplayFrameStart actual_display_frame_start = 2;

    ExpectedSurfaceFrameStart expected_surface_frame_start = 3;
    ActualSurfaceFrameStart actual_surface_frame_start = 4;

    FrameEnd frame_end = 5;
  }
}
