xref: /aosp_15_r20/cts/hostsidetests/adpf/app/hintsession/src/cpp/Renderer.h (revision b7c941bb3fa97aba169d73cee0bed2de8ac964bf)
1 /*
2  * Copyright 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #pragma once
17 
18 #include <EGL/egl.h>
19 #include <android/performance_hint.h>
20 #include <jni.h>
21 
22 #include <chrono>
23 #include <map>
24 #include <memory>
25 #include <optional>
26 
27 #include "Model.h"
28 #include "Shader.h"
29 #include "external/android_native_app_glue.h"
30 
31 struct android_app;
32 
33 struct FrameStats {
34     // Median of the durations
35     int64_t medianWorkDuration;
36     // Median of the intervals
37     int64_t medianFrameInterval;
38     // Standard deviation of a given run
39     double deviation;
40     // The total number of frames that exceeded target
41     std::optional<int64_t> exceededCount;
42     // The percent of frames that exceeded target
43     std::optional<double> exceededFraction;
44     // Efficiency of a given run is calculated by how close to min(target, baseline) the median is
45     std::optional<double> efficiency;
46 };
47 
48 class Renderer {
49 public:
50     /*!
51      * @param pApp the android_app this Renderer belongs to, needed to configure GL
52      */
Renderer(android_app * pApp)53     inline Renderer(android_app *pApp)
54           : app_(pApp),
55             display_(EGL_NO_DISPLAY),
56             surface_(EGL_NO_SURFACE),
57             context_(EGL_NO_CONTEXT),
58             width_(0),
59             height_(0),
60             shaderNeedsNewProjectionMatrix_(true) {
61         initRenderer();
62     }
63 
64     virtual ~Renderer();
65 
66     /*!
67      * Renders all the models in the renderer, returns time spent waiting for CPU work
68      * to finish.
69      */
70     jlong render();
71 
72     /*!
73      * Attempts to start hint session and returns whether ADPF is supported on a given device.
74      */
75     bool startHintSession(std::vector<pid_t> &threads, int64_t target);
76     void closeHintSession();
77     void reportActualWorkDuration(int64_t duration);
78     void updateTargetWorkDuration(int64_t target);
79     bool isHintSessionRunning();
80     int64_t getTargetWorkDuration();
81 
82     /*!
83      * Sets the number of android "heads" in the scene, these are used to create a synthetic
84      * workload that scales with performance, and by adjusting the number of them, the test can
85      * adjust the amount of stress to place the system under.
86      */
87     void setNumHeads(int headCount);
88 
89     /*!
90      * Adds an entry to the final result map that gets passed up to the Java side of the app, and
91      * eventually to the test runner.
92      */
93     void addResult(std::string name, std::string value);
94 
95     /*!
96      * Retrieve the results map.
97      */
98     std::map<std::string, std::string> &getResults();
99 
100     /*
101      * Finds the test settings that best match this device, and returns the
102      * duration of the frame's work
103      */
104     double calibrate(int &events, android_poll_source *pSource);
105 
106     /*!
107      * Sets the baseline median, used to determine efficiency score
108      */
109     void setBaselineMedian(int64_t median);
110 
111     /*!
112      * Calculates the above frame stats for a given run
113      */
114     FrameStats getFrameStats(std::vector<int64_t> &durations, std::vector<int64_t> &intervals,
115                              std::string &testName);
116 
117 private:
118     /*!
119      * Performs necessary OpenGL initialization. Customize this if you want to change your EGL
120      * context or application-wide settings.
121      */
122     void initRenderer();
123 
124     /*!
125      * @brief we have to check every frame to see if the framebuffer has changed in size. If it has,
126      * update the viewport accordingly
127      */
128     void updateRenderArea();
129 
130     /*!
131      * Adds an android "head" to the scene.
132      */
133     void addHead();
134 
135     android_app *app_;
136     EGLDisplay display_;
137     EGLSurface surface_;
138     EGLContext context_;
139     EGLint width_;
140     EGLint height_;
141     APerformanceHintSession *hintSession_ = nullptr;
142     APerformanceHintManager *hintManager_ = nullptr;
143     int64_t lastTarget_ = 0;
144     int64_t baselineMedian_ = 0;
145 
146     bool shaderNeedsNewProjectionMatrix_;
147 
148     std::unique_ptr<Shader> shader_;
149     std::vector<Model> heads_;
150 
151     // Hold on to the results object in the renderer, so
152     // we can reach the data anywhere in the rendering step.
153     std::map<std::string, std::string> results_;
154 };
155