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 void startHintSession(std::vector<pid_t> &threads, int64_t target); 73 void closeHintSession(); 74 void reportActualWorkDuration(int64_t duration); 75 void updateTargetWorkDuration(int64_t target); 76 bool isHintSessionRunning(); 77 int64_t getTargetWorkDuration(); 78 79 /*! 80 * Sets the number of android "heads" in the scene, these are used to create a synthetic 81 * workload that scales with performance, and by adjusting the number of them, the test can 82 * adjust the amount of stress to place the system under. 83 */ 84 void setNumHeads(int headCount); 85 86 /*! 87 * Adds an entry to the final result map that gets passed up to the Java side of the app, and 88 * eventually to the test runner. 89 */ 90 void addResult(std::string name, std::string value); 91 92 /*! 93 * Retrieve the results map. 94 */ 95 std::map<std::string, std::string> &getResults(); 96 97 /*! 98 * Informs the test whether ADPF is supported on a given device. 99 */ 100 bool getAdpfSupported(); 101 102 /* 103 * Finds the test settings that best match this device, and returns the 104 * duration of the frame's work 105 */ 106 double calibrate(int &events, android_poll_source *pSource); 107 108 /*! 109 * Sets the baseline median, used to determine efficiency score 110 */ 111 void setBaselineMedian(int64_t median); 112 113 /*! 114 * Calculates the above frame stats for a given run 115 */ 116 FrameStats getFrameStats(std::vector<int64_t> &durations, std::vector<int64_t> &intervals, 117 std::string &testName); 118 119 private: 120 /*! 121 * Performs necessary OpenGL initialization. Customize this if you want to change your EGL 122 * context or application-wide settings. 123 */ 124 void initRenderer(); 125 126 /*! 127 * @brief we have to check every frame to see if the framebuffer has changed in size. If it has, 128 * update the viewport accordingly 129 */ 130 void updateRenderArea(); 131 132 /*! 133 * Adds an android "head" to the scene. 134 */ 135 void addHead(); 136 137 android_app *app_; 138 EGLDisplay display_; 139 EGLSurface surface_; 140 EGLContext context_; 141 EGLint width_; 142 EGLint height_; 143 APerformanceHintSession *hintSession_ = nullptr; 144 APerformanceHintManager *hintManager_ = nullptr; 145 int64_t lastTarget_ = 0; 146 int64_t baselineMedian_ = 0; 147 148 bool shaderNeedsNewProjectionMatrix_; 149 150 std::unique_ptr<Shader> shader_; 151 std::vector<Model> heads_; 152 153 // Hold on to the results object in the renderer, so 154 // we can reach the data anywhere in the rendering step. 155 std::map<std::string, std::string> results_; 156 }; 157