Android GLSurfaceView, GL20 - ~ 15 мс потеряно в Renderer.onDrawFrame - PullRequest
0 голосов
/ 11 марта 2020

Я обнаружил кое-что интересное на Android Gl20, которое мне удалось воспроизвести в "Hello Gl20" Android Studio, и я хотел бы услышать любые мнения по этому вопросу.

В двух словах, на S5 (и других устройствах) тратится ~ 15 мс при первом использовании функции gl * (я бы сказал, что контекст gl, но я просто хочу показать факты, а не свою интерпретацию).

Способ, которым я получил этот тролль мс, чтобы показать его лицо: В GLSufaceView Renderer.onDraw (на GLThread) я называю нативный забавный c GL2JNILib.step (этот dr aws простой треугольник) 2 раза и У каждого звонка свой идентификатор (int). Для первого вызова идентификатор равен 0, а для второго - 1. В собственной функции я настроил простое измерение времени на основе CLOCK_MONOTONI C. Первый вызов (вызов с идентификатором 0) занимает 16 мс, а второй вызов занимает (вызов с идентификатором 1) - 0 мс. И эта вещь повторяет следующий кадр как-то так же и т. Д.

Кроме того, в собственной функции GL2JNILib.step я объединяю команды в блоки и измеряю эти блоки по отдельности (без изменения порядка выполнения) и получается, что те ~ 15 мс, которые потрачены впустую, теряются в блоке очистки.

Вот некоторые фрагменты модификации:

GL2JNIView. java

....

    private static class Renderer implements GLSurfaceView.Renderer {
        public void onDrawFrame(GL10 gl) {
            GL2JNILib.step(0);
            GL2JNILib.step(1);
        }

...

ATime.h (простой таймер - заголовок)

#ifndef TIME_H__
#define TIME_H__

#include "ATypes.h"

namespace ATime {
    void init ();

    u64             ms ();
    f64             s();
    void            waste (u64 const wasteMs);

};

ATime. cpp (простой таймер - реализация)

#include "ATime.h"
#include <time.h>

#define CLOCK CLOCK_MONOTONIC

namespace ATime {
    long mStartSec = 0;

    void init() {
        struct timespec res;
        clock_gettime(CLOCK, &res);
        mStartSec = res.tv_sec;
    }

    u64 ms() {
        struct timespec res;
        clock_gettime(CLOCK, &res);
        u64 ms = static_cast<u64>(res.tv_sec - mStartSec) * 1000 + res.tv_nsec / 1000000;
        return ms;
    }

    f64 s() {
        struct timespec res;
        clock_gettime(CLOCK, &res);
        f64 ms = 1000.0 * (res.tv_sec - mStartSec) + (f64) res.tv_nsec / 1000000.0;
        return ms / 1000.0;
    }

    void waste(u64 const wasteMs) {
        f64 t = s();
        f64 e = t + static_cast<f64>(wasteMs) / 1000.0f;
        while (t < e){
            t = s ();
        }
    }
}

и в gl_code. cpp Я изменил функцию renderFrame (), чтобы получить id (int), и теперь она выглядит примерно так:

...
class MeasureBlock {
public:
    MeasureBlock (i32 id, char const *const tag) : mId(id), mName (tag){
        mStart = ATime::ms();
    }
    ~MeasureBlock(){
        auto duration = ATime::ms() - mStart;
        LOGI ("%s - %d duration %d", mName, mId, static_cast<u32>(duration));
    }
protected:
    u64 mStart;
    char const * const mName;
    i32 mId;
};

void renderFrame(i32 id) {
    MeasureBlock total (id, "total");

    static float grey;
    grey += 0.01f;
    if (grey > 1.0f) {
        grey = 0.0f;
    }

    {
        MeasureBlock clear (id, "clear");

        glClearColor(grey, grey, grey, 1.0f);
        checkGlError("glClearColor");
        glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
        checkGlError("glClear");
    }

    {
        MeasureBlock actualDraw(id, "actualDraw");

        glUseProgram(gProgram);
        checkGlError("glUseProgram");

        glVertexAttribPointer(gvPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, gTriangleVertices);
        checkGlError("glVertexAttribPointer");
        glEnableVertexAttribArray(gvPositionHandle);
        checkGlError("glEnableVertexAttribArray");
        glDrawArrays(GL_TRIANGLES, 0, 3);
        checkGlError("glDrawArrays");
    }
}
...

Вот результат этого волхва c afair:

...
clear - 0 duration 15
actualDraw - 0 duration 0
total - 0 duration 15
clear - 1 duration 0
actualDraw - 1 duration 0
total - 1 duration 0
...

Стоит отметить, что значение clear - 0 продолжительности, выглядит так: 13, 16, 15..15, 18 и так далее:)

Мне кажется, что контекст gl заблокирован в другой поток и GLThred должен ждать, пока не освободится контекст gl. Эта так называемая «теория», кажется, подтверждается синхронизацией на основе CLOCK_THREAD_CPUTIME_ID и отсутствием тролля в мс, показывающего его лицо в GLThread (если измерено без времени простоя или сна - в отличие от реального мира). Я имею в виду все измерения, как ожидалось, 0 мс. Я не могу обернуться, как избавиться от этого тролля, потому что осталось немного.

Забавно, на экране больше ничего нет, активность на весь экран, а 16 мс - много времени для всего этого ничего.

Есть ли у кого-нибудь какие-либо идеи, как избавиться от этих потраченных впустую мс, выкинуть мисс тролль из своего рода речи, или может принести любой тип и / или форму света к выпуск?

С большим ожиданием и признательностью,

Жан-Артур Деда.

1 Ответ

0 голосов
/ 12 марта 2020

Не берите в голову, ребята,

После еще одного эксперимента, я думаю, я понял. Окно GLThread относительно SwapBuffers на VSyn c меняется в зависимости от рабочей нагрузки GLThread + RenderThread из предыдущего кадра.

Так что большой тролль - это хорошая новость.

...