/* * Copyright 2023 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 #include #include #include #include #include #include #include "Model.h" #include "Shader.h" #include "external/android_native_app_glue.h" struct android_app; struct FrameStats { // Median of the durations int64_t medianWorkDuration; // Median of the intervals int64_t medianFrameInterval; // Standard deviation of a given run double deviation; // The total number of frames that exceeded target std::optional exceededCount; // The percent of frames that exceeded target std::optional exceededFraction; // Efficiency of a given run is calculated by how close to min(target, baseline) the median is std::optional efficiency; }; class Renderer { public: /*! * @param pApp the android_app this Renderer belongs to, needed to configure GL */ inline Renderer(android_app *pApp) : app_(pApp), display_(EGL_NO_DISPLAY), surface_(EGL_NO_SURFACE), context_(EGL_NO_CONTEXT), width_(0), height_(0), shaderNeedsNewProjectionMatrix_(true) { initRenderer(); } virtual ~Renderer(); /*! * Renders all the models in the renderer, returns time spent waiting for CPU work * to finish. */ jlong render(); void startHintSession(std::vector &threads, int64_t target); void closeHintSession(); void reportActualWorkDuration(int64_t duration); void updateTargetWorkDuration(int64_t target); bool isHintSessionRunning(); int64_t getTargetWorkDuration(); /*! * Sets the number of android "heads" in the scene, these are used to create a synthetic * workload that scales with performance, and by adjusting the number of them, the test can * adjust the amount of stress to place the system under. */ void setNumHeads(int headCount); /*! * Adds an entry to the final result map that gets passed up to the Java side of the app, and * eventually to the test runner. */ void addResult(std::string name, std::string value); /*! * Retrieve the results map. */ std::map &getResults(); /*! * Informs the test whether ADPF is supported on a given device. */ bool getAdpfSupported(); /* * Finds the test settings that best match this device, and returns the * duration of the frame's work */ double calibrate(int &events, android_poll_source *pSource); /*! * Sets the baseline median, used to determine efficiency score */ void setBaselineMedian(int64_t median); /*! * Calculates the above frame stats for a given run */ FrameStats getFrameStats(std::vector &durations, std::vector &intervals, std::string &testName); private: /*! * Performs necessary OpenGL initialization. Customize this if you want to change your EGL * context or application-wide settings. */ void initRenderer(); /*! * @brief we have to check every frame to see if the framebuffer has changed in size. If it has, * update the viewport accordingly */ void updateRenderArea(); /*! * Adds an android "head" to the scene. */ void addHead(); android_app *app_; EGLDisplay display_; EGLSurface surface_; EGLContext context_; EGLint width_; EGLint height_; APerformanceHintSession *hintSession_ = nullptr; APerformanceHintManager *hintManager_ = nullptr; int64_t lastTarget_ = 0; int64_t baselineMedian_ = 0; bool shaderNeedsNewProjectionMatrix_; std::unique_ptr shader_; std::vector heads_; // Hold on to the results object in the renderer, so // we can reach the data anywhere in the rendering step. std::map results_; };