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