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

#pragma once

#include <stdint.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <jni.h>

#define MAX_FRAME_BUCKETS 6


#ifdef __cplusplus
extern "C" {
#endif

// If an app wishes to use the Android choreographer to provide ticks to Swappy, it can
// call the function below.
// This function *must* be called before the first Swappy_swap() call.
// Afterwards, call this function every choreographer tick.
void Swappy_onChoreographer(int64_t frameTimeNanos);

// Pass callbacks to be called each frame to trace execution
struct SwappyTracer {
    void (*preWait)(void*);
    void (*postWait)(void*);
    void (*preSwapBuffers)(void*);
    void (*postSwapBuffers)(void*, long desiredPresentationTimeMillis);
    void (*startFrame)(void*, int currentFrame, long currentFrameTimeStampMillis);
    void* userData;
    void (*swapIntervalChanged)(void*);

};
void Swappy_injectTracer(const SwappyTracer *t);

// Toggle auto-swap interval detection on/off
// By default, Swappy will adjust the swap interval based on actual frame rendering time.
// If an app wants to override the swap interval calculated by Swappy, it can call
// Swappy_setSwapIntervalNS. This will temporarily override Swappy's frame timings but, unless
// Swappy_setAutoSwapInterval(false) is called, the timings will continue to be be updated
// dynamically, so the swap interval may change.
void Swappy_setAutoSwapInterval(bool enabled);

// Toggle auto-pipeline mode on/off
// By default, if auto-swap interval is on, auto-pipelining is on and Swappy will try to reduce
// latency by scheduling cpu and gpu work in the same pipeline stage, if it fits.
void Swappy_setAutoPipelineMode(bool enabled);

// Toggle statistics collection on/off
// By default, stats collection is off and there is no overhead related to stats.
// An app can turn on stats collection by calling Swappy_setStatsMode(true).
// Then, the app is expected to call Swappy_recordFrameStart for each frame before starting to
// do any CPU related work.
// Stats will be logged to logcat with a 'FrameStatistics' tag.
// An app can get the stats by calling Swappy_getStats.
void Swappy_enableStats(bool enabled);

struct Swappy_Stats {
    // total frames swapped by swappy
    uint64_t totalFrames;

    // Histogram of the number of screen refreshes a frame waited in the compositor queue after
    // rendering was completed.
    // for example:
    //     if a frame waited 2 refresh periods in the compositor queue after rendering was done,
    //     the frame will be counted in idleFrames[2]
    uint64_t idleFrames[MAX_FRAME_BUCKETS];

    // Histogram of the number of screen refreshes passed between the requested presentation time
    // and the actual present time.
    // for example:
    //     if a frame was presented 2 refresh periods after the requested timestamp swappy set,
    //     the frame will be counted in lateFrames[2]
    uint64_t lateFrames[MAX_FRAME_BUCKETS];

    // Histogram of the number of screen refreshes passed between two consecutive frames
    // for example:
    //     if frame N was presented 2 refresh periods after frame N-1
    //     frame N will be counted in offsetFromPreviousFrame[2]
    uint64_t offsetFromPreviousFrame[MAX_FRAME_BUCKETS];

    // Histogram of the number of screen refreshes passed between the call to
    // Swappy_recordFrameStart and the actual present time.
    //     if a frame was presented 2 refresh periods after the call to Swappy_recordFrameStart
    //     the frame will be counted in latencyFrames[2]
    uint64_t latencyFrames[MAX_FRAME_BUCKETS];
};

void Swappy_recordFrameStart(EGLDisplay display, EGLSurface surface);

void Swappy_getStats(Swappy_Stats *);

#ifdef __cplusplus
};
#endif