Add a LayerScreenshot
A LayerScreenshot is a special type of layer that contains a screenshot of
the screen acquired when its created. It works just like LayerDim.
Make sure to call compositionComplete() after rendering into a FBO.
Bug: 5446982, 5467587, 5466259
Change-Id: I5d8a1b4c327f9973d950cd4f4c0bca7f62825cd4
diff --git a/services/surfaceflinger/LayerScreenshot.cpp b/services/surfaceflinger/LayerScreenshot.cpp
new file mode 100644
index 0000000..e30ccbf
--- /dev/null
+++ b/services/surfaceflinger/LayerScreenshot.cpp
@@ -0,0 +1,114 @@
+/*
+ * 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::capture() {
+ GLfloat u, v;
+ status_t result = mFlinger->renderScreenToTexture(0, &mTextureName, &u, &v);
+ if (result != NO_ERROR) {
+ return result;
+ }
+
+ 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;
+
+ return NO_ERROR;
+}
+
+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