replicant-frameworks_native/services/surfaceflinger/LayerScreenshot.cpp
Mathias Agopian 4a9ac37fe2 Fix rotation displays frame N-1 briefly while rotating
The ScreenShot layer is now created hidden. The screenshot itself
is aquired during the transaction when the layer is made visible.
This guarantees the screenshot and the layer happen atomically
with respect to screen updates.

Bug: 5534521
Change-Id: Ida23e1f13d5716ec83b78a15712e0646d6cf8729
2011-11-04 15:15:32 -07:00

157 lines
4.7 KiB
C++

/*
* Copyright (C) 2011 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.
*/
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
#include <utils/Errors.h>
#include <utils/Log.h>
#include <ui/GraphicBuffer.h>
#include "LayerScreenshot.h"
#include "SurfaceFlinger.h"
#include "DisplayHardware/DisplayHardware.h"
namespace android {
// ---------------------------------------------------------------------------
LayerScreenshot::LayerScreenshot(SurfaceFlinger* flinger, DisplayID display,
const sp<Client>& client)
: LayerBaseClient(flinger, display, client),
mTextureName(0), mFlinger(flinger)
{
}
LayerScreenshot::~LayerScreenshot()
{
if (mTextureName) {
mFlinger->postMessageAsync(
new SurfaceFlinger::MessageDestroyGLTexture(mTextureName) );
}
}
status_t LayerScreenshot::captureLocked() {
GLfloat u, v;
status_t result = mFlinger->renderScreenToTextureLocked(0, &mTextureName, &u, &v);
if (result != NO_ERROR) {
return result;
}
initTexture(u, v);
return NO_ERROR;
}
status_t LayerScreenshot::capture() {
GLfloat u, v;
status_t result = mFlinger->renderScreenToTexture(0, &mTextureName, &u, &v);
if (result != NO_ERROR) {
return result;
}
initTexture(u, v);
return NO_ERROR;
}
void LayerScreenshot::initTexture(GLfloat u, GLfloat v) {
glBindTexture(GL_TEXTURE_2D, mTextureName);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
mTexCoords[0] = 0; mTexCoords[1] = v;
mTexCoords[2] = 0; mTexCoords[3] = 0;
mTexCoords[4] = u; mTexCoords[5] = 0;
mTexCoords[6] = u; mTexCoords[7] = v;
}
void LayerScreenshot::initStates(uint32_t w, uint32_t h, uint32_t flags) {
LayerBaseClient::initStates(w, h, flags);
if (!(flags & ISurfaceComposer::eHidden)) {
capture();
}
}
uint32_t LayerScreenshot::doTransaction(uint32_t flags)
{
const Layer::State& draw(drawingState());
const Layer::State& curr(currentState());
if (draw.flags & ISurfaceComposer::eLayerHidden) {
if (!(curr.flags & ISurfaceComposer::eLayerHidden)) {
// we're going from hidden to visible
status_t err = captureLocked();
if (err != NO_ERROR) {
LOGW("createScreenshotSurface failed (%s)", strerror(-err));
}
}
} else if (curr.flags & ISurfaceComposer::eLayerHidden) {
// we're going from visible to hidden
if (mTextureName) {
glDeleteTextures(1, &mTextureName);
mTextureName = 0;
}
}
return LayerBaseClient::doTransaction(flags);
}
void LayerScreenshot::onDraw(const Region& clip) const
{
const State& s(drawingState());
Region::const_iterator it = clip.begin();
Region::const_iterator const end = clip.end();
if (s.alpha>0 && (it != end)) {
const DisplayHardware& hw(graphicPlane(0).displayHardware());
const GLfloat alpha = s.alpha/255.0f;
const uint32_t fbHeight = hw.getHeight();
if (s.alpha == 0xFF) {
glDisable(GL_BLEND);
} else {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
glColor4f(0, 0, 0, alpha);
glDisable(GL_TEXTURE_EXTERNAL_OES);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, mTextureName);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, mTexCoords);
glVertexPointer(2, GL_FLOAT, 0, mVertices);
while (it != end) {
const Rect& r = *it++;
const GLint sy = fbHeight - (r.top + r.height());
glScissor(r.left, sy, r.width(), r.height());
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
}
// ---------------------------------------------------------------------------
}; // namespace android