1441e847feb0e055ecb004802802cea07782ab228Andy McFadden/*
2441e847feb0e055ecb004802802cea07782ab228Andy McFadden * Copyright 2013 The Android Open Source Project
3441e847feb0e055ecb004802802cea07782ab228Andy McFadden *
4441e847feb0e055ecb004802802cea07782ab228Andy McFadden * Licensed under the Apache License, Version 2.0 (the "License");
5441e847feb0e055ecb004802802cea07782ab228Andy McFadden * you may not use this file except in compliance with the License.
6441e847feb0e055ecb004802802cea07782ab228Andy McFadden * You may obtain a copy of the License at
7441e847feb0e055ecb004802802cea07782ab228Andy McFadden *
8441e847feb0e055ecb004802802cea07782ab228Andy McFadden *      http://www.apache.org/licenses/LICENSE-2.0
9441e847feb0e055ecb004802802cea07782ab228Andy McFadden *
10441e847feb0e055ecb004802802cea07782ab228Andy McFadden * Unless required by applicable law or agreed to in writing, software
11441e847feb0e055ecb004802802cea07782ab228Andy McFadden * distributed under the License is distributed on an "AS IS" BASIS,
12441e847feb0e055ecb004802802cea07782ab228Andy McFadden * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13441e847feb0e055ecb004802802cea07782ab228Andy McFadden * See the License for the specific language governing permissions and
14441e847feb0e055ecb004802802cea07782ab228Andy McFadden * limitations under the License.
15441e847feb0e055ecb004802802cea07782ab228Andy McFadden */
16441e847feb0e055ecb004802802cea07782ab228Andy McFadden
17884989c67081190ff864419328e9e81506db67caMark Salyzyn#include <assert.h>
18884989c67081190ff864419328e9e81506db67caMark Salyzyn#include <inttypes.h>
19884989c67081190ff864419328e9e81506db67caMark Salyzyn#include <stdlib.h>
20884989c67081190ff864419328e9e81506db67caMark Salyzyn
21441e847feb0e055ecb004802802cea07782ab228Andy McFadden#define LOG_TAG "ScreenRecord"
22441e847feb0e055ecb004802802cea07782ab228Andy McFadden//#define LOG_NDEBUG 0
23441e847feb0e055ecb004802802cea07782ab228Andy McFadden#include <utils/Log.h>
24441e847feb0e055ecb004802802cea07782ab228Andy McFadden
25441e847feb0e055ecb004802802cea07782ab228Andy McFadden#include <gui/BufferQueue.h>
26441e847feb0e055ecb004802802cea07782ab228Andy McFadden#include <gui/Surface.h>
27441e847feb0e055ecb004802802cea07782ab228Andy McFadden#include <cutils/properties.h>
28441e847feb0e055ecb004802802cea07782ab228Andy McFadden#include <utils/misc.h>
29441e847feb0e055ecb004802802cea07782ab228Andy McFadden
30441e847feb0e055ecb004802802cea07782ab228Andy McFadden#include <GLES2/gl2.h>
31441e847feb0e055ecb004802802cea07782ab228Andy McFadden#include <GLES2/gl2ext.h>
32441e847feb0e055ecb004802802cea07782ab228Andy McFadden
33441e847feb0e055ecb004802802cea07782ab228Andy McFadden#include "screenrecord.h"
34441e847feb0e055ecb004802802cea07782ab228Andy McFadden#include "Overlay.h"
35441e847feb0e055ecb004802802cea07782ab228Andy McFadden#include "TextRenderer.h"
36441e847feb0e055ecb004802802cea07782ab228Andy McFadden
37441e847feb0e055ecb004802802cea07782ab228Andy McFaddenusing namespace android;
38441e847feb0e055ecb004802802cea07782ab228Andy McFadden
39441e847feb0e055ecb004802802cea07782ab228Andy McFadden// System properties to look up and display on the info screen.
40441e847feb0e055ecb004802802cea07782ab228Andy McFaddenconst char* Overlay::kPropertyNames[] = {
41441e847feb0e055ecb004802802cea07782ab228Andy McFadden        "ro.build.description",
42441e847feb0e055ecb004802802cea07782ab228Andy McFadden        // includes ro.build.id, ro.build.product, ro.build.tags, ro.build.type,
43441e847feb0e055ecb004802802cea07782ab228Andy McFadden        // and ro.build.version.release
44441e847feb0e055ecb004802802cea07782ab228Andy McFadden        "ro.product.manufacturer",
45441e847feb0e055ecb004802802cea07782ab228Andy McFadden        "ro.product.model",
46441e847feb0e055ecb004802802cea07782ab228Andy McFadden        "ro.board.platform",
47441e847feb0e055ecb004802802cea07782ab228Andy McFadden        "ro.revision",
48441e847feb0e055ecb004802802cea07782ab228Andy McFadden        "dalvik.vm.heapgrowthlimit",
49441e847feb0e055ecb004802802cea07782ab228Andy McFadden        "dalvik.vm.heapsize",
50483f59ab9fb4b2d8ab212f77a50eed0528beca58Brian Carlstrom        "persist.sys.dalvik.vm.lib.2",
51441e847feb0e055ecb004802802cea07782ab228Andy McFadden        //"ro.product.cpu.abi",
52441e847feb0e055ecb004802802cea07782ab228Andy McFadden        //"ro.bootloader",
53441e847feb0e055ecb004802802cea07782ab228Andy McFadden        //"this-never-appears!",
54441e847feb0e055ecb004802802cea07782ab228Andy McFadden};
55441e847feb0e055ecb004802802cea07782ab228Andy McFadden
56441e847feb0e055ecb004802802cea07782ab228Andy McFadden
57441e847feb0e055ecb004802802cea07782ab228Andy McFaddenstatus_t Overlay::start(const sp<IGraphicBufferProducer>& outputSurface,
58441e847feb0e055ecb004802802cea07782ab228Andy McFadden        sp<IGraphicBufferProducer>* pBufferProducer) {
59441e847feb0e055ecb004802802cea07782ab228Andy McFadden    ALOGV("Overlay::start");
60441e847feb0e055ecb004802802cea07782ab228Andy McFadden    mOutputSurface = outputSurface;
61441e847feb0e055ecb004802802cea07782ab228Andy McFadden
62441e847feb0e055ecb004802802cea07782ab228Andy McFadden    // Grab the current monotonic time and the current wall-clock time so we
63441e847feb0e055ecb004802802cea07782ab228Andy McFadden    // can map one to the other.  This allows the overlay counter to advance
64441e847feb0e055ecb004802802cea07782ab228Andy McFadden    // by the exact delay between frames, but if the wall clock gets adjusted
65441e847feb0e055ecb004802802cea07782ab228Andy McFadden    // we won't track it, which means we'll gradually go out of sync with the
66441e847feb0e055ecb004802802cea07782ab228Andy McFadden    // times in logcat.
67441e847feb0e055ecb004802802cea07782ab228Andy McFadden    mStartMonotonicNsecs = systemTime(CLOCK_MONOTONIC);
68441e847feb0e055ecb004802802cea07782ab228Andy McFadden    mStartRealtimeNsecs = systemTime(CLOCK_REALTIME);
69441e847feb0e055ecb004802802cea07782ab228Andy McFadden
707a66622c2c9250ce4ad0091195331ce4cb91a63dAndy McFadden    Mutex::Autolock _l(mMutex);
717a66622c2c9250ce4ad0091195331ce4cb91a63dAndy McFadden
72441e847feb0e055ecb004802802cea07782ab228Andy McFadden    // Start the thread.  Traffic begins immediately.
73441e847feb0e055ecb004802802cea07782ab228Andy McFadden    run("overlay");
74441e847feb0e055ecb004802802cea07782ab228Andy McFadden
75441e847feb0e055ecb004802802cea07782ab228Andy McFadden    mState = INIT;
76441e847feb0e055ecb004802802cea07782ab228Andy McFadden    while (mState == INIT) {
77441e847feb0e055ecb004802802cea07782ab228Andy McFadden        mStartCond.wait(mMutex);
78441e847feb0e055ecb004802802cea07782ab228Andy McFadden    }
79441e847feb0e055ecb004802802cea07782ab228Andy McFadden
80441e847feb0e055ecb004802802cea07782ab228Andy McFadden    if (mThreadResult != NO_ERROR) {
81441e847feb0e055ecb004802802cea07782ab228Andy McFadden        ALOGE("Failed to start overlay thread: err=%d", mThreadResult);
82441e847feb0e055ecb004802802cea07782ab228Andy McFadden        return mThreadResult;
83441e847feb0e055ecb004802802cea07782ab228Andy McFadden    }
847a66622c2c9250ce4ad0091195331ce4cb91a63dAndy McFadden    assert(mState == RUNNING);
85441e847feb0e055ecb004802802cea07782ab228Andy McFadden
86441e847feb0e055ecb004802802cea07782ab228Andy McFadden    ALOGV("Overlay::start successful");
87b278f5e70c001391779525fb4d3b024503ba9466Dan Stoza    *pBufferProducer = mProducer;
88441e847feb0e055ecb004802802cea07782ab228Andy McFadden    return NO_ERROR;
89441e847feb0e055ecb004802802cea07782ab228Andy McFadden}
90441e847feb0e055ecb004802802cea07782ab228Andy McFadden
91441e847feb0e055ecb004802802cea07782ab228Andy McFaddenstatus_t Overlay::stop() {
92441e847feb0e055ecb004802802cea07782ab228Andy McFadden    ALOGV("Overlay::stop");
93441e847feb0e055ecb004802802cea07782ab228Andy McFadden    Mutex::Autolock _l(mMutex);
94441e847feb0e055ecb004802802cea07782ab228Andy McFadden    mState = STOPPING;
95441e847feb0e055ecb004802802cea07782ab228Andy McFadden    mEventCond.signal();
96441e847feb0e055ecb004802802cea07782ab228Andy McFadden    return NO_ERROR;
97441e847feb0e055ecb004802802cea07782ab228Andy McFadden}
98441e847feb0e055ecb004802802cea07782ab228Andy McFadden
99441e847feb0e055ecb004802802cea07782ab228Andy McFaddenbool Overlay::threadLoop() {
100441e847feb0e055ecb004802802cea07782ab228Andy McFadden    Mutex::Autolock _l(mMutex);
101441e847feb0e055ecb004802802cea07782ab228Andy McFadden
102441e847feb0e055ecb004802802cea07782ab228Andy McFadden    mThreadResult = setup_l();
103441e847feb0e055ecb004802802cea07782ab228Andy McFadden
104441e847feb0e055ecb004802802cea07782ab228Andy McFadden    if (mThreadResult != NO_ERROR) {
105441e847feb0e055ecb004802802cea07782ab228Andy McFadden        ALOGW("Aborting overlay thread");
106441e847feb0e055ecb004802802cea07782ab228Andy McFadden        mState = STOPPED;
107441e847feb0e055ecb004802802cea07782ab228Andy McFadden        release_l();
108441e847feb0e055ecb004802802cea07782ab228Andy McFadden        mStartCond.broadcast();
109441e847feb0e055ecb004802802cea07782ab228Andy McFadden        return false;
110441e847feb0e055ecb004802802cea07782ab228Andy McFadden    }
111441e847feb0e055ecb004802802cea07782ab228Andy McFadden
112441e847feb0e055ecb004802802cea07782ab228Andy McFadden    ALOGV("Overlay thread running");
113441e847feb0e055ecb004802802cea07782ab228Andy McFadden    mState = RUNNING;
114441e847feb0e055ecb004802802cea07782ab228Andy McFadden    mStartCond.broadcast();
115441e847feb0e055ecb004802802cea07782ab228Andy McFadden
116441e847feb0e055ecb004802802cea07782ab228Andy McFadden    while (mState == RUNNING) {
117441e847feb0e055ecb004802802cea07782ab228Andy McFadden        mEventCond.wait(mMutex);
118441e847feb0e055ecb004802802cea07782ab228Andy McFadden        if (mFrameAvailable) {
119441e847feb0e055ecb004802802cea07782ab228Andy McFadden            ALOGV("Awake, frame available");
120441e847feb0e055ecb004802802cea07782ab228Andy McFadden            processFrame_l();
121441e847feb0e055ecb004802802cea07782ab228Andy McFadden            mFrameAvailable = false;
122441e847feb0e055ecb004802802cea07782ab228Andy McFadden        } else {
123441e847feb0e055ecb004802802cea07782ab228Andy McFadden            ALOGV("Awake, frame not available");
124441e847feb0e055ecb004802802cea07782ab228Andy McFadden        }
125441e847feb0e055ecb004802802cea07782ab228Andy McFadden    }
126441e847feb0e055ecb004802802cea07782ab228Andy McFadden
127441e847feb0e055ecb004802802cea07782ab228Andy McFadden    ALOGV("Overlay thread stopping");
128441e847feb0e055ecb004802802cea07782ab228Andy McFadden    release_l();
129441e847feb0e055ecb004802802cea07782ab228Andy McFadden    mState = STOPPED;
130441e847feb0e055ecb004802802cea07782ab228Andy McFadden    return false;       // stop
131441e847feb0e055ecb004802802cea07782ab228Andy McFadden}
132441e847feb0e055ecb004802802cea07782ab228Andy McFadden
133441e847feb0e055ecb004802802cea07782ab228Andy McFaddenstatus_t Overlay::setup_l() {
134441e847feb0e055ecb004802802cea07782ab228Andy McFadden    status_t err;
135441e847feb0e055ecb004802802cea07782ab228Andy McFadden
136441e847feb0e055ecb004802802cea07782ab228Andy McFadden    err = mEglWindow.createWindow(mOutputSurface);
137441e847feb0e055ecb004802802cea07782ab228Andy McFadden    if (err != NO_ERROR) {
138441e847feb0e055ecb004802802cea07782ab228Andy McFadden        return err;
139441e847feb0e055ecb004802802cea07782ab228Andy McFadden    }
140441e847feb0e055ecb004802802cea07782ab228Andy McFadden    mEglWindow.makeCurrent();
141441e847feb0e055ecb004802802cea07782ab228Andy McFadden
142441e847feb0e055ecb004802802cea07782ab228Andy McFadden    int width = mEglWindow.getWidth();
143441e847feb0e055ecb004802802cea07782ab228Andy McFadden    int height = mEglWindow.getHeight();
144441e847feb0e055ecb004802802cea07782ab228Andy McFadden
145441e847feb0e055ecb004802802cea07782ab228Andy McFadden    glViewport(0, 0, width, height);
146441e847feb0e055ecb004802802cea07782ab228Andy McFadden    glDisable(GL_DEPTH_TEST);
147441e847feb0e055ecb004802802cea07782ab228Andy McFadden    glDisable(GL_CULL_FACE);
148441e847feb0e055ecb004802802cea07782ab228Andy McFadden
149441e847feb0e055ecb004802802cea07782ab228Andy McFadden    // Shaders for rendering from different types of textures.
150441e847feb0e055ecb004802802cea07782ab228Andy McFadden    err = mTexProgram.setup(Program::PROGRAM_TEXTURE_2D);
151441e847feb0e055ecb004802802cea07782ab228Andy McFadden    if (err != NO_ERROR) {
152441e847feb0e055ecb004802802cea07782ab228Andy McFadden        return err;
153441e847feb0e055ecb004802802cea07782ab228Andy McFadden    }
154441e847feb0e055ecb004802802cea07782ab228Andy McFadden    err = mExtTexProgram.setup(Program::PROGRAM_EXTERNAL_TEXTURE);
155441e847feb0e055ecb004802802cea07782ab228Andy McFadden    if (err != NO_ERROR) {
156441e847feb0e055ecb004802802cea07782ab228Andy McFadden        return err;
157441e847feb0e055ecb004802802cea07782ab228Andy McFadden    }
158441e847feb0e055ecb004802802cea07782ab228Andy McFadden
159441e847feb0e055ecb004802802cea07782ab228Andy McFadden    err = mTextRenderer.loadIntoTexture();
160441e847feb0e055ecb004802802cea07782ab228Andy McFadden    if (err != NO_ERROR) {
161441e847feb0e055ecb004802802cea07782ab228Andy McFadden        return err;
162441e847feb0e055ecb004802802cea07782ab228Andy McFadden    }
163441e847feb0e055ecb004802802cea07782ab228Andy McFadden    mTextRenderer.setScreenSize(width, height);
164441e847feb0e055ecb004802802cea07782ab228Andy McFadden
165441e847feb0e055ecb004802802cea07782ab228Andy McFadden    // Input side (buffers from virtual display).
166441e847feb0e055ecb004802802cea07782ab228Andy McFadden    glGenTextures(1, &mExtTextureName);
167441e847feb0e055ecb004802802cea07782ab228Andy McFadden    if (mExtTextureName == 0) {
168441e847feb0e055ecb004802802cea07782ab228Andy McFadden        ALOGE("glGenTextures failed: %#x", glGetError());
169441e847feb0e055ecb004802802cea07782ab228Andy McFadden        return UNKNOWN_ERROR;
170441e847feb0e055ecb004802802cea07782ab228Andy McFadden    }
171441e847feb0e055ecb004802802cea07782ab228Andy McFadden
172b278f5e70c001391779525fb4d3b024503ba9466Dan Stoza    sp<IGraphicBufferConsumer> consumer;
173b278f5e70c001391779525fb4d3b024503ba9466Dan Stoza    BufferQueue::createBufferQueue(&mProducer, &consumer);
174b278f5e70c001391779525fb4d3b024503ba9466Dan Stoza    mGlConsumer = new GLConsumer(consumer, mExtTextureName,
175db2722a319d91a869ebc4dd618edbef43fd5b738Dan Stoza                GL_TEXTURE_EXTERNAL_OES, true, false);
176441e847feb0e055ecb004802802cea07782ab228Andy McFadden    mGlConsumer->setName(String8("virtual display"));
177441e847feb0e055ecb004802802cea07782ab228Andy McFadden    mGlConsumer->setDefaultBufferSize(width, height);
1786e6eaa7ac713ab6606726c3f76a9019ded97f018Pablo Ceballos    mProducer->setMaxDequeuedBufferCount(4);
179441e847feb0e055ecb004802802cea07782ab228Andy McFadden    mGlConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_TEXTURE);
180441e847feb0e055ecb004802802cea07782ab228Andy McFadden
181441e847feb0e055ecb004802802cea07782ab228Andy McFadden    mGlConsumer->setFrameAvailableListener(this);
182441e847feb0e055ecb004802802cea07782ab228Andy McFadden
183441e847feb0e055ecb004802802cea07782ab228Andy McFadden    return NO_ERROR;
184441e847feb0e055ecb004802802cea07782ab228Andy McFadden}
185441e847feb0e055ecb004802802cea07782ab228Andy McFadden
186441e847feb0e055ecb004802802cea07782ab228Andy McFadden
187441e847feb0e055ecb004802802cea07782ab228Andy McFaddenvoid Overlay::release_l() {
188441e847feb0e055ecb004802802cea07782ab228Andy McFadden    ALOGV("Overlay::release_l");
189441e847feb0e055ecb004802802cea07782ab228Andy McFadden    mOutputSurface.clear();
190441e847feb0e055ecb004802802cea07782ab228Andy McFadden    mGlConsumer.clear();
191b278f5e70c001391779525fb4d3b024503ba9466Dan Stoza    mProducer.clear();
192441e847feb0e055ecb004802802cea07782ab228Andy McFadden
193441e847feb0e055ecb004802802cea07782ab228Andy McFadden    mTexProgram.release();
194441e847feb0e055ecb004802802cea07782ab228Andy McFadden    mExtTexProgram.release();
195441e847feb0e055ecb004802802cea07782ab228Andy McFadden    mEglWindow.release();
196441e847feb0e055ecb004802802cea07782ab228Andy McFadden}
197441e847feb0e055ecb004802802cea07782ab228Andy McFadden
198441e847feb0e055ecb004802802cea07782ab228Andy McFaddenvoid Overlay::processFrame_l() {
199441e847feb0e055ecb004802802cea07782ab228Andy McFadden    float texMatrix[16];
200441e847feb0e055ecb004802802cea07782ab228Andy McFadden
201441e847feb0e055ecb004802802cea07782ab228Andy McFadden    mGlConsumer->updateTexImage();
202441e847feb0e055ecb004802802cea07782ab228Andy McFadden    mGlConsumer->getTransformMatrix(texMatrix);
203441e847feb0e055ecb004802802cea07782ab228Andy McFadden    nsecs_t monotonicNsec = mGlConsumer->getTimestamp();
204441e847feb0e055ecb004802802cea07782ab228Andy McFadden    nsecs_t frameNumber = mGlConsumer->getFrameNumber();
205441e847feb0e055ecb004802802cea07782ab228Andy McFadden
206441e847feb0e055ecb004802802cea07782ab228Andy McFadden    if (mLastFrameNumber > 0) {
207441e847feb0e055ecb004802802cea07782ab228Andy McFadden        mTotalDroppedFrames += size_t(frameNumber - mLastFrameNumber) - 1;
208441e847feb0e055ecb004802802cea07782ab228Andy McFadden    }
209441e847feb0e055ecb004802802cea07782ab228Andy McFadden    mLastFrameNumber = frameNumber;
210441e847feb0e055ecb004802802cea07782ab228Andy McFadden
211441e847feb0e055ecb004802802cea07782ab228Andy McFadden    mTextRenderer.setProportionalScale(35);
212441e847feb0e055ecb004802802cea07782ab228Andy McFadden
213441e847feb0e055ecb004802802cea07782ab228Andy McFadden    if (false) {  // DEBUG - full blue background
214441e847feb0e055ecb004802802cea07782ab228Andy McFadden        glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
215441e847feb0e055ecb004802802cea07782ab228Andy McFadden        glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
216441e847feb0e055ecb004802802cea07782ab228Andy McFadden    }
217441e847feb0e055ecb004802802cea07782ab228Andy McFadden
218441e847feb0e055ecb004802802cea07782ab228Andy McFadden    int width = mEglWindow.getWidth();
219441e847feb0e055ecb004802802cea07782ab228Andy McFadden    int height = mEglWindow.getHeight();
220441e847feb0e055ecb004802802cea07782ab228Andy McFadden    if (false) {  // DEBUG - draw inset
221441e847feb0e055ecb004802802cea07782ab228Andy McFadden        mExtTexProgram.blit(mExtTextureName, texMatrix,
222441e847feb0e055ecb004802802cea07782ab228Andy McFadden                100, 100, width-200, height-200);
223441e847feb0e055ecb004802802cea07782ab228Andy McFadden    } else {
224441e847feb0e055ecb004802802cea07782ab228Andy McFadden        mExtTexProgram.blit(mExtTextureName, texMatrix,
225441e847feb0e055ecb004802802cea07782ab228Andy McFadden                0, 0, width, height);
226441e847feb0e055ecb004802802cea07782ab228Andy McFadden    }
227441e847feb0e055ecb004802802cea07782ab228Andy McFadden
228441e847feb0e055ecb004802802cea07782ab228Andy McFadden    glEnable(GL_BLEND);
229441e847feb0e055ecb004802802cea07782ab228Andy McFadden    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
230441e847feb0e055ecb004802802cea07782ab228Andy McFadden    if (false) {  // DEBUG - show entire font bitmap
231441e847feb0e055ecb004802802cea07782ab228Andy McFadden        mTexProgram.blit(mTextRenderer.getTextureName(), Program::kIdentity,
232441e847feb0e055ecb004802802cea07782ab228Andy McFadden                100, 100, width-200, height-200);
233441e847feb0e055ecb004802802cea07782ab228Andy McFadden    }
234441e847feb0e055ecb004802802cea07782ab228Andy McFadden
235441e847feb0e055ecb004802802cea07782ab228Andy McFadden    char textBuf[64];
236441e847feb0e055ecb004802802cea07782ab228Andy McFadden    getTimeString_l(monotonicNsec, textBuf, sizeof(textBuf));
237884989c67081190ff864419328e9e81506db67caMark Salyzyn    String8 timeStr(String8::format("%s f=%" PRId64 " (%zd)",
238441e847feb0e055ecb004802802cea07782ab228Andy McFadden            textBuf, frameNumber, mTotalDroppedFrames));
239441e847feb0e055ecb004802802cea07782ab228Andy McFadden    mTextRenderer.drawString(mTexProgram, Program::kIdentity, 0, 0, timeStr);
240441e847feb0e055ecb004802802cea07782ab228Andy McFadden
241441e847feb0e055ecb004802802cea07782ab228Andy McFadden    glDisable(GL_BLEND);
242441e847feb0e055ecb004802802cea07782ab228Andy McFadden
243441e847feb0e055ecb004802802cea07782ab228Andy McFadden    if (false) {  // DEBUG - add red rectangle in lower-left corner
244441e847feb0e055ecb004802802cea07782ab228Andy McFadden        glEnable(GL_SCISSOR_TEST);
245441e847feb0e055ecb004802802cea07782ab228Andy McFadden        glScissor(0, 0, 200, 200);
246441e847feb0e055ecb004802802cea07782ab228Andy McFadden        glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
247441e847feb0e055ecb004802802cea07782ab228Andy McFadden        glClear(GL_COLOR_BUFFER_BIT);
248441e847feb0e055ecb004802802cea07782ab228Andy McFadden        glDisable(GL_SCISSOR_TEST);
249441e847feb0e055ecb004802802cea07782ab228Andy McFadden    }
250441e847feb0e055ecb004802802cea07782ab228Andy McFadden
251441e847feb0e055ecb004802802cea07782ab228Andy McFadden    mEglWindow.presentationTime(monotonicNsec);
252441e847feb0e055ecb004802802cea07782ab228Andy McFadden    mEglWindow.swapBuffers();
253441e847feb0e055ecb004802802cea07782ab228Andy McFadden}
254441e847feb0e055ecb004802802cea07782ab228Andy McFadden
255441e847feb0e055ecb004802802cea07782ab228Andy McFaddenvoid Overlay::getTimeString_l(nsecs_t monotonicNsec, char* buf, size_t bufLen) {
256441e847feb0e055ecb004802802cea07782ab228Andy McFadden    //const char* format = "%m-%d %T";    // matches log output
257441e847feb0e055ecb004802802cea07782ab228Andy McFadden    const char* format = "%T";
258441e847feb0e055ecb004802802cea07782ab228Andy McFadden    struct tm tm;
259441e847feb0e055ecb004802802cea07782ab228Andy McFadden
260545bcd53c828cf5b57e9158feb2e24bf0cd77985Pablo Ceballos    if (mUseMonotonicTimestamps) {
261545bcd53c828cf5b57e9158feb2e24bf0cd77985Pablo Ceballos        snprintf(buf, bufLen, "%" PRId64, monotonicNsec);
262545bcd53c828cf5b57e9158feb2e24bf0cd77985Pablo Ceballos        return;
263545bcd53c828cf5b57e9158feb2e24bf0cd77985Pablo Ceballos    }
264545bcd53c828cf5b57e9158feb2e24bf0cd77985Pablo Ceballos
265441e847feb0e055ecb004802802cea07782ab228Andy McFadden    // localtime/strftime is not the fastest way to do this, but a trivial
266441e847feb0e055ecb004802802cea07782ab228Andy McFadden    // benchmark suggests that the cost is negligible.
267441e847feb0e055ecb004802802cea07782ab228Andy McFadden    int64_t realTime = mStartRealtimeNsecs +
268441e847feb0e055ecb004802802cea07782ab228Andy McFadden            (monotonicNsec - mStartMonotonicNsecs);
269441e847feb0e055ecb004802802cea07782ab228Andy McFadden    time_t secs = (time_t) (realTime / 1000000000);
270441e847feb0e055ecb004802802cea07782ab228Andy McFadden    localtime_r(&secs, &tm);
271441e847feb0e055ecb004802802cea07782ab228Andy McFadden    strftime(buf, bufLen, format, &tm);
272441e847feb0e055ecb004802802cea07782ab228Andy McFadden
273441e847feb0e055ecb004802802cea07782ab228Andy McFadden    int32_t msec = (int32_t) ((realTime % 1000000000) / 1000000);
274441e847feb0e055ecb004802802cea07782ab228Andy McFadden    char tmpBuf[5];
275441e847feb0e055ecb004802802cea07782ab228Andy McFadden    snprintf(tmpBuf, sizeof(tmpBuf), ".%03d", msec);
276441e847feb0e055ecb004802802cea07782ab228Andy McFadden    strlcat(buf, tmpBuf, bufLen);
277441e847feb0e055ecb004802802cea07782ab228Andy McFadden}
278441e847feb0e055ecb004802802cea07782ab228Andy McFadden
279441e847feb0e055ecb004802802cea07782ab228Andy McFadden// Callback; executes on arbitrary thread.
28004f101c35eaa90b1f95939afac30674ec1611e6fDan Stozavoid Overlay::onFrameAvailable(const BufferItem& /* item */) {
281441e847feb0e055ecb004802802cea07782ab228Andy McFadden    ALOGV("Overlay::onFrameAvailable");
282441e847feb0e055ecb004802802cea07782ab228Andy McFadden    Mutex::Autolock _l(mMutex);
283441e847feb0e055ecb004802802cea07782ab228Andy McFadden    mFrameAvailable = true;
284441e847feb0e055ecb004802802cea07782ab228Andy McFadden    mEventCond.signal();
285441e847feb0e055ecb004802802cea07782ab228Andy McFadden}
286441e847feb0e055ecb004802802cea07782ab228Andy McFadden
287441e847feb0e055ecb004802802cea07782ab228Andy McFadden
288441e847feb0e055ecb004802802cea07782ab228Andy McFadden/*static*/ status_t Overlay::drawInfoPage(
289441e847feb0e055ecb004802802cea07782ab228Andy McFadden        const sp<IGraphicBufferProducer>& outputSurface) {
290441e847feb0e055ecb004802802cea07782ab228Andy McFadden    status_t err;
291441e847feb0e055ecb004802802cea07782ab228Andy McFadden
292441e847feb0e055ecb004802802cea07782ab228Andy McFadden    EglWindow window;
293441e847feb0e055ecb004802802cea07782ab228Andy McFadden    err = window.createWindow(outputSurface);
294441e847feb0e055ecb004802802cea07782ab228Andy McFadden    if (err != NO_ERROR) {
295441e847feb0e055ecb004802802cea07782ab228Andy McFadden        return err;
296441e847feb0e055ecb004802802cea07782ab228Andy McFadden    }
297441e847feb0e055ecb004802802cea07782ab228Andy McFadden    window.makeCurrent();
298441e847feb0e055ecb004802802cea07782ab228Andy McFadden
299441e847feb0e055ecb004802802cea07782ab228Andy McFadden    int width = window.getWidth();
300441e847feb0e055ecb004802802cea07782ab228Andy McFadden    int height = window.getHeight();
301441e847feb0e055ecb004802802cea07782ab228Andy McFadden    glViewport(0, 0, width, height);
302441e847feb0e055ecb004802802cea07782ab228Andy McFadden    glDisable(GL_DEPTH_TEST);
303441e847feb0e055ecb004802802cea07782ab228Andy McFadden    glDisable(GL_CULL_FACE);
304441e847feb0e055ecb004802802cea07782ab228Andy McFadden
305441e847feb0e055ecb004802802cea07782ab228Andy McFadden    // Shaders for rendering.
306441e847feb0e055ecb004802802cea07782ab228Andy McFadden    Program texProgram;
307441e847feb0e055ecb004802802cea07782ab228Andy McFadden    err = texProgram.setup(Program::PROGRAM_TEXTURE_2D);
308441e847feb0e055ecb004802802cea07782ab228Andy McFadden    if (err != NO_ERROR) {
309441e847feb0e055ecb004802802cea07782ab228Andy McFadden        return err;
310441e847feb0e055ecb004802802cea07782ab228Andy McFadden    }
311441e847feb0e055ecb004802802cea07782ab228Andy McFadden    TextRenderer textRenderer;
312441e847feb0e055ecb004802802cea07782ab228Andy McFadden    err = textRenderer.loadIntoTexture();
313441e847feb0e055ecb004802802cea07782ab228Andy McFadden    if (err != NO_ERROR) {
314441e847feb0e055ecb004802802cea07782ab228Andy McFadden        return err;
315441e847feb0e055ecb004802802cea07782ab228Andy McFadden    }
316441e847feb0e055ecb004802802cea07782ab228Andy McFadden    textRenderer.setScreenSize(width, height);
317441e847feb0e055ecb004802802cea07782ab228Andy McFadden
318441e847feb0e055ecb004802802cea07782ab228Andy McFadden    doDrawInfoPage(window, texProgram, textRenderer);
319441e847feb0e055ecb004802802cea07782ab228Andy McFadden
320441e847feb0e055ecb004802802cea07782ab228Andy McFadden    // Destroy the surface.  This causes a disconnect.
321441e847feb0e055ecb004802802cea07782ab228Andy McFadden    texProgram.release();
322441e847feb0e055ecb004802802cea07782ab228Andy McFadden    window.release();
323441e847feb0e055ecb004802802cea07782ab228Andy McFadden
324441e847feb0e055ecb004802802cea07782ab228Andy McFadden    return NO_ERROR;
325441e847feb0e055ecb004802802cea07782ab228Andy McFadden}
326441e847feb0e055ecb004802802cea07782ab228Andy McFadden
327441e847feb0e055ecb004802802cea07782ab228Andy McFadden/*static*/ void Overlay::doDrawInfoPage(const EglWindow& window,
328441e847feb0e055ecb004802802cea07782ab228Andy McFadden        const Program& texProgram, TextRenderer& textRenderer) {
329441e847feb0e055ecb004802802cea07782ab228Andy McFadden    const nsecs_t holdTime = 250000000LL;
330441e847feb0e055ecb004802802cea07782ab228Andy McFadden
331441e847feb0e055ecb004802802cea07782ab228Andy McFadden    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
332441e847feb0e055ecb004802802cea07782ab228Andy McFadden    glClear(GL_COLOR_BUFFER_BIT);
333441e847feb0e055ecb004802802cea07782ab228Andy McFadden
334441e847feb0e055ecb004802802cea07782ab228Andy McFadden    int width = window.getWidth();
335441e847feb0e055ecb004802802cea07782ab228Andy McFadden    int height = window.getHeight();
336441e847feb0e055ecb004802802cea07782ab228Andy McFadden
337441e847feb0e055ecb004802802cea07782ab228Andy McFadden    // Draw a thin border around the screen.  Some players, e.g. browser
338441e847feb0e055ecb004802802cea07782ab228Andy McFadden    // plugins, make it hard to see where the edges are when the device
339441e847feb0e055ecb004802802cea07782ab228Andy McFadden    // is using a black background, so this gives the viewer a frame of
340441e847feb0e055ecb004802802cea07782ab228Andy McFadden    // reference.
341441e847feb0e055ecb004802802cea07782ab228Andy McFadden    //
342441e847feb0e055ecb004802802cea07782ab228Andy McFadden    // This is a clumsy way to do it, but we're only doing it for one frame,
343441e847feb0e055ecb004802802cea07782ab228Andy McFadden    // and it's easier than actually drawing lines.
344441e847feb0e055ecb004802802cea07782ab228Andy McFadden    const int lineWidth = 4;
345441e847feb0e055ecb004802802cea07782ab228Andy McFadden    glEnable(GL_SCISSOR_TEST);
346441e847feb0e055ecb004802802cea07782ab228Andy McFadden    glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
347441e847feb0e055ecb004802802cea07782ab228Andy McFadden    glScissor(0, 0, width, lineWidth);
348441e847feb0e055ecb004802802cea07782ab228Andy McFadden    glClear(GL_COLOR_BUFFER_BIT);
349441e847feb0e055ecb004802802cea07782ab228Andy McFadden    glScissor(0, height - lineWidth, width, lineWidth);
350441e847feb0e055ecb004802802cea07782ab228Andy McFadden    glClear(GL_COLOR_BUFFER_BIT);
351441e847feb0e055ecb004802802cea07782ab228Andy McFadden    glScissor(0, 0, lineWidth, height);
352441e847feb0e055ecb004802802cea07782ab228Andy McFadden    glClear(GL_COLOR_BUFFER_BIT);
353441e847feb0e055ecb004802802cea07782ab228Andy McFadden    glScissor(width - lineWidth, 0, lineWidth, height);
354441e847feb0e055ecb004802802cea07782ab228Andy McFadden    glClear(GL_COLOR_BUFFER_BIT);
355441e847feb0e055ecb004802802cea07782ab228Andy McFadden    glDisable(GL_SCISSOR_TEST);
356441e847feb0e055ecb004802802cea07782ab228Andy McFadden
357441e847feb0e055ecb004802802cea07782ab228Andy McFadden    //glEnable(GL_BLEND);
358441e847feb0e055ecb004802802cea07782ab228Andy McFadden    //glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
359441e847feb0e055ecb004802802cea07782ab228Andy McFadden    textRenderer.setProportionalScale(30);
360441e847feb0e055ecb004802802cea07782ab228Andy McFadden
361441e847feb0e055ecb004802802cea07782ab228Andy McFadden    float xpos = 0;
362441e847feb0e055ecb004802802cea07782ab228Andy McFadden    float ypos = 0;
363441e847feb0e055ecb004802802cea07782ab228Andy McFadden    ypos = textRenderer.drawWrappedString(texProgram, xpos, ypos,
364441e847feb0e055ecb004802802cea07782ab228Andy McFadden            String8::format("Android screenrecord v%d.%d",
365441e847feb0e055ecb004802802cea07782ab228Andy McFadden                    kVersionMajor, kVersionMinor));
366441e847feb0e055ecb004802802cea07782ab228Andy McFadden
367441e847feb0e055ecb004802802cea07782ab228Andy McFadden    // Show date/time
368441e847feb0e055ecb004802802cea07782ab228Andy McFadden    time_t now = time(0);
369441e847feb0e055ecb004802802cea07782ab228Andy McFadden    struct tm tm;
370441e847feb0e055ecb004802802cea07782ab228Andy McFadden    localtime_r(&now, &tm);
371441e847feb0e055ecb004802802cea07782ab228Andy McFadden    char timeBuf[64];
372441e847feb0e055ecb004802802cea07782ab228Andy McFadden    strftime(timeBuf, sizeof(timeBuf), "%a, %d %b %Y %T %z", &tm);
373441e847feb0e055ecb004802802cea07782ab228Andy McFadden    String8 header("Started ");
374441e847feb0e055ecb004802802cea07782ab228Andy McFadden    header += timeBuf;
375441e847feb0e055ecb004802802cea07782ab228Andy McFadden    ypos = textRenderer.drawWrappedString(texProgram, xpos, ypos, header);
376441e847feb0e055ecb004802802cea07782ab228Andy McFadden    ypos += 8 * textRenderer.getScale();    // slight padding
377441e847feb0e055ecb004802802cea07782ab228Andy McFadden
378441e847feb0e055ecb004802802cea07782ab228Andy McFadden    // Show selected system property values
379441e847feb0e055ecb004802802cea07782ab228Andy McFadden    for (int i = 0; i < NELEM(kPropertyNames); i++) {
380441e847feb0e055ecb004802802cea07782ab228Andy McFadden        char valueBuf[PROPERTY_VALUE_MAX];
381441e847feb0e055ecb004802802cea07782ab228Andy McFadden
382441e847feb0e055ecb004802802cea07782ab228Andy McFadden        property_get(kPropertyNames[i], valueBuf, "");
383441e847feb0e055ecb004802802cea07782ab228Andy McFadden        if (valueBuf[0] == '\0') {
384441e847feb0e055ecb004802802cea07782ab228Andy McFadden            continue;
385441e847feb0e055ecb004802802cea07782ab228Andy McFadden        }
386441e847feb0e055ecb004802802cea07782ab228Andy McFadden        String8 str(String8::format("%s: [%s]", kPropertyNames[i], valueBuf));
387441e847feb0e055ecb004802802cea07782ab228Andy McFadden        ypos = textRenderer.drawWrappedString(texProgram, xpos, ypos, str);
388441e847feb0e055ecb004802802cea07782ab228Andy McFadden    }
389441e847feb0e055ecb004802802cea07782ab228Andy McFadden    ypos += 8 * textRenderer.getScale();    // slight padding
390441e847feb0e055ecb004802802cea07782ab228Andy McFadden
391441e847feb0e055ecb004802802cea07782ab228Andy McFadden    // Show GL info
392441e847feb0e055ecb004802802cea07782ab228Andy McFadden    String8 glStr("OpenGL: ");
393441e847feb0e055ecb004802802cea07782ab228Andy McFadden    glStr += (char*) glGetString(GL_VENDOR);
394441e847feb0e055ecb004802802cea07782ab228Andy McFadden    glStr += " / ";
395441e847feb0e055ecb004802802cea07782ab228Andy McFadden    glStr += (char*) glGetString(GL_RENDERER);
396441e847feb0e055ecb004802802cea07782ab228Andy McFadden    glStr += ", ";
397441e847feb0e055ecb004802802cea07782ab228Andy McFadden    glStr += (char*) glGetString(GL_VERSION);
398441e847feb0e055ecb004802802cea07782ab228Andy McFadden    ypos = textRenderer.drawWrappedString(texProgram, xpos, ypos, glStr);
399441e847feb0e055ecb004802802cea07782ab228Andy McFadden
400441e847feb0e055ecb004802802cea07782ab228Andy McFadden    //glDisable(GL_BLEND);
401441e847feb0e055ecb004802802cea07782ab228Andy McFadden
402441e847feb0e055ecb004802802cea07782ab228Andy McFadden    // Set a presentation time slightly in the past.  This will cause the
403441e847feb0e055ecb004802802cea07782ab228Andy McFadden    // player to hold the frame on screen.
404441e847feb0e055ecb004802802cea07782ab228Andy McFadden    window.presentationTime(systemTime(CLOCK_MONOTONIC) - holdTime);
405441e847feb0e055ecb004802802cea07782ab228Andy McFadden    window.swapBuffers();
406441e847feb0e055ecb004802802cea07782ab228Andy McFadden}
407