Merge "CpuConsumer: Properly track acquired buffers" into jb-mr2-dev
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index c6fda97..29838e4 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -69,43 +69,44 @@
/* Tracing categories */
static const TracingCategory k_categories[] = {
- { "gfx", "Graphics", ATRACE_TAG_GRAPHICS, { } },
- { "input", "Input", ATRACE_TAG_INPUT, { } },
- { "view", "View System", ATRACE_TAG_VIEW, { } },
- { "wm", "Window Manager", ATRACE_TAG_WINDOW_MANAGER, { } },
- { "am", "Activity Manager", ATRACE_TAG_ACTIVITY_MANAGER, { } },
- { "audio", "Audio", ATRACE_TAG_AUDIO, { } },
- { "video", "Video", ATRACE_TAG_VIDEO, { } },
- { "camera", "Camera", ATRACE_TAG_CAMERA, { } },
- { "hal", "Hardware Modules", ATRACE_TAG_HAL, { } },
- { "sched", "CPU Scheduling", 0, {
- { REQ, "/sys/kernel/debug/tracing/events/sched/sched_switch/enable" },
- { REQ, "/sys/kernel/debug/tracing/events/sched/sched_wakeup/enable" },
+ { "gfx", "Graphics", ATRACE_TAG_GRAPHICS, { } },
+ { "input", "Input", ATRACE_TAG_INPUT, { } },
+ { "view", "View System", ATRACE_TAG_VIEW, { } },
+ { "webview", "WebView", ATRACE_TAG_WEBVIEW, { } },
+ { "wm", "Window Manager", ATRACE_TAG_WINDOW_MANAGER, { } },
+ { "am", "Activity Manager", ATRACE_TAG_ACTIVITY_MANAGER, { } },
+ { "audio", "Audio", ATRACE_TAG_AUDIO, { } },
+ { "video", "Video", ATRACE_TAG_VIDEO, { } },
+ { "camera", "Camera", ATRACE_TAG_CAMERA, { } },
+ { "hal", "Hardware Modules", ATRACE_TAG_HAL, { } },
+ { "sched", "CPU Scheduling", 0, {
+ { REQ, "/sys/kernel/debug/tracing/events/sched/sched_switch/enable" },
+ { REQ, "/sys/kernel/debug/tracing/events/sched/sched_wakeup/enable" },
} },
- { "freq", "CPU Frequency", 0, {
- { REQ, "/sys/kernel/debug/tracing/events/power/cpu_frequency/enable" },
- { OPT, "/sys/kernel/debug/tracing/events/power/clock_set_rate/enable" },
+ { "freq", "CPU Frequency", 0, {
+ { REQ, "/sys/kernel/debug/tracing/events/power/cpu_frequency/enable" },
+ { OPT, "/sys/kernel/debug/tracing/events/power/clock_set_rate/enable" },
} },
- { "membus", "Memory Bus Utilization", 0, {
- { REQ, "/sys/kernel/debug/tracing/events/memory_bus/enable" },
+ { "membus", "Memory Bus Utilization", 0, {
+ { REQ, "/sys/kernel/debug/tracing/events/memory_bus/enable" },
} },
- { "idle", "CPU Idle", 0, {
- { REQ, "/sys/kernel/debug/tracing/events/power/cpu_idle/enable" },
+ { "idle", "CPU Idle", 0, {
+ { REQ, "/sys/kernel/debug/tracing/events/power/cpu_idle/enable" },
} },
- { "disk", "Disk I/O", 0, {
- { REQ, "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable" },
- { REQ, "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable" },
- { REQ, "/sys/kernel/debug/tracing/events/block/block_rq_issue/enable" },
- { REQ, "/sys/kernel/debug/tracing/events/block/block_rq_complete/enable" },
+ { "disk", "Disk I/O", 0, {
+ { REQ, "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable" },
+ { REQ, "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable" },
+ { REQ, "/sys/kernel/debug/tracing/events/block/block_rq_issue/enable" },
+ { REQ, "/sys/kernel/debug/tracing/events/block/block_rq_complete/enable" },
} },
- { "load", "CPU Load", 0, {
- { REQ, "/sys/kernel/debug/tracing/events/cpufreq_interactive/enable" },
+ { "load", "CPU Load", 0, {
+ { REQ, "/sys/kernel/debug/tracing/events/cpufreq_interactive/enable" },
} },
- { "sync", "Synchronization", 0, {
- { REQ, "/sys/kernel/debug/tracing/events/sync/enable" },
+ { "sync", "Synchronization", 0, {
+ { REQ, "/sys/kernel/debug/tracing/events/sync/enable" },
} },
- { "workq", "Kernel Workqueues", 0, {
- { REQ, "/sys/kernel/debug/tracing/events/workqueue/enable" },
+ { "workq", "Kernel Workqueues", 0, {
+ { REQ, "/sys/kernel/debug/tracing/events/workqueue/enable" },
} },
};
@@ -116,6 +117,7 @@
static bool g_compress = false;
static bool g_nohup = false;
static int g_initialSleepSecs = 0;
+static const char* g_kernelTraceFuncs = NULL;
/* Global state */
static bool g_traceAborted = false;
@@ -131,6 +133,30 @@
static const char* k_tracingOverwriteEnablePath =
"/sys/kernel/debug/tracing/options/overwrite";
+static const char* k_currentTracerPath =
+ "/sys/kernel/debug/tracing/current_tracer";
+
+static const char* k_printTgidPath =
+ "/sys/kernel/debug/tracing/options/print-tgid";
+
+static const char* k_funcgraphAbsTimePath =
+ "/sys/kernel/debug/tracing/options/funcgraph-abstime";
+
+static const char* k_funcgraphCpuPath =
+ "/sys/kernel/debug/tracing/options/funcgraph-cpu";
+
+static const char* k_funcgraphProcPath =
+ "/sys/kernel/debug/tracing/options/funcgraph-proc";
+
+static const char* k_funcgraphFlatPath =
+ "/sys/kernel/debug/tracing/options/funcgraph-flat";
+
+static const char* k_funcgraphDurationPath =
+ "/sys/kernel/debug/tracing/options/funcgraph-duration";
+
+static const char* k_ftraceFilterPath =
+ "/sys/kernel/debug/tracing/set_ftrace_filter";
+
static const char* k_tracingOnPath =
"/sys/kernel/debug/tracing/tracing_on";
@@ -147,10 +173,22 @@
return access(filename, W_OK) != -1;
}
-// Write a string to a file, returning true if the write was successful.
-static bool writeStr(const char* filename, const char* str)
+// Truncate a file.
+static bool truncateFile(const char* path)
{
- int fd = open(filename, O_WRONLY);
+ int err = truncate(path, 0);
+ if (err != 0) {
+ fprintf(stderr, "error truncating %s: %s (%d)\n", path,
+ strerror(errno), errno);
+ return false;
+ }
+
+ return true;
+}
+
+static bool _writeStr(const char* filename, const char* str, int flags)
+{
+ int fd = open(filename, flags);
if (fd == -1) {
fprintf(stderr, "error opening %s: %s (%d)\n", filename,
strerror(errno), errno);
@@ -170,6 +208,18 @@
return ok;
}
+// Write a string to a file, returning true if the write was successful.
+static bool writeStr(const char* filename, const char* str)
+{
+ return _writeStr(filename, str, O_WRONLY);
+}
+
+// Append a string to a file, returning true if the write was successful.
+static bool appendStr(const char* filename, const char* str)
+{
+ return _writeStr(filename, str, O_APPEND|O_WRONLY);
+}
+
// Enable or disable a kernel option by writing a "1" or a "0" into a /sys
// file.
static bool setKernelOptionEnable(const char* filename, bool enable)
@@ -243,16 +293,7 @@
// Clear the contents of the kernel trace.
static bool clearTrace()
{
- int traceFD = creat(k_tracePath, 0);
- if (traceFD == -1) {
- fprintf(stderr, "error truncating %s: %s (%d)\n", k_tracePath,
- strerror(errno), errno);
- return false;
- }
-
- close(traceFD);
-
- return true;
+ return truncateFile(k_tracePath);
}
// Set the size of the kernel's trace buffer in kilobytes.
@@ -274,6 +315,14 @@
return writeStr(k_traceClockPath, enable ? "global" : "local");
}
+static bool setPrintTgidEnableIfPresent(bool enable)
+{
+ if (fileExists(k_printTgidPath)) {
+ return setKernelOptionEnable(k_printTgidPath, enable);
+ }
+ return true;
+}
+
// Poke all the binder-enabled processes in the system to get them to re-read
// their system properties.
static bool pokeBinderServices()
@@ -329,8 +378,90 @@
return ok;
}
-// Enable tracing in the kernel.
-static bool startTrace()
+// Verify that the comma separated list of functions are being traced by the
+// kernel.
+static bool verifyKernelTraceFuncs(const char* funcs)
+{
+ int fd = open(k_ftraceFilterPath, O_RDONLY);
+ if (fd == -1) {
+ fprintf(stderr, "error opening %s: %s (%d)\n", k_ftraceFilterPath,
+ strerror(errno), errno);
+ return false;
+ }
+
+ char buf[4097];
+ ssize_t n = read(fd, buf, 4096);
+ close(fd);
+ if (n == -1) {
+ fprintf(stderr, "error reading %s: %s (%d)\n", k_ftraceFilterPath,
+ strerror(errno), errno);
+ return false;
+ }
+
+ buf[n] = '\0';
+ String8 funcList = String8::format("\n%s", buf);
+
+ // Make sure that every function listed in funcs is in the list we just
+ // read from the kernel.
+ bool ok = true;
+ char* myFuncs = strdup(funcs);
+ char* func = strtok(myFuncs, ",");
+ while (func) {
+ String8 fancyFunc = String8::format("\n%s\n", func);
+ bool found = funcList.find(fancyFunc.string(), 0) >= 0;
+ if (!found || func[0] == '\0') {
+ fprintf(stderr, "error: \"%s\" is not a valid kernel function "
+ "to trace.\n", func);
+ ok = false;
+ }
+ func = strtok(NULL, ",");
+ }
+ free(myFuncs);
+
+ return ok;
+}
+
+// Set the comma separated list of functions that the kernel is to trace.
+static bool setKernelTraceFuncs(const char* funcs)
+{
+ bool ok = true;
+
+ if (funcs == NULL || funcs[0] == '\0') {
+ // Disable kernel function tracing.
+ ok &= writeStr(k_currentTracerPath, "nop");
+ if (fileExists(k_ftraceFilterPath)) {
+ ok &= truncateFile(k_ftraceFilterPath);
+ }
+ } else {
+ // Enable kernel function tracing.
+ ok &= writeStr(k_currentTracerPath, "function_graph");
+ ok &= setKernelOptionEnable(k_funcgraphAbsTimePath, true);
+ ok &= setKernelOptionEnable(k_funcgraphCpuPath, true);
+ ok &= setKernelOptionEnable(k_funcgraphProcPath, true);
+ ok &= setKernelOptionEnable(k_funcgraphFlatPath, true);
+
+ // Set the requested filter functions.
+ ok &= truncateFile(k_ftraceFilterPath);
+ char* myFuncs = strdup(funcs);
+ char* func = strtok(myFuncs, ",");
+ while (func) {
+ ok &= appendStr(k_ftraceFilterPath, func);
+ func = strtok(NULL, ",");
+ }
+ free(myFuncs);
+
+ // Verify that the set functions are being traced.
+ if (ok) {
+ ok &= verifyKernelTraceFuncs(funcs);
+ }
+ }
+
+ return ok;
+}
+
+// Set all the kernel tracing settings to the desired state for this trace
+// capture.
+static bool setUpTrace()
{
bool ok = true;
@@ -338,6 +469,8 @@
ok &= setTraceOverwriteEnable(g_traceOverwrite);
ok &= setTraceBufferSizeKB(g_traceBufferSizeKB);
ok &= setGlobalClockEnable(true);
+ ok &= setPrintTgidEnableIfPresent(true);
+ ok &= setKernelTraceFuncs(g_kernelTraceFuncs);
// Set up the tags property.
uint64_t tags = 0;
@@ -372,18 +505,12 @@
}
}
- // Enable tracing.
- ok &= setTracingEnabled(true);
-
return ok;
}
-// Disable tracing in the kernel.
-static void stopTrace()
+// Reset all the kernel tracing settings to their default state.
+static void cleanUpTrace()
{
- // Disable tracing.
- setTracingEnabled(false);
-
// Disable all tracing that we're able to.
disableKernelTraceEvents();
@@ -392,10 +519,23 @@
// Set the options back to their defaults.
setTraceOverwriteEnable(true);
+ setTraceBufferSizeKB(1);
setGlobalClockEnable(false);
+ setPrintTgidEnableIfPresent(false);
+ setKernelTraceFuncs(NULL);
+}
- // Note that we can't reset the trace buffer size here because that would
- // clear the trace before we've read it.
+
+// Enable tracing in the kernel.
+static bool startTrace()
+{
+ return setTracingEnabled(true);
+}
+
+// Disable tracing in the kernel.
+static void stopTrace()
+{
+ setTracingEnabled(false);
}
// Read the current kernel trace and write it to stdout.
@@ -555,6 +695,7 @@
fprintf(stderr, "options include:\n"
" -b N use a trace buffer size of N KB\n"
" -c trace into a circular buffer\n"
+ " -k fname,... trace the listed kernel functions\n"
" -n ignore signals\n"
" -s N sleep for N seconds before tracing [default 0]\n"
" -t N trace for N seconds [defualt 5]\n"
@@ -591,7 +732,7 @@
{ 0, 0, 0, 0 }
};
- ret = getopt_long(argc, argv, "b:cns:t:z",
+ ret = getopt_long(argc, argv, "b:ck:ns:t:z",
long_options, &option_index);
if (ret < 0) {
@@ -613,6 +754,10 @@
g_traceOverwrite = true;
break;
+ case 'k':
+ g_kernelTraceFuncs = optarg;
+ break;
+
case 'n':
g_nohup = true;
break;
@@ -662,7 +807,9 @@
sleep(g_initialSleepSecs);
}
- bool ok = startTrace();
+ bool ok = true;
+ ok &= setUpTrace();
+ ok &= startTrace();
if (ok && traceStart) {
printf("capturing trace...");
@@ -708,7 +855,7 @@
// Reset the trace buffer size to 1.
if (traceStop)
- setTraceBufferSizeKB(1);
+ cleanUpTrace();
return g_traceAborted ? 1 : 0;
}
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index 9a1839d..a18c00d 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -101,6 +101,12 @@
run_command("LIST OF OPEN FILES", 10, SU_PATH, "root", "lsof", NULL);
+ if (screenshot_path[0]) {
+ ALOGI("taking screenshot\n");
+ run_command(NULL, 10, "/system/bin/screencap", "-p", screenshot_path, NULL);
+ ALOGI("wrote screenshot: %s\n", screenshot_path);
+ }
+
for_each_pid(do_showmap, "SMAPS OF ALL PROCESSES");
for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
@@ -159,12 +165,6 @@
dump_file("LAST PANIC CONSOLE", "/data/dontpanic/apanic_console");
dump_file("LAST PANIC THREADS", "/data/dontpanic/apanic_threads");
- if (screenshot_path[0]) {
- ALOGI("taking screenshot\n");
- run_command(NULL, 5, SU_PATH, "root", "screenshot", screenshot_path, NULL);
- ALOGI("wrote screenshot: %s\n", screenshot_path);
- }
-
run_command("SYSTEM SETTINGS", 20, SU_PATH, "root", "sqlite3",
"/data/data/com.android.providers.settings/databases/settings.db",
"pragma user_version; select * from system; select * from secure; select * from global;", NULL);
@@ -311,6 +311,7 @@
" -b: play sound file instead of vibrate, at beginning of job\n"
" -e: play sound file instead of vibrate, at end of job\n"
" -q: disable vibrate\n"
+ " -B: send broadcast when finished (requires -o and -p)\n"
);
}
@@ -323,6 +324,7 @@
char* end_sound = 0;
int use_socket = 0;
int do_fb = 0;
+ int do_broadcast = 0;
if (getuid() != 0) {
// Old versions of the adb client would call the
@@ -348,7 +350,7 @@
dump_traces_path = dump_traces();
int c;
- while ((c = getopt(argc, argv, "b:de:ho:svqzp")) != -1) {
+ while ((c = getopt(argc, argv, "b:de:ho:svqzpB")) != -1) {
switch (c) {
case 'b': begin_sound = optarg; break;
case 'd': do_add_date = 1; break;
@@ -359,6 +361,7 @@
case 'q': do_vibrate = 0; break;
case 'z': do_compress = 6; break;
case 'p': do_fb = 1; break;
+ case 'B': do_broadcast = 1; break;
case '?': printf("\n");
case 'h':
usage();
@@ -474,6 +477,14 @@
fprintf(stderr, "rename(%s, %s): %s\n", tmp_path, path, strerror(errno));
}
+ if (do_broadcast && use_outfile && do_fb) {
+ run_command(NULL, 5, "/system/bin/am", "broadcast",
+ "-a", "android.intent.action.BUGREPORT_FINISHED",
+ "--es", "android.intent.extra.BUGREPORT", path,
+ "--es", "android.intent.extra.SCREENSHOT", screenshot_path,
+ "--receiver-permission", "android.permission.DUMP", NULL);
+ }
+
ALOGI("done\n");
return 0;
diff --git a/cmds/dumpstate/utils.c b/cmds/dumpstate/utils.c
index fd390f5..9b0013e 100644
--- a/cmds/dumpstate/utils.c
+++ b/cmds/dumpstate/utils.c
@@ -31,6 +31,7 @@
#include <sys/klog.h>
#include <time.h>
#include <unistd.h>
+#include <sys/prctl.h>
#include <cutils/debugger.h>
#include <cutils/properties.h>
@@ -264,6 +265,9 @@
const char *args[1024] = {command};
size_t arg;
+ /* make sure the child dies when dumpstate dies */
+ prctl(PR_SET_PDEATHSIG, SIGKILL);
+
va_list ap;
va_start(ap, command);
if (title) printf("------ %s (%s", title, command);
@@ -375,7 +379,7 @@
chp = strchr(chp, '/');
if (chp) {
*chp = 0;
- mkdir(path, 0775); /* drwxrwxr-x */
+ mkdir(path, 0770); /* drwxrwx--- */
*chp++ = '/';
}
}
diff --git a/cmds/surfaceflinger/main_surfaceflinger.cpp b/cmds/surfaceflinger/main_surfaceflinger.cpp
index 28e58e4..ce7fde0 100644
--- a/cmds/surfaceflinger/main_surfaceflinger.cpp
+++ b/cmds/surfaceflinger/main_surfaceflinger.cpp
@@ -20,9 +20,9 @@
using namespace android;
int main(int argc, char** argv) {
- SurfaceFlinger::publishAndJoinThreadPool(true);
// When SF is launched in its own process, limit the number of
// binder threads to 4.
ProcessState::self()->setThreadPoolMaxThreadCount(4);
+ SurfaceFlinger::publishAndJoinThreadPool(true);
return 0;
}
diff --git a/include/android/input.h b/include/android/input.h
index f2befa9e..c8ac938 100644
--- a/include/android/input.h
+++ b/include/android/input.h
@@ -428,6 +428,7 @@
enum {
AINPUT_SOURCE_CLASS_MASK = 0x000000ff,
+ AINPUT_SOURCE_CLASS_NONE = 0x00000000,
AINPUT_SOURCE_CLASS_BUTTON = 0x00000001,
AINPUT_SOURCE_CLASS_POINTER = 0x00000002,
AINPUT_SOURCE_CLASS_NAVIGATION = 0x00000004,
@@ -446,6 +447,7 @@
AINPUT_SOURCE_STYLUS = 0x00004000 | AINPUT_SOURCE_CLASS_POINTER,
AINPUT_SOURCE_TRACKBALL = 0x00010000 | AINPUT_SOURCE_CLASS_NAVIGATION,
AINPUT_SOURCE_TOUCHPAD = 0x00100000 | AINPUT_SOURCE_CLASS_POSITION,
+ AINPUT_SOURCE_TOUCH_NAVIGATION = 0x00200000 | AINPUT_SOURCE_CLASS_NONE,
AINPUT_SOURCE_JOYSTICK = 0x01000000 | AINPUT_SOURCE_CLASS_JOYSTICK,
AINPUT_SOURCE_ANY = 0xffffff00,
diff --git a/include/binder/BinderService.h b/include/binder/BinderService.h
index 6460268..5ac36d9 100644
--- a/include/binder/BinderService.h
+++ b/include/binder/BinderService.h
@@ -36,13 +36,18 @@
public:
static status_t publish(bool allowIsolated = false) {
sp<IServiceManager> sm(defaultServiceManager());
- return sm->addService(String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated);
+ return sm->addService(
+ String16(SERVICE::getServiceName()),
+ new SERVICE(), allowIsolated);
}
static void publishAndJoinThreadPool(bool allowIsolated = false) {
sp<IServiceManager> sm(defaultServiceManager());
- sm->addService(String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated);
+ sm->addService(
+ String16(SERVICE::getServiceName()),
+ new SERVICE(), allowIsolated);
ProcessState::self()->startThreadPool();
+ ProcessState::self()->giveThreadPoolName();
IPCThreadState::self()->joinThreadPool();
}
diff --git a/include/binder/ProcessState.h b/include/binder/ProcessState.h
index 8caf1af..e63a0d0 100644
--- a/include/binder/ProcessState.h
+++ b/include/binder/ProcessState.h
@@ -71,6 +71,7 @@
void spawnPooledThread(bool isMain);
status_t setThreadPoolMaxThreadCount(size_t maxThreads);
+ void giveThreadPoolName();
private:
friend class IPCThreadState;
@@ -80,6 +81,7 @@
ProcessState(const ProcessState& o);
ProcessState& operator=(const ProcessState& o);
+ String8 makeBinderThreadName();
struct handle_entry {
IBinder* binder;
diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h
index c59e00e..6a86db6 100644
--- a/include/gui/BufferQueue.h
+++ b/include/gui/BufferQueue.h
@@ -128,7 +128,7 @@
// GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv).
// An error due to invalid dimensions might not be reported until
// updateTexImage() is called.
- virtual status_t dequeueBuffer(int *buf, sp<Fence>& fence,
+ virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence,
uint32_t width, uint32_t height, uint32_t format, uint32_t usage);
// queueBuffer returns a filled buffer to the BufferQueue. In addition, a
@@ -139,7 +139,7 @@
virtual status_t queueBuffer(int buf,
const QueueBufferInput& input, QueueBufferOutput* output);
- virtual void cancelBuffer(int buf, sp<Fence> fence);
+ virtual void cancelBuffer(int buf, const sp<Fence>& fence);
// setSynchronousMode set whether dequeueBuffer is synchronous or
// asynchronous. In synchronous mode, dequeueBuffer blocks until
diff --git a/include/gui/ConsumerBase.h b/include/gui/ConsumerBase.h
index 49a764f..78a3608 100644
--- a/include/gui/ConsumerBase.h
+++ b/include/gui/ConsumerBase.h
@@ -69,10 +69,9 @@
// ConsumerBase is connected.
sp<BufferQueue> getBufferQueue() const;
- // dump writes the current state to a string. These methods should NOT be
- // overridden by child classes. Instead they should override the
- // dumpLocked method, which is called by these methods after locking the
- // mutex.
+ // dump writes the current state to a string. Child classes should add
+ // their state to the dump by overriding the dumpLocked method, which is
+ // called by these methods after locking the mutex.
void dump(String8& result) const;
void dump(String8& result, const char* prefix, char* buffer, size_t SIZE) const;
diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h
index a3e258d..29c7ff3 100644
--- a/include/gui/IGraphicBufferProducer.h
+++ b/include/gui/IGraphicBufferProducer.h
@@ -84,7 +84,7 @@
// the buffer. The contents of the buffer must not be overwritten until the
// fence signals. If the fence is NULL, the buffer may be written
// immediately.
- virtual status_t dequeueBuffer(int *slot, sp<Fence>& fence,
+ virtual status_t dequeueBuffer(int *slot, sp<Fence>* fence,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage) = 0;
// queueBuffer indicates that the client has finished filling in the
@@ -165,7 +165,7 @@
// cancelBuffer indicates that the client does not wish to fill in the
// buffer associated with slot and transfers ownership of the slot back to
// the server.
- virtual void cancelBuffer(int slot, sp<Fence> fence) = 0;
+ virtual void cancelBuffer(int slot, const sp<Fence>& fence) = 0;
// query retrieves some information for this surface
// 'what' tokens allowed are that of android_natives.h
diff --git a/include/gui/ISurface.h b/include/gui/ISurface.h
deleted file mode 100644
index 5a928f2..0000000
--- a/include/gui/ISurface.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-#ifndef ANDROID_GUI_ISURFACE_H
-#define ANDROID_GUI_ISURFACE_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
-
-#include <binder/IInterface.h>
-
-#include <ui/PixelFormat.h>
-
-namespace android {
-
-class IGraphicBufferProducer;
-
-class ISurface : public IInterface
-{
-protected:
- enum {
- GET_SURFACE_TEXTURE = IBinder::FIRST_CALL_TRANSACTION,
- };
-
-public:
- DECLARE_META_INTERFACE(Surface);
-
- virtual sp<IGraphicBufferProducer> getSurfaceTexture() const = 0;
-};
-
-// ----------------------------------------------------------------------------
-
-class BnSurface : public BnInterface<ISurface>
-{
-public:
- virtual status_t onTransact( uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
-};
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_GUI_ISURFACE_H
diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h
index 4862949..9018b87 100644
--- a/include/gui/ISurfaceComposer.h
+++ b/include/gui/ISurfaceComposer.h
@@ -95,24 +95,28 @@
virtual bool authenticateSurfaceTexture(
const sp<IGraphicBufferProducer>& surface) const = 0;
- /* Capture the specified screen. requires READ_FRAME_BUFFER permission
- * This function will fail if there is a secure window on screen.
+ /* triggers screen off and waits for it to complete
+ * requires ACCESS_SURFACE_FLINGER permission.
*/
- virtual status_t captureScreen(const sp<IBinder>& display, sp<IMemoryHeap>* heap,
- uint32_t* width, uint32_t* height, PixelFormat* format,
- uint32_t reqWidth, uint32_t reqHeight,
- uint32_t minLayerZ, uint32_t maxLayerZ) = 0;
-
-
- /* triggers screen off and waits for it to complete */
virtual void blank(const sp<IBinder>& display) = 0;
- /* triggers screen on and waits for it to complete */
+ /* triggers screen on and waits for it to complete
+ * requires ACCESS_SURFACE_FLINGER permission.
+ */
virtual void unblank(const sp<IBinder>& display) = 0;
/* returns information about a display
* intended to be used to get information about built-in displays */
virtual status_t getDisplayInfo(const sp<IBinder>& display, DisplayInfo* info) = 0;
+
+ /* Capture the specified screen. requires READ_FRAME_BUFFER permission
+ * This function will fail if there is a secure window on screen.
+ */
+ virtual status_t captureScreen(const sp<IBinder>& display,
+ const sp<IGraphicBufferProducer>& producer,
+ uint32_t reqWidth, uint32_t reqHeight,
+ uint32_t minLayerZ, uint32_t maxLayerZ,
+ bool isCpuConsumer) = 0;
};
// ----------------------------------------------------------------------------
@@ -130,11 +134,11 @@
GET_BUILT_IN_DISPLAY,
SET_TRANSACTION_STATE,
AUTHENTICATE_SURFACE,
- CAPTURE_SCREEN,
BLANK,
UNBLANK,
GET_DISPLAY_INFO,
CONNECT_DISPLAY,
+ CAPTURE_SCREEN,
};
virtual status_t onTransact(uint32_t code, const Parcel& data,
diff --git a/include/gui/ISurfaceComposerClient.h b/include/gui/ISurfaceComposerClient.h
index 23d1d4c..cb9816f 100644
--- a/include/gui/ISurfaceComposerClient.h
+++ b/include/gui/ISurfaceComposerClient.h
@@ -27,11 +27,11 @@
#include <ui/PixelFormat.h>
-#include <gui/ISurface.h>
-
namespace android {
// ----------------------------------------------------------------------------
+class IGraphicBufferProducer;
+
class ISurfaceComposerClient : public IInterface
{
public:
@@ -48,18 +48,18 @@
eProtectedByDRM = 0x00001000,
eFXSurfaceNormal = 0x00000000,
- eFXSurfaceBlur = 0x00010000, // deprecated, same as Dim
eFXSurfaceDim = 0x00020000,
- eFXSurfaceScreenshot= 0x00030000,
eFXSurfaceMask = 0x000F0000,
};
/*
* Requires ACCESS_SURFACE_FLINGER permission
*/
- virtual sp<ISurface> createSurface(
+ virtual status_t createSurface(
const String8& name, uint32_t w, uint32_t h,
- PixelFormat format, uint32_t flags) = 0;
+ PixelFormat format, uint32_t flags,
+ sp<IBinder>* handle,
+ sp<IGraphicBufferProducer>* gbp) = 0;
/*
* Requires ACCESS_SURFACE_FLINGER permission
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index 18e57ed..c25847c 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -76,24 +76,13 @@
return surface != NULL && surface->getIGraphicBufferProducer() != NULL;
}
- /* writes the given Surface into a Parcel */
- static status_t writeToParcel(const sp<Surface>& surface, Parcel* parcel);
-
- /* constructs a Surface from a Parcel. see Surface::writeToParcel()
- * and SurfaceControl::writeToParcel() */
- static sp<Surface> readFromParcel(const Parcel& data);
-
-
protected:
- Surface();
virtual ~Surface();
- void setIGraphicBufferProducer(const sp<IGraphicBufferProducer>& bufferProducer);
private:
// can't be copied
Surface& operator = (const Surface& rhs);
Surface(const Surface& rhs);
- void init();
// ANativeWindow hooks
static int hook_cancelBuffer(ANativeWindow* window,
diff --git a/include/gui/SurfaceComposerClient.h b/include/gui/SurfaceComposerClient.h
index 9e4d6fc..23655c7 100644
--- a/include/gui/SurfaceComposerClient.h
+++ b/include/gui/SurfaceComposerClient.h
@@ -30,6 +30,7 @@
#include <ui/PixelFormat.h>
+#include <gui/CpuConsumer.h>
#include <gui/SurfaceControl.h>
namespace android {
@@ -38,7 +39,6 @@
class DisplayInfo;
class Composer;
-class IMemoryHeap;
class ISurfaceComposerClient;
class IGraphicBufferProducer;
class Region;
@@ -156,10 +156,18 @@
class ScreenshotClient
{
- sp<IMemoryHeap> mHeap;
- uint32_t mWidth;
- uint32_t mHeight;
- PixelFormat mFormat;
+public:
+ static status_t capture(
+ const sp<IBinder>& display,
+ const sp<IGraphicBufferProducer>& producer,
+ uint32_t reqWidth, uint32_t reqHeight,
+ uint32_t minLayerZ, uint32_t maxLayerZ);
+
+private:
+ mutable sp<CpuConsumer> mCpuConsumer;
+ CpuConsumer::LockedBuffer mBuffer;
+ bool mHaveBuffer;
+
public:
ScreenshotClient();
@@ -171,6 +179,8 @@
uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ);
+ sp<CpuConsumer> getCpuConsumer() const;
+
// release memory occupied by the screenshot
void release();
diff --git a/include/gui/SurfaceControl.h b/include/gui/SurfaceControl.h
index f70888d..f27754c 100644
--- a/include/gui/SurfaceControl.h
+++ b/include/gui/SurfaceControl.h
@@ -27,7 +27,6 @@
#include <ui/PixelFormat.h>
#include <ui/Region.h>
-#include <gui/ISurface.h>
#include <gui/ISurfaceComposerClient.h>
namespace android {
@@ -46,9 +45,11 @@
static bool isValid(const sp<SurfaceControl>& surface) {
return (surface != 0) && surface->isValid();
}
+
bool isValid() {
- return mSurface!=0 && mClient!=0;
+ return mHandle!=0 && mClient!=0;
}
+
static bool isSameSurface(
const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs);
@@ -57,7 +58,7 @@
status_t setLayerStack(int32_t layerStack);
status_t setLayer(int32_t layer);
- status_t setPosition(int32_t x, int32_t y);
+ status_t setPosition(float x, float y);
status_t setSize(uint32_t w, uint32_t h);
status_t hide();
status_t show();
@@ -82,7 +83,8 @@
SurfaceControl(
const sp<SurfaceComposerClient>& client,
- const sp<ISurface>& surface);
+ const sp<IBinder>& handle,
+ const sp<IGraphicBufferProducer>& gbp);
~SurfaceControl();
@@ -90,7 +92,7 @@
void destroy();
sp<SurfaceComposerClient> mClient;
- sp<IBinder> mSurface;
+ sp<IBinder> mHandle;
sp<IGraphicBufferProducer> mGraphicBufferProducer;
mutable Mutex mLock;
mutable sp<Surface> mSurfaceData;
diff --git a/include/media/drm/DrmAPI.h b/include/media/drm/DrmAPI.h
new file mode 100644
index 0000000..77da0bf
--- /dev/null
+++ b/include/media/drm/DrmAPI.h
@@ -0,0 +1,205 @@
+ /*
+ * Copyright (C) 2013 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.
+ */
+
+#ifndef DRM_API_H_
+#define DRM_API_H_
+
+#include <utils/List.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+#include <utils/KeyedVector.h>
+#include <utils/RefBase.h>
+#include <media/stagefright/foundation/ABase.h>
+
+// Loadable DrmEngine shared libraries should define the entry points
+// createDrmFactory and createCryptoFactory as shown below:
+//
+// extern "C" {
+// extern android::DrmFactory *createDrmFactory();
+// extern android::CryptoFactory *createCryptoFactory();
+// }
+
+namespace android {
+
+ struct DrmPlugin;
+
+ // DRMs are implemented in DrmEngine plugins, which are dynamically
+ // loadable shared libraries that implement the entry points
+ // createDrmFactory and createCryptoFactory. createDrmFactory
+ // constructs and returns an instance of a DrmFactory object. Similarly,
+ // createCryptoFactory creates an instance of a CryptoFactory object.
+ // When a MediaCrypto or MediaDrm object needs to be constructed, all
+ // available DrmEngines present in the plugins directory on the device
+ // are scanned for a matching DrmEngine that can support the crypto
+ // scheme. When a match is found, the DrmEngine's createCryptoPlugin and
+ // createDrmPlugin methods are used to create CryptoPlugin or
+ // DrmPlugin instances to support that DRM scheme.
+
+ class DrmFactory {
+ public:
+ DrmFactory() {}
+ virtual ~DrmFactory() {}
+
+ // DrmFactory::isCryptoSchemeSupported can be called to determine
+ // if the plugin factory is able to construct plugins that support a
+ // given crypto scheme, which is specified by a UUID.
+ virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) = 0;
+
+ // Construct a DrmPlugin for the crypto scheme specified by UUID.
+ virtual status_t createDrmPlugin(
+ const uint8_t uuid[16], DrmPlugin **plugin) = 0;
+
+ private:
+ DrmFactory(const DrmFactory &);
+ DrmFactory &operator=(const DrmFactory &);
+ };
+
+ class DrmPlugin {
+ public:
+ enum EventType {
+ kDrmPluginEventProvisionRequired,
+ kDrmPluginEventLicenseNeeded,
+ kDrmPluginEventLicenseExpired,
+ kDrmPluginEventVendorDefined
+ };
+
+ // A license can be for offline content or for online streaming.
+ // Offline licenses are persisted on the device and may be used when the device
+ // is disconnected from the network.
+ enum LicenseType {
+ kLicenseType_Offline,
+ kLicenseType_Streaming
+ };
+
+ DrmPlugin() {}
+ virtual ~DrmPlugin() {}
+
+ // Open a new session with the DrmPlugin object. A session ID is returned
+ // in the sessionId parameter.
+ virtual status_t openSession(Vector<uint8_t> &sessionId) = 0;
+
+ // Close a session on the DrmPlugin object.
+ virtual status_t closeSession(Vector<uint8_t> const &sessionId) = 0;
+
+ // A license request/response exchange occurs between the app and a License
+ // Server to obtain the keys required to decrypt the content. getLicenseRequest()
+ // is used to obtain an opaque license request blob that is delivered to the
+ // license server.
+ //
+ // The init data passed to getLicenseRequest is container-specific and its
+ // meaning is interpreted based on the mime type provided in the mimeType
+ // parameter to getLicenseRequest. It could contain, for example, the content
+ // ID, key ID or other data obtained from the content metadata that is required
+ // in generating the license request.
+ //
+ // licenseType specifes if the license is for streaming or offline content
+ //
+ // optionalParameters are included in the license server request message to
+ // allow a client application to provide additional message parameters to the
+ // server.
+ //
+ // If successful, the opaque license request blob is returned to the caller.
+ virtual status_t
+ getLicenseRequest(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &initData,
+ String8 const &mimeType, LicenseType licenseType,
+ KeyedVector<String8, String8> const &optionalParameters,
+ Vector<uint8_t> &request, String8 &defaultUrl) = 0;
+
+ // After a license response is received by the app, it is provided to the
+ // Drm plugin using provideLicenseResponse.
+ virtual status_t provideLicenseResponse(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &response) = 0;
+
+ // Remove the keys associated with a license.
+ virtual status_t removeLicense(Vector<uint8_t> const &sessionId) = 0;
+
+ // Request an informative description of the license for the session. The status
+ // is in the form of {name, value} pairs. Since DRM license policies vary by
+ // vendor, the specific status field names are determined by each DRM vendor.
+ // Refer to your DRM provider documentation for definitions of the field names
+ // for a particular DrmEngine.
+ virtual status_t
+ queryLicenseStatus(Vector<uint8_t> const &sessionId,
+ KeyedVector<String8, String8> &infoMap) const = 0;
+
+ // A provision request/response exchange occurs between the app and a
+ // provisioning server to retrieve a device certificate. getProvisionRequest
+ // is used to obtain an opaque license request blob that is delivered to the
+ // provisioning server.
+ //
+ // If successful, the opaque provision request blob is returned to the caller.
+ virtual status_t getProvisionRequest(Vector<uint8_t> &request,
+ String8 &defaultUrl) = 0;
+
+ // After a provision response is received by the app, it is provided to the
+ // Drm plugin using provideProvisionResponse.
+ virtual status_t provideProvisionResponse(Vector<uint8_t> const &response) = 0;
+
+ // A means of enforcing the contractual requirement for a concurrent stream
+ // limit per subscriber across devices is provided via SecureStop. SecureStop
+ // is a means of securely monitoring the lifetime of sessions. Since playback
+ // on a device can be interrupted due to reboot, power failure, etc. a means
+ // of persisting the lifetime information on the device is needed.
+ //
+ // A signed version of the sessionID is written to persistent storage on the
+ // device when each MediaCrypto object is created. The sessionID is signed by
+ // the device private key to prevent tampering.
+ //
+ // In the normal case, playback will be completed, the session destroyed and
+ // the Secure Stops will be queried. The App queries secure stops and forwards
+ // the secure stop message to the server which verifies the signature and
+ // notifies the server side database that the session destruction has been
+ // confirmed. The persisted record on the client is only removed after positive
+ // confirmation that the server received the message using releaseSecureStops().
+ virtual status_t getSecureStops(List<Vector<uint8_t> > &secureStops) = 0;
+ virtual status_t releaseSecureStops(Vector<uint8_t> const &ssRelease) = 0;
+
+ // Read a property value given the device property string. There are a few forms
+ // of property access methods, depending on the data type returned.
+ // Since DRM plugin properties may vary, additional field names may be defined
+ // by each DRM vendor. Refer to your DRM provider documentation for definitions
+ // of its additional field names.
+ //
+ // Standard values are:
+ // "vendor" [string] identifies the maker of the plugin
+ // "version" [string] identifies the version of the plugin
+ // "description" [string] describes the plugin
+ // 'deviceUniqueId' [byte array] The device unique identifier is established
+ // during device provisioning and provides a means of uniquely identifying
+ // each device.
+ virtual status_t getPropertyString(String8 const &name, String8 &value ) const = 0;
+ virtual status_t getPropertyByteArray(String8 const &name,
+ Vector<uint8_t> &value ) const = 0;
+
+ // Write a property value given the device property string. There are a few forms
+ // of property setting methods, depending on the data type.
+ // Since DRM plugin properties may vary, additional field names may be defined
+ // by each DRM vendor. Refer to your DRM provider documentation for definitions
+ // of its field names.
+ virtual status_t setPropertyString(String8 const &name,
+ String8 const &value ) = 0;
+ virtual status_t setPropertyByteArray(String8 const &name,
+ Vector<uint8_t> const &value ) = 0;
+
+ // TODO: provide way to send an event
+ private:
+ DISALLOW_EVIL_CONSTRUCTORS(DrmPlugin);
+ };
+
+} // namespace android
+
+#endif // DRM_API_H_
diff --git a/include/media/drm/DrmClientAPI.h b/include/media/drm/DrmClientAPI.h
deleted file mode 100644
index 6a08933..0000000
--- a/include/media/drm/DrmClientAPI.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-#ifndef DRM_CLIENT_API_H_
-#define DRM_CLIENT_API_H_
-
-#include <utils/String8.h>
-#include <utils/Vector.h>
-#include <utils/List.h>
-#include <media/stagefright/foundation/ABase.h>
-
-namespace android {
-
- // A DrmMessageStatus object aggregates a sessionId, which uniquely
- // identifies a playback context with a status code and opaque message
- // data.
- struct DrmMessageStatus {
- Vector<uint8_t> mSessionId;
- status_t mStatus;
- Vector<uint8_t> mData;
- };
-
- class DrmClientPlugin {
- public:
-
- // A license can be for downloaded, offline content or for online streaming
- // Offline licenses are persisted on the device and may be used when the device
- // is disconnected from the network.
- enum LicenseType {
- kLicenseType_Offline,
- kLicenseType_Streaming
- };
-
- DrmClientPlugin() {}
- virtual ~DrmClientPlugin() {}
-
- // A license request/response exchange occurs between the app and a License
- // Server to obtain the keys required to decrypt the content. getLicenseRequest()
- // is used to obtain an opaque license request blob that is delivered to the
- // license server.
- //
- // The init data passed to getLicenseRequest is container-specific and its
- // meaning is interpreted based on the mime type provided in the mimeType
- // parameter to getLicenseRequest. It could contain, for example, the content
- // ID, key ID or other data obtained from the content metadata that is required
- // in generating the license request.
- //
- // The DrmMessageStatus returned from getLicenseRequest contains a sessionId for
- // the new session, a status code indicating whether the operation was successful
- // and if so, the request blob is placed into the mData field.
- virtual DrmMessageStatus getLicenseRequest(Vector<uint8_t> const &initData,
- String8 const &mimeType, LicenseType licenseType) = 0;
-
- // After a license response is received by the app, it is provided to the
- // DrmClient plugin using provideLicenseResponse. The response data is provided
- // in the mData field of the response parameter.
- virtual status_t provideLicenseResponse(DrmMessageStatus const &response) = 0;
-
- // Remove the keys associated with a license and release the session
- virtual status_t clearLicense(Vector<uint8_t> const &sessionId) = 0;
-
- // A provision request/response exchange occurs between the app and a
- // provisioning server to retrieve a device certificate. getProvisionRequest
- // is used to obtain an opaque license request blob that is delivered to the
- // provisioning server.
- //
- // The DrmMessageStatus returned from getLicenseRequest contains a status code
- // indicating whether the operation was successful and if so, the request blob
- // is placed into the mData field.
- virtual DrmMessageStatus getProvisionRequest() = 0;
-
- // After a provision response is received by the app, it is provided to the
- // DrmClient plugin using provideProvisionResponse. The response data is
- // provided in the mData field of the response parameter.
- virtual status_t provideProvisionResponse(DrmMessageStatus const &response) = 0;
-
- // A means of enforcing the contractual requirement for a concurrent stream
- // limit per subscriber across devices is provided via SecureStop. SecureStop
- // is a means of securely monitoring the lifetime of sessions. Since playback
- // on a device can be interrupted due to reboot, power failure, etc. a means
- // of persisting the lifetime information on the device is needed.
- //
- // A signed version of the sessionID is written to persistent storage on the
- // device when each MediaCrypto object is created. The sessionID is signed by
- // the device private key to prevent tampering.
- //
- // In the normal case, playback will be completed, the session destroyed and
- // the Secure Stops will be queried. The App queries secure stops and forwards
- // the secure stop message to the server which verifies the signature and
- // notifies the server side database that the session destruction has been
- // confirmed. The persisted record on the client is only removed after positive
- // confirmation that the server received the message using releaseSecureStops().
- virtual List<DrmMessageStatus> getSecureStops() = 0;
- virtual status_t releaseSecureStops(DrmMessageStatus const &ssRelease) = 0;
-
- // Retrieve the device unique identifier for this device. The device unique
- // identifier is established during device provisioning.
- virtual Vector<uint8_t> getDeviceUniqueId() const = 0;
-
- private:
- DISALLOW_EVIL_CONSTRUCTORS(DrmClientPlugin);
- };
-
-} // namespace android
-
-#endif // DRM_CLIENT_API_H_
diff --git a/include/media/drm/DrmEngineAPI.h b/include/media/drm/DrmEngineAPI.h
deleted file mode 100644
index 25bd34a..0000000
--- a/include/media/drm/DrmEngineAPI.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-#ifndef DRM_ENGINE_API_H_
-#define DRM_ENGINE_API_H_
-
-#include <utils/Errors.h>
-#include <media/stagefright/foundation/ABase.h>
-
-
-namespace android {
-
- class CryptoPlugin;
- class DrmClientPlugin;
-
- // DRMs are implemented in DrmEngine plugins, which are dynamically
- // loadable shared libraries that implement the entry point
- // createDrmPluginFactory. createDrmPluginFactory constructs and returns
- // an instance of a DrmPluginFactory object. When a MediaCrypto or
- // DrmClient object needs to be constructed, all available
- // DrmEngines present in the plugins directory on the device are scanned
- // for a matching DrmEngine that can support the crypto scheme. When a
- // match is found, the DrmEngine’s createCryptoPlugin or
- // createDrmClientPlugin methods are used to create CryptoPlugin or
- // DrmClientPlugin instances to support that DRM scheme.
-
- class DrmPluginFactory {
- public:
- DrmPluginFactory() {}
- virtual ~DrmPluginFactory() {}
-
- // DrmPluginFactory::isCryptoSchemeSupported can be called to determine
- // if the plugin factory is able to construct plugins that support a
- // given crypto scheme, which is specified by a UUID.
- virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) const = 0;
-
- // Construct a CryptoPlugin for the crypto scheme specified by UUID.
- // {data, size} provide scheme-specific initialization data.
- virtual status_t createCryptoPlugin(
- const uint8_t uuid[16], const void *data, size_t size,
- CryptoPlugin **plugin) = 0;
-
- // Construct a DrmClientPlugin for the crypto scheme specified by UUID.
- // {data, size} provide scheme-specific initialization data.
- virtual status_t createDrmClientPlugin(
- const uint8_t uuid[16], const void *data, size_t size,
- DrmClientPlugin **plugin) = 0;
-
- private:
- DISALLOW_EVIL_CONSTRUCTORS(DrmPluginFactory);
- };
-
-} // namespace android
-
- // Loadable DrmEngine shared libraries should define the entry point
- // createDrmPluginFactory as shown below:
- //
- // extern "C" {
- // extern android::DrmPluginFactory *createDrmPluginFactory();
- // }
-
-#endif // DRM_ENGINE_API_H_
diff --git a/include/private/gui/LayerState.h b/include/private/gui/LayerState.h
index 0798e17..bf4bf03 100644
--- a/include/private/gui/LayerState.h
+++ b/include/private/gui/LayerState.h
@@ -24,7 +24,6 @@
#include <ui/Region.h>
#include <ui/Rect.h>
-#include <gui/ISurface.h>
namespace android {
diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h
index 4b9b5a8..ea9368d 100644
--- a/include/ui/GraphicBuffer.h
+++ b/include/ui/GraphicBuffer.h
@@ -24,6 +24,7 @@
#include <ui/PixelFormat.h>
#include <ui/Rect.h>
#include <utils/Flattenable.h>
+#include <utils/RefBase.h>
struct ANativeWindowBuffer;
@@ -37,10 +38,8 @@
// ===========================================================================
class GraphicBuffer
- : public ANativeObjectBase<
- ANativeWindowBuffer,
- GraphicBuffer,
- LightRefBase<GraphicBuffer> >, public Flattenable
+ : public ANativeObjectBase< ANativeWindowBuffer, GraphicBuffer, RefBase >,
+ public Flattenable
{
public:
diff --git a/include/utils/AndroidThreads.h b/include/utils/AndroidThreads.h
index f67648f..4eee14d 100644
--- a/include/utils/AndroidThreads.h
+++ b/include/utils/AndroidThreads.h
@@ -56,6 +56,9 @@
size_t threadStackSize,
android_thread_id_t *threadId);
+// set the same of the running thread
+extern void androidSetThreadName(const char* name);
+
// Used by the Java Runtime to control how threads are created, so that
// they can be proper and lovely Java threads.
typedef int (*android_create_thread_fn)(android_thread_func_t entryFunction,
diff --git a/include/utils/Condition.h b/include/utils/Condition.h
index 8852d53..e63ba7e 100644
--- a/include/utils/Condition.h
+++ b/include/utils/Condition.h
@@ -48,6 +48,11 @@
SHARED = 1
};
+ enum WakeUpType {
+ WAKE_UP_ONE = 0,
+ WAKE_UP_ALL = 1
+ };
+
Condition();
Condition(int type);
~Condition();
@@ -57,6 +62,14 @@
status_t waitRelative(Mutex& mutex, nsecs_t reltime);
// Signal the condition variable, allowing one thread to continue.
void signal();
+ // Signal the condition variable, allowing one or all threads to continue.
+ void signal(WakeUpType type) {
+ if (type == WAKE_UP_ONE) {
+ signal();
+ } else {
+ broadcast();
+ }
+ }
// Signal the condition variable, allowing all threads to continue.
void broadcast();
diff --git a/include/utils/RefBase.h b/include/utils/RefBase.h
index 0a8e10a..033fe67 100644
--- a/include/utils/RefBase.h
+++ b/include/utils/RefBase.h
@@ -52,12 +52,16 @@
}
// ---------------------------------------------------------------------------
-class ReferenceMover;
-class ReferenceConverterBase {
+
+class ReferenceRenamer {
+protected:
+ // destructor is purposedly not virtual so we avoid code overhead from
+ // subclasses; we have to make it protected to guarantee that it
+ // cannot be called from this base class (and to make strict compilers
+ // happy).
+ ~ReferenceRenamer() { }
public:
- virtual size_t getReferenceTypeSize() const = 0;
- virtual void* getReferenceBase(void const*) const = 0;
- inline virtual ~ReferenceConverterBase() { }
+ virtual void operator()(size_t i) const = 0;
};
// ---------------------------------------------------------------------------
@@ -144,17 +148,23 @@
virtual void onLastWeakRef(const void* id);
private:
- friend class ReferenceMover;
- static void moveReferences(void* d, void const* s, size_t n,
- const ReferenceConverterBase& caster);
-
-private:
friend class weakref_type;
class weakref_impl;
RefBase(const RefBase& o);
RefBase& operator=(const RefBase& o);
+private:
+ friend class ReferenceMover;
+
+ static void renameRefs(size_t n, const ReferenceRenamer& renamer);
+
+ static void renameRefId(weakref_type* ref,
+ const void* old_id, const void* new_id);
+
+ static void renameRefId(RefBase* ref,
+ const void* old_id, const void* new_id);
+
weakref_impl* const mRefs;
};
@@ -185,8 +195,9 @@
private:
friend class ReferenceMover;
- inline static void moveReferences(void* d, void const* s, size_t n,
- const ReferenceConverterBase& caster) { }
+ inline static void renameRefs(size_t n, const ReferenceRenamer& renamer) { }
+ inline static void renameRefId(T* ref,
+ const void* old_id, const void* new_id) { }
private:
mutable volatile int32_t mCount;
@@ -455,42 +466,48 @@
// this class just serves as a namespace so TYPE::moveReferences can stay
// private.
-
class ReferenceMover {
- // StrongReferenceCast and WeakReferenceCast do the impedance matching
- // between the generic (void*) implementation in Refbase and the strongly typed
- // template specializations below.
-
- template <typename TYPE>
- struct StrongReferenceCast : public ReferenceConverterBase {
- virtual size_t getReferenceTypeSize() const { return sizeof( sp<TYPE> ); }
- virtual void* getReferenceBase(void const* p) const {
- sp<TYPE> const* sptr(reinterpret_cast<sp<TYPE> const*>(p));
- return static_cast<typename TYPE::basetype *>(sptr->get());
- }
- };
-
- template <typename TYPE>
- struct WeakReferenceCast : public ReferenceConverterBase {
- virtual size_t getReferenceTypeSize() const { return sizeof( wp<TYPE> ); }
- virtual void* getReferenceBase(void const* p) const {
- wp<TYPE> const* sptr(reinterpret_cast<wp<TYPE> const*>(p));
- return static_cast<typename TYPE::basetype *>(sptr->unsafe_get());
- }
- };
-
public:
+ // it would be nice if we could make sure no extra code is generated
+ // for sp<TYPE> or wp<TYPE> when TYPE is a descendant of RefBase:
+ // Using a sp<RefBase> override doesn't work; it's a bit like we wanted
+ // a template<typename TYPE inherits RefBase> template...
+
template<typename TYPE> static inline
void move_references(sp<TYPE>* d, sp<TYPE> const* s, size_t n) {
+
+ class Renamer : public ReferenceRenamer {
+ sp<TYPE>* d;
+ sp<TYPE> const* s;
+ virtual void operator()(size_t i) const {
+ // The id are known to be the sp<>'s this pointer
+ TYPE::renameRefId(d[i].get(), &s[i], &d[i]);
+ }
+ public:
+ Renamer(sp<TYPE>* d, sp<TYPE> const* s) : s(s), d(d) { }
+ };
+
memmove(d, s, n*sizeof(sp<TYPE>));
- StrongReferenceCast<TYPE> caster;
- TYPE::moveReferences(d, s, n, caster);
+ TYPE::renameRefs(n, Renamer(d, s));
}
+
+
template<typename TYPE> static inline
void move_references(wp<TYPE>* d, wp<TYPE> const* s, size_t n) {
+
+ class Renamer : public ReferenceRenamer {
+ wp<TYPE>* d;
+ wp<TYPE> const* s;
+ virtual void operator()(size_t i) const {
+ // The id are known to be the wp<>'s this pointer
+ TYPE::renameRefId(d[i].get_refs(), &s[i], &d[i]);
+ }
+ public:
+ Renamer(wp<TYPE>* d, wp<TYPE> const* s) : s(s), d(d) { }
+ };
+
memmove(d, s, n*sizeof(wp<TYPE>));
- WeakReferenceCast<TYPE> caster;
- TYPE::moveReferences(d, s, n, caster);
+ TYPE::renameRefs(n, Renamer(d, s));
}
};
diff --git a/include/utils/Thread.h b/include/utils/Thread.h
index 4a34abd..df30611 100644
--- a/include/utils/Thread.h
+++ b/include/utils/Thread.h
@@ -67,6 +67,9 @@
// Do not call from this object's thread; will return WOULD_BLOCK in that case.
status_t join();
+ // Indicates whether this thread is running or not.
+ bool isRunning() const;
+
#ifdef HAVE_ANDROID_OS
// Return the thread's kernel ID, same as the thread itself calling gettid() or
// androidGetTid(), or -1 if the thread is not running.
diff --git a/include/utils/Vector.h b/include/utils/Vector.h
index f3020d6..ed7b725 100644
--- a/include/utils/Vector.h
+++ b/include/utils/Vector.h
@@ -80,7 +80,13 @@
//! sets the capacity. capacity can never be reduced less than size()
inline ssize_t setCapacity(size_t size) { return VectorImpl::setCapacity(size); }
- /*!
+ /*!
+ * set the size of the vector. items are appended with the default
+ * constructor, or removed from the end as needed.
+ */
+ inline ssize_t resize(size_t size) { return VectorImpl::resize(size); }
+
+ /*!
* C-style array access
*/
diff --git a/include/utils/VectorImpl.h b/include/utils/VectorImpl.h
index c4ec2ff..9bc50e6 100644
--- a/include/utils/VectorImpl.h
+++ b/include/utils/VectorImpl.h
@@ -64,6 +64,7 @@
inline bool isEmpty() const { return mCount == 0; }
size_t capacity() const;
ssize_t setCapacity(size_t size);
+ ssize_t resize(size_t size);
/*! append/insert another vector or array */
ssize_t insertVectorAt(const VectorImpl& vector, size_t index);
diff --git a/libs/binder/MemoryBase.cpp b/libs/binder/MemoryBase.cpp
index 033066b..5c82330 100644
--- a/libs/binder/MemoryBase.cpp
+++ b/libs/binder/MemoryBase.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#define LOG_TAG "MemoryBase"
#include <stdlib.h>
#include <stdint.h>
@@ -44,3 +45,11 @@
// ---------------------------------------------------------------------------
}; // namespace android
+
+// Backwards compatibility for libdatabase_sqlcipher (http://b/8253769).
+extern "C" void _ZN7android10MemoryBaseC1ERKNS_2spINS_11IMemoryHeapEEEij(void*, void*, ssize_t, size_t);
+extern "C" void _ZN7android10MemoryBaseC1ERKNS_2spINS_11IMemoryHeapEEElj(void* obj, void* h, long o, unsigned int size) {
+ _ZN7android10MemoryBaseC1ERKNS_2spINS_11IMemoryHeapEEEij(obj, h, o, size);
+ ALOGW("Using temporary compatibility workaround for usage of MemoryBase "
+ "private API. Please fix your application!");
+}
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index d95fd6f..294e1d4 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -283,15 +283,20 @@
}
}
+String8 ProcessState::makeBinderThreadName() {
+ int32_t s = android_atomic_add(1, &mThreadPoolSeq);
+ String8 name;
+ name.appendFormat("Binder_%X", s);
+ return name;
+}
+
void ProcessState::spawnPooledThread(bool isMain)
{
if (mThreadPoolStarted) {
- int32_t s = android_atomic_add(1, &mThreadPoolSeq);
- char buf[16];
- snprintf(buf, sizeof(buf), "Binder_%X", s);
- ALOGV("Spawning new pooled thread, name=%s\n", buf);
+ String8 name = makeBinderThreadName();
+ ALOGV("Spawning new pooled thread, name=%s\n", name.string());
sp<Thread> t = new PoolThread(isMain);
- t->run(buf);
+ t->run(name.string());
}
}
@@ -304,6 +309,10 @@
return result;
}
+void ProcessState::giveThreadPoolName() {
+ androidSetThreadName( makeBinderThreadName().string() );
+}
+
static int open_driver()
{
int fd = open("/dev/binder", O_RDWR);
diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk
index 544b664..5c7bb4c 100644
--- a/libs/gui/Android.mk
+++ b/libs/gui/Android.mk
@@ -17,7 +17,6 @@
IGraphicBufferProducer.cpp \
ISensorEventConnection.cpp \
ISensorServer.cpp \
- ISurface.cpp \
ISurfaceComposer.cpp \
ISurfaceComposerClient.cpp \
LayerState.cpp \
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index d93c067..75a0296 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -254,7 +254,7 @@
return NO_ERROR;
}
-status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>& outFence,
+status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>* outFence,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
ATRACE_CALL();
ST_LOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage);
@@ -393,7 +393,7 @@
dpy = mSlots[buf].mEglDisplay;
eglFence = mSlots[buf].mEglFence;
- outFence = mSlots[buf].mFence;
+ *outFence = mSlots[buf].mFence;
mSlots[buf].mEglFence = EGL_NO_SYNC_KHR;
mSlots[buf].mFence = Fence::NO_FENCE;
} // end lock scope
@@ -590,7 +590,7 @@
return OK;
}
-void BufferQueue::cancelBuffer(int buf, sp<Fence> fence) {
+void BufferQueue::cancelBuffer(int buf, const sp<Fence>& fence) {
ATRACE_CALL();
ST_LOGV("cancelBuffer: slot=%d", buf);
Mutex::Autolock lock(mMutex);
@@ -995,7 +995,7 @@
}
status_t BufferQueue::drainQueueLocked() {
- while (mSynchronousMode && !mQueue.isEmpty()) {
+ while (mSynchronousMode && mQueue.size() > 1) {
mDequeueCondition.wait(mMutex);
if (mAbandoned) {
ST_LOGE("drainQueueLocked: BufferQueue has been abandoned!");
@@ -1012,7 +1012,7 @@
status_t BufferQueue::drainQueueAndFreeBuffersLocked() {
status_t err = drainQueueLocked();
if (err == NO_ERROR) {
- if (mSynchronousMode) {
+ if (mQueue.empty()) {
freeAllBuffersLocked();
} else {
freeAllBuffersExceptHeadLocked();
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 54860d7..63d7628 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -81,7 +81,7 @@
return result;
}
- virtual status_t dequeueBuffer(int *buf, sp<Fence>& fence,
+ virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
Parcel data, reply;
data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
@@ -99,8 +99,8 @@
// If the fence was written by the callee, then overwrite the
// caller's fence here. If it wasn't written then don't touch the
// caller's fence.
- fence = new Fence();
- reply.read(*fence.get());
+ *fence = new Fence();
+ reply.read(*(fence->get()));
}
result = reply.readInt32();
return result;
@@ -121,7 +121,7 @@
return result;
}
- virtual void cancelBuffer(int buf, sp<Fence> fence) {
+ virtual void cancelBuffer(int buf, const sp<Fence>& fence) {
Parcel data, reply;
data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
data.writeInt32(buf);
@@ -215,7 +215,7 @@
uint32_t usage = data.readInt32();
int buf;
sp<Fence> fence;
- int result = dequeueBuffer(&buf, fence, w, h, format, usage);
+ int result = dequeueBuffer(&buf, &fence, w, h, format, usage);
reply->writeInt32(buf);
reply->writeInt32(fence != NULL);
if (fence != NULL) {
diff --git a/libs/gui/ISurface.cpp b/libs/gui/ISurface.cpp
deleted file mode 100644
index 8c25f45..0000000
--- a/libs/gui/ISurface.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-#define LOG_TAG "ISurface"
-
-#include <stdio.h>
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <binder/Parcel.h>
-
-#include <gui/ISurface.h>
-#include <gui/IGraphicBufferProducer.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------
-
-class BpSurface : public BpInterface<ISurface>
-{
-public:
- BpSurface(const sp<IBinder>& impl)
- : BpInterface<ISurface>(impl)
- {
- }
-
- virtual sp<IGraphicBufferProducer> getSurfaceTexture() const {
- Parcel data, reply;
- data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
- remote()->transact(GET_SURFACE_TEXTURE, data, &reply);
- return interface_cast<IGraphicBufferProducer>(reply.readStrongBinder());
- }
-};
-
-IMPLEMENT_META_INTERFACE(Surface, "android.ui.ISurface");
-
-// ----------------------------------------------------------------------
-
-status_t BnSurface::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- switch(code) {
- case GET_SURFACE_TEXTURE: {
- CHECK_INTERFACE(ISurface, data, reply);
- reply->writeStrongBinder( getSurfaceTexture()->asBinder() );
- return NO_ERROR;
- }
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-}; // namespace android
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 72b6277..6442a86 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -102,24 +102,22 @@
remote()->transact(BnSurfaceComposer::BOOT_FINISHED, data, &reply);
}
- virtual status_t captureScreen(
- const sp<IBinder>& display, sp<IMemoryHeap>* heap,
- uint32_t* width, uint32_t* height, PixelFormat* format,
+ virtual status_t captureScreen(const sp<IBinder>& display,
+ const sp<IGraphicBufferProducer>& producer,
uint32_t reqWidth, uint32_t reqHeight,
- uint32_t minLayerZ, uint32_t maxLayerZ)
+ uint32_t minLayerZ, uint32_t maxLayerZ,
+ bool isCpuConsumer)
{
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
data.writeStrongBinder(display);
+ data.writeStrongBinder(producer->asBinder());
data.writeInt32(reqWidth);
data.writeInt32(reqHeight);
data.writeInt32(minLayerZ);
data.writeInt32(maxLayerZ);
+ data.writeInt32(isCpuConsumer);
remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply);
- *heap = interface_cast<IMemoryHeap>(reply.readStrongBinder());
- *width = reply.readInt32();
- *height = reply.readInt32();
- *format = reply.readInt32();
return reply.readInt32();
}
@@ -271,19 +269,16 @@
case CAPTURE_SCREEN: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> display = data.readStrongBinder();
+ sp<IGraphicBufferProducer> producer =
+ interface_cast<IGraphicBufferProducer>(data.readStrongBinder());
uint32_t reqWidth = data.readInt32();
uint32_t reqHeight = data.readInt32();
uint32_t minLayerZ = data.readInt32();
uint32_t maxLayerZ = data.readInt32();
- sp<IMemoryHeap> heap;
- uint32_t w, h;
- PixelFormat f;
- status_t res = captureScreen(display, &heap, &w, &h, &f,
- reqWidth, reqHeight, minLayerZ, maxLayerZ);
- reply->writeStrongBinder(heap->asBinder());
- reply->writeInt32(w);
- reply->writeInt32(h);
- reply->writeInt32(f);
+ bool isCpuConsumer = data.readInt32();
+ status_t res = captureScreen(display, producer,
+ reqWidth, reqHeight, minLayerZ, maxLayerZ,
+ isCpuConsumer);
reply->writeInt32(res);
} break;
case AUTHENTICATE_SURFACE: {
diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp
index 101292d..1adc134 100644
--- a/libs/gui/ISurfaceComposerClient.cpp
+++ b/libs/gui/ISurfaceComposerClient.cpp
@@ -29,7 +29,7 @@
#include <ui/Point.h>
#include <ui/Rect.h>
-#include <gui/ISurface.h>
+#include <gui/IGraphicBufferProducer.h>
#include <gui/ISurfaceComposerClient.h>
#include <private/gui/LayerState.h>
@@ -46,16 +46,13 @@
{
public:
BpSurfaceComposerClient(const sp<IBinder>& impl)
- : BpInterface<ISurfaceComposerClient>(impl)
- {
+ : BpInterface<ISurfaceComposerClient>(impl) {
}
- virtual sp<ISurface> createSurface( const String8& name,
- uint32_t w,
- uint32_t h,
- PixelFormat format,
- uint32_t flags)
- {
+ virtual status_t createSurface(const String8& name, uint32_t w,
+ uint32_t h, PixelFormat format, uint32_t flags,
+ sp<IBinder>* handle,
+ sp<IGraphicBufferProducer>* gbp) {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
data.writeString8(name);
@@ -64,11 +61,12 @@
data.writeInt32(format);
data.writeInt32(flags);
remote()->transact(CREATE_SURFACE, data, &reply);
- return interface_cast<ISurface>(reply.readStrongBinder());
+ *handle = reply.readStrongBinder();
+ *gbp = interface_cast<IGraphicBufferProducer>(reply.readStrongBinder());
+ return reply.readInt32();
}
- virtual status_t destroySurface(const sp<IBinder>& handle)
- {
+ virtual status_t destroySurface(const sp<IBinder>& handle) {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
data.writeStrongBinder(handle);
@@ -92,8 +90,13 @@
uint32_t h = data.readInt32();
PixelFormat format = data.readInt32();
uint32_t flags = data.readInt32();
- sp<ISurface> s = createSurface(name, w, h, format, flags);
- reply->writeStrongBinder(s->asBinder());
+ sp<IBinder> handle;
+ sp<IGraphicBufferProducer> gbp;
+ status_t result = createSurface(name, w, h, format, flags,
+ &handle, &gbp);
+ reply->writeStrongBinder(handle);
+ reply->writeStrongBinder(gbp->asBinder());
+ reply->writeInt32(result);
return NO_ERROR;
} break;
case DESTROY_SURFACE: {
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 410ad5d..4a58023 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -38,22 +38,8 @@
Surface::Surface(
const sp<IGraphicBufferProducer>& bufferProducer)
+ : mGraphicBufferProducer(bufferProducer)
{
- Surface::init();
- Surface::setIGraphicBufferProducer(bufferProducer);
-}
-
-Surface::Surface() {
- Surface::init();
-}
-
-Surface::~Surface() {
- if (mConnectedToCpu) {
- Surface::disconnect(NATIVE_WINDOW_API_CPU);
- }
-}
-
-void Surface::init() {
// Initialize the ANativeWindow function pointers.
ANativeWindow::setSwapInterval = hook_setSwapInterval;
ANativeWindow::dequeueBuffer = hook_dequeueBuffer;
@@ -87,10 +73,10 @@
mConnectedToCpu = false;
}
-void Surface::setIGraphicBufferProducer(
- const sp<IGraphicBufferProducer>& bufferProducer)
-{
- mGraphicBufferProducer = bufferProducer;
+Surface::~Surface() {
+ if (mConnectedToCpu) {
+ Surface::disconnect(NATIVE_WINDOW_API_CPU);
+ }
}
sp<IGraphicBufferProducer> Surface::getIGraphicBufferProducer() const {
@@ -196,8 +182,8 @@
int reqW = mReqWidth ? mReqWidth : mUserWidth;
int reqH = mReqHeight ? mReqHeight : mUserHeight;
sp<Fence> fence;
- status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, fence, reqW, reqH,
- mReqFormat, mReqUsage);
+ status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence,
+ reqW, reqH, mReqFormat, mReqUsage);
if (result < 0) {
ALOGV("dequeueBuffer: IGraphicBufferProducer::dequeueBuffer(%d, %d, %d, %d)"
"failed: %d", mReqWidth, mReqHeight, mReqFormat, mReqUsage,
@@ -723,23 +709,6 @@
// ----------------------------------------------------------------------------
-status_t Surface::writeToParcel(
- const sp<Surface>& surface, Parcel* parcel) {
- sp<IGraphicBufferProducer> bp;
- if (surface != NULL) {
- bp = surface->mGraphicBufferProducer;
- }
- return parcel->writeStrongBinder(bp->asBinder());
-}
-
-sp<Surface> Surface::readFromParcel(const Parcel& data) {
- sp<IBinder> binder(data.readStrongBinder());
- sp<IGraphicBufferProducer> bp(interface_cast<IGraphicBufferProducer>(binder));
- return new Surface(bp);
-}
-
-// ----------------------------------------------------------------------------
-
status_t Surface::lock(
ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds)
{
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index e8e208f..ec46fce 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -31,8 +31,8 @@
#include <ui/DisplayInfo.h>
+#include <gui/CpuConsumer.h>
#include <gui/IGraphicBufferProducer.h>
-#include <gui/ISurface.h>
#include <gui/ISurfaceComposer.h>
#include <gui/ISurfaceComposerClient.h>
#include <gui/SurfaceComposerClient.h>
@@ -471,14 +471,18 @@
PixelFormat format,
uint32_t flags)
{
- sp<SurfaceControl> result;
+ sp<SurfaceControl> sur;
if (mStatus == NO_ERROR) {
- sp<ISurface> surface = mClient->createSurface(name, w, h, format, flags);
- if (surface != 0) {
- result = new SurfaceControl(this, surface);
+ sp<IBinder> handle;
+ sp<IGraphicBufferProducer> gbp;
+ status_t err = mClient->createSurface(name, w, h, format, flags,
+ &handle, &gbp);
+ ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err));
+ if (err == NO_ERROR) {
+ sur = new SurfaceControl(this, handle, gbp);
}
}
- return result;
+ return sur;
}
sp<IBinder> SurfaceComposerClient::createDisplay(const String8& displayName,
@@ -606,27 +610,29 @@
// ----------------------------------------------------------------------------
+status_t ScreenshotClient::capture(
+ const sp<IBinder>& display,
+ const sp<IGraphicBufferProducer>& producer,
+ uint32_t reqWidth, uint32_t reqHeight,
+ uint32_t minLayerZ, uint32_t maxLayerZ) {
+ sp<ISurfaceComposer> s(ComposerService::getComposerService());
+ if (s == NULL) return NO_INIT;
+ return s->captureScreen(display, producer,
+ reqWidth, reqHeight, minLayerZ, maxLayerZ,
+ false);
+}
+
ScreenshotClient::ScreenshotClient()
- : mWidth(0), mHeight(0), mFormat(PIXEL_FORMAT_NONE) {
+ : mHaveBuffer(false) {
+ memset(&mBuffer, 0, sizeof(mBuffer));
}
-status_t ScreenshotClient::update(const sp<IBinder>& display) {
- sp<ISurfaceComposer> s(ComposerService::getComposerService());
- if (s == NULL) return NO_INIT;
- mHeap = 0;
- return s->captureScreen(display, &mHeap,
- &mWidth, &mHeight, &mFormat, 0, 0,
- 0, -1UL);
-}
-
-status_t ScreenshotClient::update(const sp<IBinder>& display,
- uint32_t reqWidth, uint32_t reqHeight) {
- sp<ISurfaceComposer> s(ComposerService::getComposerService());
- if (s == NULL) return NO_INIT;
- mHeap = 0;
- return s->captureScreen(display, &mHeap,
- &mWidth, &mHeight, &mFormat, reqWidth, reqHeight,
- 0, -1UL);
+sp<CpuConsumer> ScreenshotClient::getCpuConsumer() const {
+ if (mCpuConsumer == NULL) {
+ mCpuConsumer = new CpuConsumer(1);
+ mCpuConsumer->setName(String8("ScreenshotClient"));
+ }
+ return mCpuConsumer;
}
status_t ScreenshotClient::update(const sp<IBinder>& display,
@@ -634,38 +640,66 @@
uint32_t minLayerZ, uint32_t maxLayerZ) {
sp<ISurfaceComposer> s(ComposerService::getComposerService());
if (s == NULL) return NO_INIT;
- mHeap = 0;
- return s->captureScreen(display, &mHeap,
- &mWidth, &mHeight, &mFormat, reqWidth, reqHeight,
- minLayerZ, maxLayerZ);
+ sp<CpuConsumer> cpuConsumer = getCpuConsumer();
+
+ if (mHaveBuffer) {
+ mCpuConsumer->unlockBuffer(mBuffer);
+ memset(&mBuffer, 0, sizeof(mBuffer));
+ mHaveBuffer = false;
+ }
+
+ status_t err = s->captureScreen(display,cpuConsumer->getBufferQueue(),
+ reqWidth, reqHeight, minLayerZ, maxLayerZ, true);
+
+ if (err == NO_ERROR) {
+ err = mCpuConsumer->lockNextBuffer(&mBuffer);
+ if (err == NO_ERROR) {
+ mHaveBuffer = true;
+ }
+ }
+ return err;
+}
+
+status_t ScreenshotClient::update(const sp<IBinder>& display) {
+ return ScreenshotClient::update(display, 0, 0, 0, -1UL);
+}
+
+status_t ScreenshotClient::update(const sp<IBinder>& display,
+ uint32_t reqWidth, uint32_t reqHeight) {
+ return ScreenshotClient::update(display, reqWidth, reqHeight, 0, -1UL);
}
void ScreenshotClient::release() {
- mHeap = 0;
+ if (mHaveBuffer) {
+ mCpuConsumer->unlockBuffer(mBuffer);
+ memset(&mBuffer, 0, sizeof(mBuffer));
+ mHaveBuffer = false;
+ }
+ mCpuConsumer.clear();
}
void const* ScreenshotClient::getPixels() const {
- return mHeap->getBase();
+ return mBuffer.data;
}
uint32_t ScreenshotClient::getWidth() const {
- return mWidth;
+ return mBuffer.width;
}
uint32_t ScreenshotClient::getHeight() const {
- return mHeight;
+ return mBuffer.height;
}
PixelFormat ScreenshotClient::getFormat() const {
- return mFormat;
+ return mBuffer.format;
}
uint32_t ScreenshotClient::getStride() const {
- return mWidth;
+ return mBuffer.stride;
}
size_t ScreenshotClient::getSize() const {
- return mHeap->getSize();
+ return mBuffer.stride * mBuffer.height * bytesPerPixel(mBuffer.format);
}
// ----------------------------------------------------------------------------
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index ef52269..f4e88f5 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -34,7 +34,6 @@
#include <ui/GraphicBuffer.h>
#include <ui/Rect.h>
-#include <gui/ISurface.h>
#include <gui/ISurfaceComposer.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
@@ -48,13 +47,10 @@
SurfaceControl::SurfaceControl(
const sp<SurfaceComposerClient>& client,
- const sp<ISurface>& surface)
- : mClient(client)
+ const sp<IBinder>& handle,
+ const sp<IGraphicBufferProducer>& gbp)
+ : mClient(client), mHandle(handle), mGraphicBufferProducer(gbp)
{
- if (surface != 0) {
- mSurface = surface->asBinder();
- mGraphicBufferProducer = surface->getSurfaceTexture();
- }
}
SurfaceControl::~SurfaceControl()
@@ -65,12 +61,12 @@
void SurfaceControl::destroy()
{
if (isValid()) {
- mClient->destroySurface(mSurface);
+ mClient->destroySurface(mHandle);
}
// clear all references and trigger an IPC now, to make sure things
// happen without delay, since these resources are quite heavy.
mClient.clear();
- mSurface.clear();
+ mHandle.clear();
mGraphicBufferProducer.clear();
IPCThreadState::self()->flushCommands();
}
@@ -91,81 +87,81 @@
{
if (lhs == 0 || rhs == 0)
return false;
- return lhs->mSurface == rhs->mSurface;
+ return lhs->mHandle == rhs->mHandle;
}
status_t SurfaceControl::setLayerStack(int32_t layerStack) {
status_t err = validate();
if (err < 0) return err;
const sp<SurfaceComposerClient>& client(mClient);
- return client->setLayerStack(mSurface, layerStack);
+ return client->setLayerStack(mHandle, layerStack);
}
status_t SurfaceControl::setLayer(int32_t layer) {
status_t err = validate();
if (err < 0) return err;
const sp<SurfaceComposerClient>& client(mClient);
- return client->setLayer(mSurface, layer);
+ return client->setLayer(mHandle, layer);
}
-status_t SurfaceControl::setPosition(int32_t x, int32_t y) {
+status_t SurfaceControl::setPosition(float x, float y) {
status_t err = validate();
if (err < 0) return err;
const sp<SurfaceComposerClient>& client(mClient);
- return client->setPosition(mSurface, x, y);
+ return client->setPosition(mHandle, x, y);
}
status_t SurfaceControl::setSize(uint32_t w, uint32_t h) {
status_t err = validate();
if (err < 0) return err;
const sp<SurfaceComposerClient>& client(mClient);
- return client->setSize(mSurface, w, h);
+ return client->setSize(mHandle, w, h);
}
status_t SurfaceControl::hide() {
status_t err = validate();
if (err < 0) return err;
const sp<SurfaceComposerClient>& client(mClient);
- return client->hide(mSurface);
+ return client->hide(mHandle);
}
status_t SurfaceControl::show() {
status_t err = validate();
if (err < 0) return err;
const sp<SurfaceComposerClient>& client(mClient);
- return client->show(mSurface);
+ return client->show(mHandle);
}
status_t SurfaceControl::setFlags(uint32_t flags, uint32_t mask) {
status_t err = validate();
if (err < 0) return err;
const sp<SurfaceComposerClient>& client(mClient);
- return client->setFlags(mSurface, flags, mask);
+ return client->setFlags(mHandle, flags, mask);
}
status_t SurfaceControl::setTransparentRegionHint(const Region& transparent) {
status_t err = validate();
if (err < 0) return err;
const sp<SurfaceComposerClient>& client(mClient);
- return client->setTransparentRegionHint(mSurface, transparent);
+ return client->setTransparentRegionHint(mHandle, transparent);
}
status_t SurfaceControl::setAlpha(float alpha) {
status_t err = validate();
if (err < 0) return err;
const sp<SurfaceComposerClient>& client(mClient);
- return client->setAlpha(mSurface, alpha);
+ return client->setAlpha(mHandle, alpha);
}
status_t SurfaceControl::setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
status_t err = validate();
if (err < 0) return err;
const sp<SurfaceComposerClient>& client(mClient);
- return client->setMatrix(mSurface, dsdx, dtdx, dsdy, dtdy);
+ return client->setMatrix(mHandle, dsdx, dtdx, dsdy, dtdy);
}
status_t SurfaceControl::setCrop(const Rect& crop) {
status_t err = validate();
if (err < 0) return err;
const sp<SurfaceComposerClient>& client(mClient);
- return client->setCrop(mSurface, crop);
+ return client->setCrop(mHandle, crop);
}
status_t SurfaceControl::validate() const
{
- if (mSurface==0 || mClient==0) {
- ALOGE("invalid ISurface (%p) or client (%p)",
- mSurface.get(), mClient.get());
+ if (mHandle==0 || mClient==0) {
+ ALOGE("invalid handle (%p) or client (%p)",
+ mHandle.get(), mClient.get());
return NO_INIT;
}
return NO_ERROR;
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index 93f8faf..62d215b 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -76,7 +76,7 @@
for (int i = 0; i < 2; i++) {
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
- mBQ->dequeueBuffer(&slot, fence, 1, 1, 0,
+ mBQ->dequeueBuffer(&slot, &fence, 1, 1, 0,
GRALLOC_USAGE_SW_READ_OFTEN));
ASSERT_EQ(OK, mBQ->requestBuffer(slot, &buf));
ASSERT_EQ(OK, mBQ->queueBuffer(slot, qbi, &qbo));
@@ -84,7 +84,7 @@
}
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
- mBQ->dequeueBuffer(&slot, fence, 1, 1, 0,
+ mBQ->dequeueBuffer(&slot, &fence, 1, 1, 0,
GRALLOC_USAGE_SW_READ_OFTEN));
ASSERT_EQ(OK, mBQ->requestBuffer(slot, &buf));
ASSERT_EQ(OK, mBQ->queueBuffer(slot, qbi, &qbo));
diff --git a/libs/gui/tests/CpuConsumer_test.cpp b/libs/gui/tests/CpuConsumer_test.cpp
index 12ae19c..73fdd04 100644
--- a/libs/gui/tests/CpuConsumer_test.cpp
+++ b/libs/gui/tests/CpuConsumer_test.cpp
@@ -35,6 +35,11 @@
#include <ui/FramebufferNativeWindow.h>
+#define CPU_CONSUMER_TEST_FORMAT_RAW 0
+#define CPU_CONSUMER_TEST_FORMAT_Y8 0
+#define CPU_CONSUMER_TEST_FORMAT_Y16 0
+#define CPU_CONSUMER_TEST_FORMAT_RGBA_8888 1
+
namespace android {
struct CpuConsumerTestParams {
@@ -157,7 +162,7 @@
ASSERT_EQ(NO_ERROR, err) << msg << strerror(-err)
void checkPixel(const CpuConsumer::LockedBuffer &buf,
- uint32_t x, uint32_t y, uint32_t r, uint32_t g, uint32_t b) {
+ uint32_t x, uint32_t y, uint32_t r, uint32_t g=0, uint32_t b=0) {
// Ignores components that don't exist for given pixel
switch(buf.format) {
case HAL_PIXEL_FORMAT_RAW_SENSOR: {
@@ -179,6 +184,31 @@
}
break;
}
+ // ignores g,b
+ case HAL_PIXEL_FORMAT_Y8: {
+ uint8_t *bPtr = (uint8_t*)buf.data;
+ bPtr += y * buf.stride + x;
+ EXPECT_EQ(r, *bPtr) << "at x = " << x << " y = " << y;
+ break;
+ }
+ // ignores g,b
+ case HAL_PIXEL_FORMAT_Y16: {
+ // stride is in pixels, not in bytes
+ uint16_t *bPtr = ((uint16_t*)buf.data) + y * buf.stride + x;
+
+ EXPECT_EQ(r, *bPtr) << "at x = " << x << " y = " << y;
+ break;
+ }
+ case HAL_PIXEL_FORMAT_RGBA_8888: {
+ const int bytesPerPixel = 4;
+ uint8_t *bPtr = (uint8_t*)buf.data;
+ bPtr += (y * buf.stride + x) * bytesPerPixel;
+
+ EXPECT_EQ(r, bPtr[0]) << "at x = " << x << " y = " << y;
+ EXPECT_EQ(g, bPtr[1]) << "at x = " << x << " y = " << y;
+ EXPECT_EQ(b, bPtr[2]) << "at x = " << x << " y = " << y;
+ break;
+ }
default: {
ADD_FAILURE() << "Unknown format for check:" << buf.format;
break;
@@ -189,6 +219,61 @@
// Fill a YV12 buffer with a multi-colored checkerboard pattern
void fillYV12Buffer(uint8_t* buf, int w, int h, int stride);
+// Fill a Y8/Y16 buffer with a multi-colored checkerboard pattern
+template <typename T> // T == uint8_t or uint16_t
+void fillGreyscaleBuffer(T* buf, int w, int h, int stride, int bpp) {
+ const int blockWidth = w > 16 ? w / 16 : 1;
+ const int blockHeight = h > 16 ? h / 16 : 1;
+ const int yuvTexOffsetY = 0;
+
+ ASSERT_TRUE(bpp == 8 || bpp == 16);
+ ASSERT_TRUE(sizeof(T)*8 == bpp);
+
+ // stride is in pixels, not in bytes
+ int yuvTexStrideY = stride;
+ for (int x = 0; x < w; x++) {
+ for (int y = 0; y < h; y++) {
+ int parityX = (x / blockWidth) & 1;
+ int parityY = (y / blockHeight) & 1;
+ T intensity = (parityX ^ parityY) ? 63 : 191;
+ buf[yuvTexOffsetY + (y * yuvTexStrideY) + x] = intensity;
+ }
+ }
+}
+
+inline uint8_t chooseColorRgba8888(int blockX, int blockY, uint8_t channel) {
+ const int colorVariations = 3;
+ uint8_t color = ((blockX % colorVariations) + (blockY % colorVariations))
+ % (colorVariations) == channel ? 191: 63;
+
+ return color;
+}
+
+// Fill a RGBA8888 buffer with a multi-colored checkerboard pattern
+void fillRgba8888Buffer(uint8_t* buf, int w, int h, int stride)
+{
+ const int blockWidth = w > 16 ? w / 16 : 1;
+ const int blockHeight = h > 16 ? h / 16 : 1;
+ const int bytesPerPixel = 4;
+
+ // stride is in pixels, not in bytes
+ for (int x = 0; x < w; ++x) {
+ for (int y = 0; y < h; ++y) {
+ int blockX = (x / blockWidth);
+ int blockY = (y / blockHeight);
+
+ uint8_t r = chooseColorRgba8888(blockX, blockY, 0);
+ uint8_t g = chooseColorRgba8888(blockX, blockY, 1);
+ uint8_t b = chooseColorRgba8888(blockX, blockY, 2);
+
+ buf[(y*stride + x)*bytesPerPixel + 0] = r;
+ buf[(y*stride + x)*bytesPerPixel + 1] = g;
+ buf[(y*stride + x)*bytesPerPixel + 2] = b;
+ buf[(y*stride + x)*bytesPerPixel + 3] = 255;
+ }
+ }
+}
+
// Fill a RAW sensor buffer with a multi-colored checkerboard pattern.
// Assumes GRBG mosaic ordering. Result should be a grid in a 2x2 pattern
// of [ R, B; G, W]
@@ -217,6 +302,89 @@
}
+template<typename T> // uint8_t or uint16_t
+void checkGreyscaleBuffer(const CpuConsumer::LockedBuffer &buf) {
+ uint32_t w = buf.width;
+ uint32_t h = buf.height;
+ const int blockWidth = w > 16 ? w / 16 : 1;
+ const int blockHeight = h > 16 ? h / 16 : 1;
+ const int blockRows = h / blockHeight;
+ const int blockCols = w / blockWidth;
+
+ // Top-left square is bright
+ checkPixel(buf, 0, 0, 191);
+ checkPixel(buf, 1, 0, 191);
+ checkPixel(buf, 0, 1, 191);
+ checkPixel(buf, 1, 1, 191);
+
+ // One-right square is dark
+ checkPixel(buf, blockWidth, 0, 63);
+ checkPixel(buf, blockWidth + 1, 0, 63);
+ checkPixel(buf, blockWidth, 1, 63);
+ checkPixel(buf, blockWidth + 1, 1, 63);
+
+ // One-down square is dark
+ checkPixel(buf, 0, blockHeight, 63);
+ checkPixel(buf, 1, blockHeight, 63);
+ checkPixel(buf, 0, blockHeight + 1, 63);
+ checkPixel(buf, 1, blockHeight + 1, 63);
+
+ // One-diag square is bright
+ checkPixel(buf, blockWidth, blockHeight, 191);
+ checkPixel(buf, blockWidth + 1, blockHeight, 191);
+ checkPixel(buf, blockWidth, blockHeight + 1, 191);
+ checkPixel(buf, blockWidth + 1, blockHeight + 1, 191);
+
+ // Test bottom-right pixel
+ const int maxBlockX = ((w-1 + (blockWidth-1)) / blockWidth) & 0x1;
+ const int maxBlockY = ((h-1 + (blockHeight-1)) / blockHeight) & 0x1;
+ uint32_t pixelValue = ((maxBlockX % 2) == (maxBlockY % 2)) ? 191 : 63;
+ checkPixel(buf, w-1, h-1, pixelValue);
+}
+
+void checkRgba8888Buffer(const CpuConsumer::LockedBuffer &buf) {
+ uint32_t w = buf.width;
+ uint32_t h = buf.height;
+ const int blockWidth = w > 16 ? w / 16 : 1;
+ const int blockHeight = h > 16 ? h / 16 : 1;
+ const int blockRows = h / blockHeight;
+ const int blockCols = w / blockWidth;
+
+ // Top-left square is bright red
+ checkPixel(buf, 0, 0, 191, 63, 63);
+ checkPixel(buf, 1, 0, 191, 63, 63);
+ checkPixel(buf, 0, 1, 191, 63, 63);
+ checkPixel(buf, 1, 1, 191, 63, 63);
+
+ // One-right square is bright green
+ checkPixel(buf, blockWidth, 0, 63, 191, 63);
+ checkPixel(buf, blockWidth + 1, 0, 63, 191, 63);
+ checkPixel(buf, blockWidth, 1, 63, 191, 63);
+ checkPixel(buf, blockWidth + 1, 1, 63, 191, 63);
+
+ // One-down square is bright green
+ checkPixel(buf, 0, blockHeight, 63, 191, 63);
+ checkPixel(buf, 1, blockHeight, 63, 191, 63);
+ checkPixel(buf, 0, blockHeight + 1, 63, 191, 63);
+ checkPixel(buf, 1, blockHeight + 1, 63, 191, 63);
+
+ // One-diag square is bright blue
+ checkPixel(buf, blockWidth, blockHeight, 63, 63, 191);
+ checkPixel(buf, blockWidth + 1, blockHeight, 63, 63, 191);
+ checkPixel(buf, blockWidth, blockHeight + 1, 63, 63, 191);
+ checkPixel(buf, blockWidth + 1, blockHeight + 1, 63, 63, 191);
+
+ // Test bottom-right pixel
+ {
+ const int maxBlockX = ((w-1) / blockWidth);
+ const int maxBlockY = ((h-1) / blockHeight);
+ uint8_t r = chooseColorRgba8888(maxBlockX, maxBlockY, 0);
+ uint8_t g = chooseColorRgba8888(maxBlockX, maxBlockY, 1);
+ uint8_t b = chooseColorRgba8888(maxBlockX, maxBlockY, 2);
+ checkPixel(buf, w-1, h-1, r, g, b);
+ }
+}
+
void checkBayerRawBuffer(const CpuConsumer::LockedBuffer &buf) {
uint32_t w = buf.width;
uint32_t h = buf.height;
@@ -258,6 +426,23 @@
checkPixel(buf, w-1, h-1, maxR, maxG, maxB);
}
+void checkAnyBuffer(const CpuConsumer::LockedBuffer &buf, int format) {
+ switch (format) {
+ case HAL_PIXEL_FORMAT_RAW_SENSOR:
+ checkBayerRawBuffer(buf);
+ break;
+ case HAL_PIXEL_FORMAT_Y8:
+ checkGreyscaleBuffer<uint8_t>(buf);
+ break;
+ case HAL_PIXEL_FORMAT_Y16:
+ checkGreyscaleBuffer<uint16_t>(buf);
+ break;
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ checkRgba8888Buffer(buf);
+ break;
+ }
+}
+
void fillYV12BufferRect(uint8_t* buf, int w, int h, int stride,
const android_native_rect_t& rect);
@@ -322,6 +507,18 @@
case HAL_PIXEL_FORMAT_RAW_SENSOR:
fillBayerRawBuffer(img, params.width, params.height, buf->getStride());
break;
+ case HAL_PIXEL_FORMAT_Y8:
+ fillGreyscaleBuffer<uint8_t>(img, params.width, params.height,
+ buf->getStride(), /*bpp*/8);
+ break;
+ case HAL_PIXEL_FORMAT_Y16:
+ fillGreyscaleBuffer<uint16_t>((uint16_t*)img, params.width,
+ params.height, buf->getStride(),
+ /*bpp*/16);
+ break;
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ fillRgba8888Buffer(img, params.width, params.height, buf->getStride());
+ break;
default:
FAIL() << "Unknown pixel format under test!";
break;
@@ -341,7 +538,7 @@
// This test is disabled because the HAL_PIXEL_FORMAT_RAW_SENSOR format is not
// supported on all devices.
-TEST_P(CpuConsumerTest, DISABLED_FromCpuSingle) {
+TEST_P(CpuConsumerTest, FromCpuSingle) {
status_t err;
CpuConsumerTestParams params = GetParam();
@@ -369,13 +566,13 @@
EXPECT_EQ(stride, b.stride);
EXPECT_EQ(time, b.timestamp);
- checkBayerRawBuffer(b);
+ checkAnyBuffer(b, GetParam().format);
mCC->unlockBuffer(b);
}
// This test is disabled because the HAL_PIXEL_FORMAT_RAW_SENSOR format is not
// supported on all devices.
-TEST_P(CpuConsumerTest, DISABLED_FromCpuManyInQueue) {
+TEST_P(CpuConsumerTest, FromCpuManyInQueue) {
status_t err;
CpuConsumerTestParams params = GetParam();
@@ -410,7 +607,7 @@
EXPECT_EQ(stride[i], b.stride);
EXPECT_EQ(time[i], b.timestamp);
- checkBayerRawBuffer(b);
+ checkAnyBuffer(b, GetParam().format);
mCC->unlockBuffer(b);
}
@@ -418,7 +615,7 @@
// This test is disabled because the HAL_PIXEL_FORMAT_RAW_SENSOR format is not
// supported on all devices.
-TEST_P(CpuConsumerTest, DISABLED_FromCpuLockMax) {
+TEST_P(CpuConsumerTest, FromCpuLockMax) {
status_t err;
CpuConsumerTestParams params = GetParam();
@@ -452,7 +649,7 @@
EXPECT_EQ(stride, b[i].stride);
EXPECT_EQ(time, b[i].timestamp);
- checkBayerRawBuffer(b[i]);
+ checkAnyBuffer(b[i], GetParam().format);
}
ALOGV("Locking frame %d (too many)", params.maxLockedBuffers);
@@ -475,7 +672,7 @@
EXPECT_EQ(stride, bTooMuch.stride);
EXPECT_EQ(time, bTooMuch.timestamp);
- checkBayerRawBuffer(bTooMuch);
+ checkAnyBuffer(bTooMuch, GetParam().format);
ALOGV("Unlocking extra buffer");
err = mCC->unlockBuffer(bTooMuch);
@@ -493,17 +690,66 @@
}
+CpuConsumerTestParams y8TestSets[] = {
+ { 512, 512, 1, HAL_PIXEL_FORMAT_Y8},
+ { 512, 512, 3, HAL_PIXEL_FORMAT_Y8},
+ { 2608, 1960, 1, HAL_PIXEL_FORMAT_Y8},
+ { 2608, 1960, 3, HAL_PIXEL_FORMAT_Y8},
+ { 100, 100, 1, HAL_PIXEL_FORMAT_Y8},
+ { 100, 100, 3, HAL_PIXEL_FORMAT_Y8},
+};
+
+CpuConsumerTestParams y16TestSets[] = {
+ { 512, 512, 1, HAL_PIXEL_FORMAT_Y16},
+ { 512, 512, 3, HAL_PIXEL_FORMAT_Y16},
+ { 2608, 1960, 1, HAL_PIXEL_FORMAT_Y16},
+ { 2608, 1960, 3, HAL_PIXEL_FORMAT_Y16},
+ { 100, 100, 1, HAL_PIXEL_FORMAT_Y16},
+ { 100, 100, 3, HAL_PIXEL_FORMAT_Y16},
+};
+
CpuConsumerTestParams rawTestSets[] = {
{ 512, 512, 1, HAL_PIXEL_FORMAT_RAW_SENSOR},
{ 512, 512, 3, HAL_PIXEL_FORMAT_RAW_SENSOR},
{ 2608, 1960, 1, HAL_PIXEL_FORMAT_RAW_SENSOR},
{ 2608, 1960, 3, HAL_PIXEL_FORMAT_RAW_SENSOR},
{ 100, 100, 1, HAL_PIXEL_FORMAT_RAW_SENSOR},
- { 100, 100, 3, HAL_PIXEL_FORMAT_RAW_SENSOR}
+ { 100, 100, 3, HAL_PIXEL_FORMAT_RAW_SENSOR},
};
+CpuConsumerTestParams rgba8888TestSets[] = {
+ { 512, 512, 1, HAL_PIXEL_FORMAT_RGBA_8888},
+ { 512, 512, 3, HAL_PIXEL_FORMAT_RGBA_8888},
+ { 2608, 1960, 1, HAL_PIXEL_FORMAT_RGBA_8888},
+ { 2608, 1960, 3, HAL_PIXEL_FORMAT_RGBA_8888},
+ { 100, 100, 1, HAL_PIXEL_FORMAT_RGBA_8888},
+ { 100, 100, 3, HAL_PIXEL_FORMAT_RGBA_8888},
+};
+
+#if CPU_CONSUMER_TEST_FORMAT_Y8
+INSTANTIATE_TEST_CASE_P(Y8Tests,
+ CpuConsumerTest,
+ ::testing::ValuesIn(y8TestSets));
+#endif
+
+#if CPU_CONSUMER_TEST_FORMAT_Y16
+INSTANTIATE_TEST_CASE_P(Y16Tests,
+ CpuConsumerTest,
+ ::testing::ValuesIn(y16TestSets));
+#endif
+
+#if CPU_CONSUMER_TEST_FORMAT_RAW
INSTANTIATE_TEST_CASE_P(RawTests,
CpuConsumerTest,
::testing::ValuesIn(rawTestSets));
+#endif
+
+#if CPU_CONSUMER_TEST_FORMAT_RGBA_8888
+INSTANTIATE_TEST_CASE_P(Rgba8888Tests,
+ CpuConsumerTest,
+ ::testing::ValuesIn(rgba8888TestSets));
+#endif
+
+
} // namespace android
diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp
index fbaf6aa..2d30305 100644
--- a/libs/gui/tests/SurfaceTexture_test.cpp
+++ b/libs/gui/tests/SurfaceTexture_test.cpp
@@ -1636,6 +1636,81 @@
}
}
+TEST_F(SurfaceTextureGLToGLTest, EglMakeCurrentBeforeConsumerDeathUnrefsBuffers) {
+ sp<GraphicBuffer> buffer;
+
+ EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
+ mProducerEglSurface, mProducerEglContext));
+
+ // Produce a frame
+ glClear(GL_COLOR_BUFFER_BIT);
+ EXPECT_TRUE(eglSwapBuffers(mEglDisplay, mProducerEglSurface));
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+ // Destroy the EGLSurface.
+ EXPECT_TRUE(eglDestroySurface(mEglDisplay, mProducerEglSurface));
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ mProducerEglSurface = EGL_NO_SURFACE;
+ mSTC.clear();
+ mANW.clear();
+ mTextureRenderer.clear();
+
+ // Consume a frame
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
+ buffer = mST->getCurrentBuffer();
+
+ // Destroy the GL texture object to release its ref
+ GLuint texID = TEX_ID;
+ glDeleteTextures(1, &texID);
+
+ // make un-current, all references to buffer should be gone
+ EXPECT_TRUE(eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE,
+ EGL_NO_SURFACE, EGL_NO_CONTEXT));
+
+ // Destroy consumer
+ mST.clear();
+
+ EXPECT_EQ(1, buffer->getStrongCount());
+}
+
+TEST_F(SurfaceTextureGLToGLTest, EglMakeCurrentAfterConsumerDeathUnrefsBuffers) {
+ sp<GraphicBuffer> buffer;
+
+ EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
+ mProducerEglSurface, mProducerEglContext));
+
+ // Produce a frame
+ glClear(GL_COLOR_BUFFER_BIT);
+ EXPECT_TRUE(eglSwapBuffers(mEglDisplay, mProducerEglSurface));
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+ // Destroy the EGLSurface.
+ EXPECT_TRUE(eglDestroySurface(mEglDisplay, mProducerEglSurface));
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ mProducerEglSurface = EGL_NO_SURFACE;
+ mSTC.clear();
+ mANW.clear();
+ mTextureRenderer.clear();
+
+ // Consume a frame
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
+ buffer = mST->getCurrentBuffer();
+
+ // Destroy the GL texture object to release its ref
+ GLuint texID = TEX_ID;
+ glDeleteTextures(1, &texID);
+
+ // Destroy consumer
+ mST.clear();
+
+ // make un-current, all references to buffer should be gone
+ EXPECT_TRUE(eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE,
+ EGL_NO_SURFACE, EGL_NO_CONTEXT));
+
+ EXPECT_EQ(1, buffer->getStrongCount());
+}
+
+
TEST_F(SurfaceTextureGLToGLTest, EglSurfaceDefaultsToSynchronousMode) {
// This test requires 3 buffers to run on a single thread.
mST->setDefaultMaxBufferCount(3);
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 545b547..429becf 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -23,11 +23,17 @@
#include <utils/String8.h>
#include <private/gui/ComposerService.h>
+#include <binder/ProcessState.h>
namespace android {
class SurfaceTest : public ::testing::Test {
protected:
+
+ SurfaceTest() {
+ ProcessState::self()->startThreadPool();
+ }
+
virtual void SetUp() {
mComposerClient = new SurfaceComposerClient;
ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
@@ -81,14 +87,11 @@
sp<ANativeWindow> anw(mSurface);
// Verify the screenshot works with no protected buffers.
- sp<IMemoryHeap> heap;
- uint32_t w=0, h=0;
- PixelFormat fmt=0;
+ sp<CpuConsumer> consumer = new CpuConsumer(1);
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
sp<IBinder> display(sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
- ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &heap, &w, &h, &fmt, 64, 64, 0,
- 0x7fffffff));
- ASSERT_TRUE(heap != NULL);
+ ASSERT_EQ(NO_ERROR, sf->captureScreen(display, consumer->getBufferQueue(),
+ 64, 64, 0, 0x7fffffff, true));
// Set the PROTECTED usage bit and verify that the screenshot fails. Note
// that we need to dequeue a buffer in order for it to actually get
@@ -116,11 +119,8 @@
&buf));
ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf, -1));
}
- heap = 0;
- w = h = fmt = 0;
- ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &heap, &w, &h, &fmt,
- 64, 64, 0, 0x7fffffff));
- ASSERT_TRUE(heap != NULL);
+ ASSERT_EQ(NO_ERROR, sf->captureScreen(display, consumer->getBufferQueue(),
+ 64, 64, 0, 0x7fffffff, true));
}
TEST_F(SurfaceTest, ConcreteTypeIsSurface) {
diff --git a/libs/utils/RefBase.cpp b/libs/utils/RefBase.cpp
index e80a795..3d3a595 100644
--- a/libs/utils/RefBase.cpp
+++ b/libs/utils/RefBase.cpp
@@ -15,6 +15,7 @@
*/
#define LOG_TAG "RefBase"
+// #define LOG_NDEBUG 0
#include <utils/RefBase.h>
@@ -34,10 +35,18 @@
// compile with refcounting debugging enabled
#define DEBUG_REFS 0
-#define DEBUG_REFS_FATAL_SANITY_CHECKS 0
-#define DEBUG_REFS_ENABLED_BY_DEFAULT 1
+
+// whether ref-tracking is enabled by default, if not, trackMe(true, false)
+// needs to be called explicitly
+#define DEBUG_REFS_ENABLED_BY_DEFAULT 0
+
+// whether callstack are collected (significantly slows things down)
#define DEBUG_REFS_CALLSTACK_ENABLED 1
+// folder where stack traces are saved when DEBUG_REFS is enabled
+// this folder needs to exist and be writable
+#define DEBUG_REFS_CALLSTACK_PATH "/data/debug"
+
// log all reference counting operations
#define PRINT_REFS 0
@@ -95,11 +104,7 @@
bool dumpStack = false;
if (!mRetain && mStrongRefs != NULL) {
dumpStack = true;
-#if DEBUG_REFS_FATAL_SANITY_CHECKS
- LOG_ALWAYS_FATAL("Strong references remain!");
-#else
ALOGE("Strong references remain:");
-#endif
ref_entry* refs = mStrongRefs;
while (refs) {
char inc = refs->ref >= 0 ? '+' : '-';
@@ -113,11 +118,7 @@
if (!mRetain && mWeakRefs != NULL) {
dumpStack = true;
-#if DEBUG_REFS_FATAL_SANITY_CHECKS
- LOG_ALWAYS_FATAL("Weak references remain:");
-#else
ALOGE("Weak references remain!");
-#endif
ref_entry* refs = mWeakRefs;
while (refs) {
char inc = refs->ref >= 0 ? '+' : '-';
@@ -198,8 +199,8 @@
{
char name[100];
- snprintf(name, 100, "/data/%p.stack", this);
- int rc = open(name, O_RDWR | O_CREAT | O_APPEND);
+ snprintf(name, 100, DEBUG_REFS_CALLSTACK_PATH "/%p.stack", this);
+ int rc = open(name, O_RDWR | O_CREAT | O_APPEND, 644);
if (rc >= 0) {
write(rc, text.string(), text.length());
close(rc);
@@ -257,12 +258,6 @@
ref = *refs;
}
-#if DEBUG_REFS_FATAL_SANITY_CHECKS
- LOG_ALWAYS_FATAL("RefBase: removing id %p on RefBase %p"
- "(weakref_type %p) that doesn't exist!",
- id, mBase, this);
-#endif
-
ALOGE("RefBase: removing id %p on RefBase %p"
"(weakref_type %p) that doesn't exist!",
id, mBase, this);
@@ -440,39 +435,68 @@
incWeak(id);
weakref_impl* const impl = static_cast<weakref_impl*>(this);
-
int32_t curCount = impl->mStrong;
- ALOG_ASSERT(curCount >= 0, "attemptIncStrong called on %p after underflow",
- this);
+
+ ALOG_ASSERT(curCount >= 0,
+ "attemptIncStrong called on %p after underflow", this);
+
while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
+ // we're in the easy/common case of promoting a weak-reference
+ // from an existing strong reference.
if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) {
break;
}
+ // the strong count has changed on us, we need to re-assert our
+ // situation.
curCount = impl->mStrong;
}
if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
- bool allow;
- if (curCount == INITIAL_STRONG_VALUE) {
- // Attempting to acquire first strong reference... this is allowed
- // if the object does NOT have a longer lifetime (meaning the
- // implementation doesn't need to see this), or if the implementation
- // allows it to happen.
- allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK
- || impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
+ // we're now in the harder case of either:
+ // - there never was a strong reference on us
+ // - or, all strong references have been released
+ if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
+ // this object has a "normal" life-time, i.e.: it gets destroyed
+ // when the last strong reference goes away
+ if (curCount <= 0) {
+ // the last strong-reference got released, the object cannot
+ // be revived.
+ decWeak(id);
+ return false;
+ }
+
+ // here, curCount == INITIAL_STRONG_VALUE, which means
+ // there never was a strong-reference, so we can try to
+ // promote this object; we need to do that atomically.
+ while (curCount > 0) {
+ if (android_atomic_cmpxchg(curCount, curCount + 1,
+ &impl->mStrong) == 0) {
+ break;
+ }
+ // the strong count has changed on us, we need to re-assert our
+ // situation (e.g.: another thread has inc/decStrong'ed us)
+ curCount = impl->mStrong;
+ }
+
+ if (curCount <= 0) {
+ // promote() failed, some other thread destroyed us in the
+ // meantime (i.e.: strong count reached zero).
+ decWeak(id);
+ return false;
+ }
} else {
- // Attempting to revive the object... this is allowed
- // if the object DOES have a longer lifetime (so we can safely
- // call the object with only a weak ref) and the implementation
- // allows it to happen.
- allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK
- && impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
+ // this object has an "extended" life-time, i.e.: it can be
+ // revived from a weak-reference only.
+ // Ask the object's implementation if it agrees to be revived
+ if (!impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id)) {
+ // it didn't so give-up.
+ decWeak(id);
+ return false;
+ }
+ // grab a strong-reference, which is always safe due to the
+ // extended life-time.
+ curCount = android_atomic_inc(&impl->mStrong);
}
- if (!allow) {
- decWeak(id);
- return false;
- }
- curCount = android_atomic_inc(&impl->mStrong);
// If the strong reference count has already been incremented by
// someone else, the implementor of onIncStrongAttempted() is holding
@@ -490,11 +514,23 @@
ALOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount);
#endif
- if (curCount == INITIAL_STRONG_VALUE) {
- android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong);
- impl->mBase->onFirstRef();
+ // now we need to fix-up the count if it was INITIAL_STRONG_VALUE
+ // this must be done safely, i.e.: handle the case where several threads
+ // were here in attemptIncStrong().
+ curCount = impl->mStrong;
+ while (curCount >= INITIAL_STRONG_VALUE) {
+ ALOG_ASSERT(curCount > INITIAL_STRONG_VALUE,
+ "attemptIncStrong in %p underflowed to INITIAL_STRONG_VALUE",
+ this);
+ if (android_atomic_cmpxchg(curCount, curCount-INITIAL_STRONG_VALUE,
+ &impl->mStrong) == 0) {
+ break;
+ }
+ // the strong-count changed on us, we need to re-assert the situation,
+ // for e.g.: it's possible the fix-up happened in another thread.
+ curCount = impl->mStrong;
}
-
+
return true;
}
@@ -595,21 +631,27 @@
// ---------------------------------------------------------------------------
-void RefBase::moveReferences(void* dst, void const* src, size_t n,
- const ReferenceConverterBase& caster)
-{
+void RefBase::renameRefs(size_t n, const ReferenceRenamer& renamer) {
#if DEBUG_REFS
- const size_t itemSize = caster.getReferenceTypeSize();
for (size_t i=0 ; i<n ; i++) {
- void* d = reinterpret_cast<void *>(intptr_t(dst) + i*itemSize);
- void const* s = reinterpret_cast<void const*>(intptr_t(src) + i*itemSize);
- RefBase* ref(reinterpret_cast<RefBase*>(caster.getReferenceBase(d)));
- ref->mRefs->renameStrongRefId(s, d);
- ref->mRefs->renameWeakRefId(s, d);
+ renamer(i);
}
#endif
}
+void RefBase::renameRefId(weakref_type* ref,
+ const void* old_id, const void* new_id) {
+ weakref_impl* const impl = static_cast<weakref_impl*>(ref);
+ impl->renameStrongRefId(old_id, new_id);
+ impl->renameWeakRefId(old_id, new_id);
+}
+
+void RefBase::renameRefId(RefBase* ref,
+ const void* old_id, const void* new_id) {
+ ref->mRefs->renameStrongRefId(old_id, new_id);
+ ref->mRefs->renameWeakRefId(old_id, new_id);
+}
+
// ---------------------------------------------------------------------------
TextOutput& printStrongPointer(TextOutput& to, const void* val)
diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp
index a25a81f..7b877e0 100644
--- a/libs/utils/Threads.cpp
+++ b/libs/utils/Threads.cpp
@@ -109,30 +109,34 @@
}
if (name) {
-#if defined(HAVE_PRCTL)
- // Mac OS doesn't have this, and we build libutil for the host too
- int hasAt = 0;
- int hasDot = 0;
- char *s = name;
- while (*s) {
- if (*s == '.') hasDot = 1;
- else if (*s == '@') hasAt = 1;
- s++;
- }
- int len = s - name;
- if (len < 15 || hasAt || !hasDot) {
- s = name;
- } else {
- s = name + len - 15;
- }
- prctl(PR_SET_NAME, (unsigned long) s, 0, 0, 0);
-#endif
+ androidSetThreadName(name);
free(name);
}
return f(u);
}
};
+void androidSetThreadName(const char* name) {
+#if defined(HAVE_PRCTL)
+ // Mac OS doesn't have this, and we build libutil for the host too
+ int hasAt = 0;
+ int hasDot = 0;
+ const char *s = name;
+ while (*s) {
+ if (*s == '.') hasDot = 1;
+ else if (*s == '@') hasAt = 1;
+ s++;
+ }
+ int len = s - name;
+ if (len < 15 || hasAt || !hasDot) {
+ s = name;
+ } else {
+ s = name + len - 15;
+ }
+ prctl(PR_SET_NAME, (unsigned long) s, 0, 0, 0);
+#endif
+}
+
int androidCreateRawThreadEtc(android_thread_func_t entryFunction,
void *userData,
const char* threadName,
@@ -871,6 +875,11 @@
return mStatus;
}
+bool Thread::isRunning() const {
+ Mutex::Autolock _l(mLock);
+ return mRunning;
+}
+
#ifdef HAVE_ANDROID_OS
pid_t Thread::getTid() const
{
diff --git a/libs/utils/VectorImpl.cpp b/libs/utils/VectorImpl.cpp
index c3257bb..70f49de 100644
--- a/libs/utils/VectorImpl.cpp
+++ b/libs/utils/VectorImpl.cpp
@@ -343,6 +343,16 @@
return new_capacity;
}
+ssize_t VectorImpl::resize(size_t size) {
+ ssize_t result = NO_ERROR;
+ if (size > mCount) {
+ result = insertAt(mCount, size - mCount);
+ } else if (size < mCount) {
+ result = removeItemsAt(size, mCount - size);
+ }
+ return result < 0 ? result : size;
+}
+
void VectorImpl::release_storage()
{
if (mStorage) {
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 8578874..c8d228c 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -311,6 +311,18 @@
#define EGL_FRAMEBUFFER_TARGET_ANDROID 0x3147
#endif
+/* EGL_ANDROID_presentation_time
+ */
+#ifndef EGL_ANDROID_presentation_time
+#define EGL_ANDROID_presentation_time 1
+typedef khronos_stime_nanoseconds_t EGLnsecsANDROID;
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean eglPresentationTimeANDROID(EGLDisplay dpy, EGLSurface sur, EGLnsecsANDROID time);
+#else
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLPRESENTATIONTIMEANDROID) (EGLDisplay dpy, EGLSurface sur, EGLnsecsANDROID time);
+#endif
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
index 172ef95..0ed5727 100644
--- a/opengl/libagl/egl.cpp
+++ b/opengl/libagl/egl.cpp
@@ -147,6 +147,7 @@
EGLDisplay dpy;
EGLConfig config;
EGLContext ctx;
+ bool zombie;
egl_surface_t(EGLDisplay dpy, EGLConfig config, int32_t depthFormat);
virtual ~egl_surface_t();
@@ -173,7 +174,7 @@
egl_surface_t::egl_surface_t(EGLDisplay dpy,
EGLConfig config,
int32_t depthFormat)
- : magic(MAGIC), dpy(dpy), config(config), ctx(0)
+ : magic(MAGIC), dpy(dpy), config(config), ctx(0), zombie(false)
{
depth.version = sizeof(GGLSurface);
depth.data = 0;
@@ -419,9 +420,8 @@
bits = NULL;
unlock(buffer);
}
- // enqueue the last frame
- nativeWindow->queueBuffer(nativeWindow, buffer, -1);
if (buffer) {
+ nativeWindow->cancelBuffer(nativeWindow, buffer, -1);
buffer->common.decRef(&buffer->common);
buffer = 0;
}
@@ -1580,11 +1580,12 @@
if (surface->dpy != dpy)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
if (surface->ctx) {
- // FIXME: this surface is current check what the spec says
+ // defer disconnect/delete until no longer current
+ surface->zombie = true;
+ } else {
surface->disconnect();
- surface->ctx = 0;
+ delete surface;
}
- delete surface;
}
return EGL_TRUE;
}
@@ -1736,6 +1737,9 @@
if (c->draw) {
egl_surface_t* s = reinterpret_cast<egl_surface_t*>(c->draw);
s->disconnect();
+ s->ctx = EGL_NO_CONTEXT;
+ if (s->zombie)
+ delete s;
}
if (c->read) {
// FIXME: unlock/disconnect the read surface too
@@ -1777,8 +1781,10 @@
egl_surface_t* r = (egl_surface_t*)c->read;
if (d) {
c->draw = 0;
- d->ctx = EGL_NO_CONTEXT;
d->disconnect();
+ d->ctx = EGL_NO_CONTEXT;
+ if (d->zombie)
+ delete d;
}
if (r) {
c->read = 0;
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index ed9db94..978ab04 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -1307,6 +1307,28 @@
return result;
}
+EGLBoolean eglPresentationTimeANDROID(EGLDisplay dpy, EGLSurface surface,
+ EGLnsecsANDROID time)
+{
+ clearError();
+
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) {
+ return EGL_FALSE;
+ }
+
+ SurfaceRef _s(dp.get(), surface);
+ if (!_s.get()) {
+ setError(EGL_BAD_SURFACE, EGL_FALSE);
+ return EGL_FALSE;
+ }
+
+ egl_surface_t const * const s = get_surface(surface);
+ native_window_set_buffers_timestamp(s->win.get(), time);
+
+ return EGL_TRUE;
+}
+
// ----------------------------------------------------------------------------
// NVIDIA extensions
// ----------------------------------------------------------------------------
diff --git a/opengl/tests/gl2_yuvtex/Android.mk b/opengl/tests/gl2_yuvtex/Android.mk
index 7d43759..bb3cc0c 100644
--- a/opengl/tests/gl2_yuvtex/Android.mk
+++ b/opengl/tests/gl2_yuvtex/Android.mk
@@ -5,9 +5,10 @@
gl2_yuvtex.cpp
LOCAL_SHARED_LIBRARIES := \
- libcutils \
+ libcutils \
libEGL \
libGLESv2 \
+ libutils \
libui
LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
diff --git a/opengl/tests/gl_yuvtex/Android.mk b/opengl/tests/gl_yuvtex/Android.mk
index 9e5dba0..e0e2c16 100644
--- a/opengl/tests/gl_yuvtex/Android.mk
+++ b/opengl/tests/gl_yuvtex/Android.mk
@@ -5,9 +5,10 @@
gl_yuvtex.cpp
LOCAL_SHARED_LIBRARIES := \
- libcutils \
+ libcutils \
libEGL \
libGLESv1_CM \
+ libutils \
libui
LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
diff --git a/opengl/tests/hwc/Android.mk b/opengl/tests/hwc/Android.mk
index 9eb58b1..177eb63 100644
--- a/opengl/tests/hwc/Android.mk
+++ b/opengl/tests/hwc/Android.mk
@@ -39,6 +39,7 @@
libcutils \
libEGL \
libGLESv2 \
+ libutils \
libui \
libhardware \
@@ -70,6 +71,7 @@
libcutils \
libEGL \
libGLESv2 \
+ libutils \
libui \
libhardware \
@@ -99,6 +101,7 @@
libcutils \
libEGL \
libGLESv2 \
+ libutils \
libui \
libhardware \
@@ -128,6 +131,7 @@
libcutils \
libEGL \
libGLESv2 \
+ libutils \
libui \
libhardware \
diff --git a/opengl/tools/glgen/specs/egl/EGL14.spec b/opengl/tools/glgen/specs/egl/EGL14.spec
index 828e114..aef0bcb 100644
--- a/opengl/tools/glgen/specs/egl/EGL14.spec
+++ b/opengl/tools/glgen/specs/egl/EGL14.spec
@@ -31,3 +31,4 @@
EGLBoolean eglWaitNative ( EGLint engine )
EGLBoolean eglSwapBuffers ( EGLDisplay dpy, EGLSurface surface )
EGLBoolean eglCopyBuffers ( EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target )
+EGLBoolean eglPresentationTimeANDROID ( EGLDisplay dpy, EGLSurface sur, EGLnsecsANDROID time )
diff --git a/opengl/tools/glgen/src/JType.java b/opengl/tools/glgen/src/JType.java
index 3f7cb73..994e609 100644
--- a/opengl/tools/glgen/src/JType.java
+++ b/opengl/tools/glgen/src/JType.java
@@ -56,6 +56,7 @@
typeMapping.put(new CType("EGLNativeWindowType"), new JType("int"));
typeMapping.put(new CType("EGLNativeDisplayType"), new JType("int"));
typeMapping.put(new CType("EGLClientBuffer"), new JType("int"));
+ typeMapping.put(new CType("EGLnsecsANDROID"), new JType("long"));
// EGL nonprimitive types
typeMapping.put(new CType("EGLConfig"), new JType("EGLConfig", true, false));
diff --git a/opengl/tools/glgen/src/JniCodeEmitter.java b/opengl/tools/glgen/src/JniCodeEmitter.java
index 01c5c48..ffe3767 100644
--- a/opengl/tools/glgen/src/JniCodeEmitter.java
+++ b/opengl/tools/glgen/src/JniCodeEmitter.java
@@ -54,7 +54,7 @@
} else if (baseType.equals("short")) {
jniName += "S";
} else if (baseType.equals("long")) {
- jniName += "L";
+ jniName += "J";
} else if (baseType.equals("byte")) {
jniName += "B";
} else if (baseType.equals("String")) {
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index b4b19b4..30a01be 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -2,24 +2,23 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- Client.cpp \
- DisplayDevice.cpp \
- EventThread.cpp \
- FrameTracker.cpp \
- Layer.cpp \
- LayerBase.cpp \
- LayerDim.cpp \
- LayerScreenshot.cpp \
- DisplayHardware/FramebufferSurface.cpp \
- DisplayHardware/HWComposer.cpp \
- DisplayHardware/PowerHAL.cpp \
- GLExtensions.cpp \
- MessageQueue.cpp \
- SurfaceFlinger.cpp \
- SurfaceFlingerConsumer.cpp \
- SurfaceTextureLayer.cpp \
- Transform.cpp \
-
+ Client.cpp \
+ DisplayDevice.cpp \
+ EventThread.cpp \
+ FrameTracker.cpp \
+ GLExtensions.cpp \
+ Layer.cpp \
+ LayerDim.cpp \
+ MessageQueue.cpp \
+ SurfaceFlinger.cpp \
+ SurfaceFlingerConsumer.cpp \
+ SurfaceTextureLayer.cpp \
+ Transform.cpp \
+ DisplayHardware/BufferQueueInterposer.cpp \
+ DisplayHardware/FramebufferSurface.cpp \
+ DisplayHardware/HWComposer.cpp \
+ DisplayHardware/PowerHAL.cpp \
+ DisplayHardware/VirtualDisplaySurface.cpp \
LOCAL_CFLAGS:= -DLOG_TAG=\"SurfaceFlinger\"
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index 0f56f99..dd65348 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -23,7 +23,6 @@
#include "Client.h"
#include "Layer.h"
-#include "LayerBase.h"
#include "SurfaceFlinger.h"
namespace android {
@@ -43,7 +42,7 @@
{
const size_t count = mLayers.size();
for (size_t i=0 ; i<count ; i++) {
- sp<LayerBaseClient> layer(mLayers.valueAt(i).promote());
+ sp<Layer> layer(mLayers.valueAt(i).promote());
if (layer != 0) {
mFlinger->removeLayer(layer);
}
@@ -54,13 +53,13 @@
return NO_ERROR;
}
-void Client::attachLayer(const sp<IBinder>& handle, const sp<LayerBaseClient>& layer)
+void Client::attachLayer(const sp<IBinder>& handle, const sp<Layer>& layer)
{
Mutex::Autolock _l(mLock);
mLayers.add(handle, layer);
}
-void Client::detachLayer(const LayerBaseClient* layer)
+void Client::detachLayer(const Layer* layer)
{
Mutex::Autolock _l(mLock);
// we do a linear search here, because this doesn't happen often
@@ -72,11 +71,11 @@
}
}
}
-sp<LayerBaseClient> Client::getLayerUser(const sp<IBinder>& handle) const
+sp<Layer> Client::getLayerUser(const sp<IBinder>& handle) const
{
Mutex::Autolock _l(mLock);
- sp<LayerBaseClient> lbc;
- wp<LayerBaseClient> layer(mLayers.valueFor(handle));
+ sp<Layer> lbc;
+ wp<Layer> layer(mLayers.valueFor(handle));
if (layer != 0) {
lbc = layer.promote();
ALOGE_IF(lbc==0, "getLayerUser(name=%p) is dead", handle.get());
@@ -106,10 +105,11 @@
}
-sp<ISurface> Client::createSurface(
+status_t Client::createSurface(
const String8& name,
- uint32_t w, uint32_t h, PixelFormat format,
- uint32_t flags)
+ uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
+ sp<IBinder>* handle,
+ sp<IGraphicBufferProducer>* gbp)
{
/*
* createSurface must be called from the GL thread so that it can
@@ -117,9 +117,11 @@
*/
class MessageCreateLayer : public MessageBase {
- sp<ISurface> result;
SurfaceFlinger* flinger;
Client* client;
+ sp<IBinder>* handle;
+ sp<IGraphicBufferProducer>* gbp;
+ status_t result;
const String8& name;
uint32_t w, h;
PixelFormat format;
@@ -127,21 +129,23 @@
public:
MessageCreateLayer(SurfaceFlinger* flinger,
const String8& name, Client* client,
- uint32_t w, uint32_t h, PixelFormat format,
- uint32_t flags)
- : flinger(flinger), client(client), name(name),
- w(w), h(h), format(format), flags(flags)
- {
+ uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
+ sp<IBinder>* handle,
+ sp<IGraphicBufferProducer>* gbp)
+ : flinger(flinger), client(client),
+ handle(handle), gbp(gbp),
+ name(name), w(w), h(h), format(format), flags(flags) {
}
- sp<ISurface> getResult() const { return result; }
+ status_t getResult() const { return result; }
virtual bool handler() {
- result = flinger->createLayer(name, client, w, h, format, flags);
+ result = flinger->createLayer(name, client, w, h, format, flags,
+ handle, gbp);
return true;
}
};
sp<MessageBase> msg = new MessageCreateLayer(mFlinger.get(),
- name, this, w, h, format, flags);
+ name, this, w, h, format, flags, handle, gbp);
mFlinger->postMessageSync(msg);
return static_cast<MessageCreateLayer*>( msg.get() )->getResult();
}
diff --git a/services/surfaceflinger/Client.h b/services/surfaceflinger/Client.h
index e6a7165..84e649f 100644
--- a/services/surfaceflinger/Client.h
+++ b/services/surfaceflinger/Client.h
@@ -30,7 +30,7 @@
// ---------------------------------------------------------------------------
-class LayerBaseClient;
+class Layer;
class SurfaceFlinger;
// ---------------------------------------------------------------------------
@@ -44,18 +44,19 @@
status_t initCheck() const;
// protected by SurfaceFlinger::mStateLock
- void attachLayer(const sp<IBinder>& handle, const sp<LayerBaseClient>& layer);
+ void attachLayer(const sp<IBinder>& handle, const sp<Layer>& layer);
- void detachLayer(const LayerBaseClient* layer);
+ void detachLayer(const Layer* layer);
- sp<LayerBaseClient> getLayerUser(const sp<IBinder>& handle) const;
+ sp<Layer> getLayerUser(const sp<IBinder>& handle) const;
private:
// ISurfaceComposerClient interface
- virtual sp<ISurface> createSurface(
+ virtual status_t createSurface(
const String8& name,
- uint32_t w, uint32_t h,PixelFormat format,
- uint32_t flags);
+ uint32_t w, uint32_t h,PixelFormat format, uint32_t flags,
+ sp<IBinder>* handle,
+ sp<IGraphicBufferProducer>* gbp);
virtual status_t destroySurface(const sp<IBinder>& handle);
@@ -66,7 +67,7 @@
sp<SurfaceFlinger> mFlinger;
// protected by mLock
- DefaultKeyedVector< wp<IBinder>, wp<LayerBaseClient> > mLayers;
+ DefaultKeyedVector< wp<IBinder>, wp<Layer> > mLayers;
// thread-safe
mutable Mutex mLock;
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 9466944..ecd12d0 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -35,14 +35,14 @@
#include <hardware/gralloc.h>
-#include "DisplayHardware/FramebufferSurface.h"
+#include "DisplayHardware/DisplaySurface.h"
#include "DisplayHardware/HWComposer.h"
#include "clz.h"
#include "DisplayDevice.h"
#include "GLExtensions.h"
#include "SurfaceFlinger.h"
-#include "LayerBase.h"
+#include "Layer.h"
// ----------------------------------------------------------------------------
using namespace android;
@@ -72,14 +72,12 @@
DisplayType type,
bool isSecure,
const wp<IBinder>& displayToken,
- const sp<ANativeWindow>& nativeWindow,
- const sp<FramebufferSurface>& framebufferSurface,
+ const sp<DisplaySurface>& displaySurface,
EGLConfig config)
: mFlinger(flinger),
mType(type), mHwcDisplayId(-1),
mDisplayToken(displayToken),
- mNativeWindow(nativeWindow),
- mFramebufferSurface(framebufferSurface),
+ mDisplaySurface(displaySurface),
mDisplay(EGL_NO_DISPLAY),
mSurface(EGL_NO_SURFACE),
mContext(EGL_NO_CONTEXT),
@@ -89,9 +87,10 @@
mIsSecure(isSecure),
mSecureLayerVisible(false),
mScreenAcquired(false),
- mLayerStack(0),
+ mLayerStack(NO_LAYER_STACK),
mOrientation()
{
+ mNativeWindow = new Surface(mDisplaySurface->getIGraphicBufferProducer());
init(config);
}
@@ -183,10 +182,7 @@
}
status_t DisplayDevice::compositionComplete() const {
- if (mFramebufferSurface == NULL) {
- return NO_ERROR;
- }
- return mFramebufferSurface->compositionComplete();
+ return mDisplaySurface->compositionComplete();
}
void DisplayDevice::flip(const Region& dirty) const
@@ -196,58 +192,51 @@
EGLDisplay dpy = mDisplay;
EGLSurface surface = mSurface;
-#ifdef EGL_ANDROID_swap_rectangle
+#ifdef EGL_ANDROID_swap_rectangle
if (mFlags & SWAP_RECTANGLE) {
const Region newDirty(dirty.intersect(bounds()));
const Rect b(newDirty.getBounds());
eglSetSwapRectangleANDROID(dpy, surface,
b.left, b.top, b.width(), b.height());
- }
+ }
#endif
mPageFlipCount++;
}
void DisplayDevice::swapBuffers(HWComposer& hwc) const {
- EGLBoolean success = EGL_TRUE;
- if (hwc.initCheck() != NO_ERROR) {
- // no HWC, we call eglSwapBuffers()
- success = eglSwapBuffers(mDisplay, mSurface);
- } else {
- // We have a valid HWC, but not all displays can use it, in particular
- // the virtual displays are on their own.
- // TODO: HWC 1.2 will allow virtual displays
- if (mType >= DisplayDevice::DISPLAY_VIRTUAL) {
- // always call eglSwapBuffers() for virtual displays
- success = eglSwapBuffers(mDisplay, mSurface);
- } else if (hwc.supportsFramebufferTarget()) {
- // as of hwc 1.1 we always call eglSwapBuffers if we have some
- // GLES layers
- if (hwc.hasGlesComposition(mType)) {
- success = eglSwapBuffers(mDisplay, mSurface);
+ // We need to call eglSwapBuffers() unless:
+ // (a) there was no GLES composition this frame, or
+ // (b) we're using a legacy HWC with no framebuffer target support (in
+ // which case HWComposer::commit() handles things).
+ if (hwc.initCheck() != NO_ERROR ||
+ (hwc.hasGlesComposition(mHwcDisplayId) &&
+ hwc.supportsFramebufferTarget())) {
+ EGLBoolean success = eglSwapBuffers(mDisplay, mSurface);
+ if (!success) {
+ EGLint error = eglGetError();
+ if (error == EGL_CONTEXT_LOST ||
+ mType == DisplayDevice::DISPLAY_PRIMARY) {
+ LOG_ALWAYS_FATAL("eglSwapBuffers(%p, %p) failed with 0x%08x",
+ mDisplay, mSurface, error);
+ } else {
+ ALOGE("eglSwapBuffers(%p, %p) failed with 0x%08x",
+ mDisplay, mSurface, error);
}
- } else {
- // HWC doesn't have the framebuffer target, we don't call
- // eglSwapBuffers(), since this is handled by HWComposer::commit().
}
}
- if (!success) {
- EGLint error = eglGetError();
- if (error == EGL_CONTEXT_LOST ||
- mType == DisplayDevice::DISPLAY_PRIMARY) {
- LOG_ALWAYS_FATAL("eglSwapBuffers(%p, %p) failed with 0x%08x",
- mDisplay, mSurface, error);
- }
+ status_t result = mDisplaySurface->advanceFrame();
+ if (result != NO_ERROR) {
+ ALOGE("[%s] failed pushing new frame to HWC: %d",
+ mDisplayName.string(), result);
}
}
void DisplayDevice::onSwapBuffersCompleted(HWComposer& hwc) const {
if (hwc.initCheck() == NO_ERROR) {
- if (hwc.supportsFramebufferTarget()) {
- int fd = hwc.getAndResetReleaseFenceFd(mType);
- mFramebufferSurface->setReleaseFenceFd(fd);
- }
+ int fd = hwc.getAndResetReleaseFenceFd(mType);
+ mDisplaySurface->setReleaseFenceFd(fd);
}
}
@@ -282,18 +271,19 @@
// ----------------------------------------------------------------------------
-void DisplayDevice::setVisibleLayersSortedByZ(const Vector< sp<LayerBase> >& layers) {
+void DisplayDevice::setVisibleLayersSortedByZ(const Vector< sp<Layer> >& layers) {
mVisibleLayersSortedByZ = layers;
mSecureLayerVisible = false;
size_t count = layers.size();
for (size_t i=0 ; i<count ; i++) {
- if (layers[i]->isSecure()) {
+ const sp<Layer>& layer(layers[i]);
+ if (layer->isSecure()) {
mSecureLayerVisible = true;
}
}
}
-const Vector< sp<LayerBase> >& DisplayDevice::getVisibleLayersSortedByZ() const {
+const Vector< sp<Layer> >& DisplayDevice::getVisibleLayersSortedByZ() const {
return mVisibleLayersSortedByZ;
}
@@ -365,74 +355,72 @@
}
void DisplayDevice::setProjection(int orientation,
- const Rect& viewport, const Rect& frame) {
+ const Rect& newViewport, const Rect& newFrame) {
+ Rect viewport(newViewport);
+ Rect frame(newFrame);
+
+ const int w = mDisplayWidth;
+ const int h = mDisplayHeight;
+
+ Transform R;
+ DisplayDevice::orientationToTransfrom(orientation, w, h, &R);
+
+ if (!frame.isValid()) {
+ // the destination frame can be invalid if it has never been set,
+ // in that case we assume the whole display frame.
+ frame = Rect(w, h);
+ }
+
+ if (viewport.isEmpty()) {
+ // viewport can be invalid if it has never been set, in that case
+ // we assume the whole display size.
+ // it's also invalid to have an empty viewport, so we handle that
+ // case in the same way.
+ viewport = Rect(w, h);
+ if (R.getOrientation() & Transform::ROT_90) {
+ // viewport is always specified in the logical orientation
+ // of the display (ie: post-rotation).
+ swap(viewport.right, viewport.bottom);
+ }
+ }
+
+ dirtyRegion.set(getBounds());
+
+ Transform TL, TP, S;
+ float src_width = viewport.width();
+ float src_height = viewport.height();
+ float dst_width = frame.width();
+ float dst_height = frame.height();
+ if (src_width != dst_width || src_height != dst_height) {
+ float sx = dst_width / src_width;
+ float sy = dst_height / src_height;
+ S.set(sx, 0, 0, sy);
+ }
+
+ float src_x = viewport.left;
+ float src_y = viewport.top;
+ float dst_x = frame.left;
+ float dst_y = frame.top;
+ TL.set(-src_x, -src_y);
+ TP.set(dst_x, dst_y);
+
+ // The viewport and frame are both in the logical orientation.
+ // Apply the logical translation, scale to physical size, apply the
+ // physical translation and finally rotate to the physical orientation.
+ mGlobalTransform = R * TP * S * TL;
+
+ const uint8_t type = mGlobalTransform.getType();
+ mNeedsFiltering = (!mGlobalTransform.preserveRects() ||
+ (type >= Transform::SCALE));
+
+ mScissor = mGlobalTransform.transform(viewport);
+ if (mScissor.isEmpty()) {
+ mScissor.set(getBounds());
+ }
+
mOrientation = orientation;
mViewport = viewport;
mFrame = frame;
- updateGeometryTransform();
-}
-
-void DisplayDevice::updateGeometryTransform() {
- int w = mDisplayWidth;
- int h = mDisplayHeight;
- Transform TL, TP, R, S;
- if (DisplayDevice::orientationToTransfrom(
- mOrientation, w, h, &R) == NO_ERROR) {
- dirtyRegion.set(bounds());
-
- Rect viewport(mViewport);
- Rect frame(mFrame);
-
- if (!frame.isValid()) {
- // the destination frame can be invalid if it has never been set,
- // in that case we assume the whole display frame.
- frame = Rect(w, h);
- }
-
- if (viewport.isEmpty()) {
- // viewport can be invalid if it has never been set, in that case
- // we assume the whole display size.
- // it's also invalid to have an empty viewport, so we handle that
- // case in the same way.
- viewport = Rect(w, h);
- if (R.getOrientation() & Transform::ROT_90) {
- // viewport is always specified in the logical orientation
- // of the display (ie: post-rotation).
- swap(viewport.right, viewport.bottom);
- }
- }
-
- float src_width = viewport.width();
- float src_height = viewport.height();
- float dst_width = frame.width();
- float dst_height = frame.height();
- if (src_width != dst_width || src_height != dst_height) {
- float sx = dst_width / src_width;
- float sy = dst_height / src_height;
- S.set(sx, 0, 0, sy);
- }
-
- float src_x = viewport.left;
- float src_y = viewport.top;
- float dst_x = frame.left;
- float dst_y = frame.top;
- TL.set(-src_x, -src_y);
- TP.set(dst_x, dst_y);
-
- // The viewport and frame are both in the logical orientation.
- // Apply the logical translation, scale to physical size, apply the
- // physical translation and finally rotate to the physical orientation.
- mGlobalTransform = R * TP * S * TL;
-
- const uint8_t type = mGlobalTransform.getType();
- mNeedsFiltering = (!mGlobalTransform.preserveRects() ||
- (type >= Transform::SCALE));
-
- mScissor = mGlobalTransform.transform(mViewport);
- if (mScissor.isEmpty()) {
- mScissor.set(getBounds());
- }
- }
}
void DisplayDevice::dump(String8& result, char* buffer, size_t SIZE) const {
@@ -456,9 +444,7 @@
result.append(buffer);
- String8 fbtargetDump;
- if (mFramebufferSurface != NULL) {
- mFramebufferSurface->dump(fbtargetDump);
- result.append(fbtargetDump);
- }
+ String8 surfaceDump;
+ mDisplaySurface->dump(surfaceDump);
+ result.append(surfaceDump);
}
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index bb6eb70..d8f55b4 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -37,8 +37,8 @@
namespace android {
class DisplayInfo;
-class FramebufferSurface;
-class LayerBase;
+class DisplaySurface;
+class Layer;
class SurfaceFlinger;
class HWComposer;
@@ -65,13 +65,16 @@
SWAP_RECTANGLE = 0x00080000,
};
+ enum {
+ NO_LAYER_STACK = 0xFFFFFFFF,
+ };
+
DisplayDevice(
const sp<SurfaceFlinger>& flinger,
DisplayType type,
bool isSecure,
const wp<IBinder>& displayToken,
- const sp<ANativeWindow>& nativeWindow,
- const sp<FramebufferSurface>& framebufferSurface,
+ const sp<DisplaySurface>& displaySurface,
EGLConfig config);
~DisplayDevice();
@@ -95,8 +98,8 @@
EGLSurface getEGLSurface() const;
- void setVisibleLayersSortedByZ(const Vector< sp<LayerBase> >& layers);
- const Vector< sp<LayerBase> >& getVisibleLayersSortedByZ() const;
+ void setVisibleLayersSortedByZ(const Vector< sp<Layer> >& layers);
+ const Vector< sp<Layer> >& getVisibleLayersSortedByZ() const;
bool getSecureLayerVisible() const;
Region getDirtyRegion(bool repaintEverything) const;
@@ -105,8 +108,8 @@
int getOrientation() const { return mOrientation; }
const Transform& getTransform() const { return mGlobalTransform; }
- const Rect& getViewport() const { return mViewport; }
- const Rect& getFrame() const { return mFrame; }
+ const Rect getViewport() const { return mViewport; }
+ const Rect getFrame() const { return mFrame; }
const Rect& getScissor() const { return mScissor; }
bool needsFiltering() const { return mNeedsFiltering; }
@@ -117,7 +120,7 @@
void swapBuffers(HWComposer& hwc) const;
status_t compositionComplete() const;
-
+
// called after h/w composer has completed its set() call
void onSwapBuffersCompleted(HWComposer& hwc) const;
@@ -161,9 +164,7 @@
// ANativeWindow this display is rendering into
sp<ANativeWindow> mNativeWindow;
-
- // set if mNativeWindow is a FramebufferSurface
- sp<FramebufferSurface> mFramebufferSurface;
+ sp<DisplaySurface> mDisplaySurface;
EGLDisplay mDisplay;
EGLSurface mSurface;
@@ -182,7 +183,7 @@
*/
// list of visible layers on that display
- Vector< sp<LayerBase> > mVisibleLayersSortedByZ;
+ Vector< sp<Layer> > mVisibleLayersSortedByZ;
// Whether we have a visible secure layer on this display
bool mSecureLayerVisible;
@@ -197,8 +198,6 @@
static status_t orientationToTransfrom(int orientation,
int w, int h, Transform* tr);
- void updateGeometryTransform();
-
uint32_t mLayerStack;
int mOrientation;
// user-provided visible area of the layer stack
diff --git a/services/surfaceflinger/DisplayHardware/BufferQueueInterposer.cpp b/services/surfaceflinger/DisplayHardware/BufferQueueInterposer.cpp
new file mode 100644
index 0000000..d8ad224
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/BufferQueueInterposer.cpp
@@ -0,0 +1,238 @@
+/*
+ * Copyright 2013 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "BQInterposer"
+
+#include "BufferQueueInterposer.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+// ---------------------------------------------------------------------------
+
+#define BQI_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define BQI_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define BQI_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define BQI_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define BQI_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__)
+
+// Get an ID that's unique within this process.
+static int32_t createProcessUniqueId() {
+ static volatile int32_t globalCounter = 0;
+ return android_atomic_inc(&globalCounter);
+}
+
+BufferQueueInterposer::BufferQueueInterposer(
+ const sp<IGraphicBufferProducer>& sink, const String8& name)
+: mSink(sink),
+ mName(name),
+ mAcquired(false)
+{
+ BQI_LOGV("BufferQueueInterposer sink=%p", sink.get());
+
+ // We need one additional dequeued buffer beyond what the source needs.
+ // To have more than one (the default), we must call setBufferCount. But
+ // we have no way of knowing what the sink has set as the minimum buffer
+ // count, so if we just call setBufferCount(3) it may fail (and does, on
+ // one device using a video encoder sink). So far on the devices we care
+ // about, this is the smallest value that works.
+ //
+ // TODO: Change IGraphicBufferProducer and implementations to support this.
+ // Maybe change it so both the consumer and producer declare how many
+ // buffers they need, and the IGBP adds them? Then BQInterposer would just
+ // add 1 to the source's buffer count.
+ mSink->setBufferCount(6);
+}
+
+BufferQueueInterposer::~BufferQueueInterposer() {
+ Mutex::Autolock lock(mMutex);
+ flushQueuedBuffersLocked();
+ BQI_LOGV("~BufferQueueInterposer");
+}
+
+status_t BufferQueueInterposer::requestBuffer(int slot,
+ sp<GraphicBuffer>* outBuf) {
+ BQI_LOGV("requestBuffer slot=%d", slot);
+ Mutex::Autolock lock(mMutex);
+
+ if (size_t(slot) >= mBuffers.size()) {
+ size_t size = mBuffers.size();
+ mBuffers.insertAt(size, size - slot + 1);
+ }
+ sp<GraphicBuffer>& buf = mBuffers.editItemAt(slot);
+
+ status_t result = mSink->requestBuffer(slot, &buf);
+ *outBuf = buf;
+ return result;
+}
+
+status_t BufferQueueInterposer::setBufferCount(int bufferCount) {
+ BQI_LOGV("setBufferCount count=%d", bufferCount);
+ Mutex::Autolock lock(mMutex);
+
+ bufferCount += 1;
+
+ status_t result = flushQueuedBuffersLocked();
+ if (result != NO_ERROR)
+ return result;
+
+ result = mSink->setBufferCount(bufferCount);
+ if (result != NO_ERROR)
+ return result;
+
+ for (size_t i = 0; i < mBuffers.size(); i++)
+ mBuffers.editItemAt(i).clear();
+ ssize_t n = mBuffers.resize(bufferCount);
+ result = (n < 0) ? n : result;
+
+ return result;
+}
+
+status_t BufferQueueInterposer::dequeueBuffer(int* slot, sp<Fence>* fence,
+ uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
+ BQI_LOGV("dequeueBuffer %ux%u fmt=%u usage=%#x", w, h, format, usage);
+ return mSink->dequeueBuffer(slot, fence, w, h, format, usage);
+}
+
+status_t BufferQueueInterposer::queueBuffer(int slot,
+ const QueueBufferInput& input, QueueBufferOutput* output) {
+ BQI_LOGV("queueBuffer slot=%d", slot);
+ Mutex::Autolock lock(mMutex);
+ mQueue.push(QueuedBuffer(slot, input));
+ *output = mQueueBufferOutput;
+ return NO_ERROR;
+}
+
+void BufferQueueInterposer::cancelBuffer(int slot, const sp<Fence>& fence) {
+ BQI_LOGV("cancelBuffer slot=%d", slot);
+ mSink->cancelBuffer(slot, fence);
+}
+
+int BufferQueueInterposer::query(int what, int* value) {
+ BQI_LOGV("query what=%d", what);
+ return mSink->query(what, value);
+}
+
+status_t BufferQueueInterposer::setSynchronousMode(bool enabled) {
+ BQI_LOGV("setSynchronousMode %s", enabled ? "true" : "false");
+ return mSink->setSynchronousMode(enabled);
+}
+
+status_t BufferQueueInterposer::connect(int api, QueueBufferOutput* output) {
+ BQI_LOGV("connect api=%d", api);
+ Mutex::Autolock lock(mMutex);
+ status_t result = mSink->connect(api, &mQueueBufferOutput);
+ if (result == NO_ERROR) {
+ *output = mQueueBufferOutput;
+ }
+ return result;
+}
+
+status_t BufferQueueInterposer::disconnect(int api) {
+ BQI_LOGV("disconnect: api=%d", api);
+ Mutex::Autolock lock(mMutex);
+ flushQueuedBuffersLocked();
+ return mSink->disconnect(api);
+}
+
+status_t BufferQueueInterposer::pullEmptyBuffer() {
+ status_t result;
+
+ int slot;
+ sp<Fence> fence;
+ result = dequeueBuffer(&slot, &fence, 0, 0, 0, 0);
+ if (result == IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) {
+ sp<GraphicBuffer> buffer;
+ result = requestBuffer(slot, &buffer);
+ } else if (result != NO_ERROR) {
+ return result;
+ }
+
+ uint32_t w, h, transformHint, numPendingBuffers;
+ mQueueBufferOutput.deflate(&w, &h, &transformHint, &numPendingBuffers);
+
+ IGraphicBufferProducer::QueueBufferInput qbi(0, Rect(w, h),
+ NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, fence);
+ IGraphicBufferProducer::QueueBufferOutput qbo;
+ result = queueBuffer(slot, qbi, &qbo);
+ if (result != NO_ERROR)
+ return result;
+
+ return NO_ERROR;
+}
+
+status_t BufferQueueInterposer::acquireBuffer(sp<GraphicBuffer>* buf,
+ sp<Fence>* fence) {
+ Mutex::Autolock lock(mMutex);
+ if (mQueue.empty()) {
+ BQI_LOGV("acquireBuffer: no buffers available");
+ return NO_BUFFER_AVAILABLE;
+ }
+ if (mAcquired) {
+ BQI_LOGE("acquireBuffer: buffer already acquired");
+ return BUFFER_ALREADY_ACQUIRED;
+ }
+ BQI_LOGV("acquireBuffer: acquiring slot %d", mQueue[0].slot);
+
+ *buf = mBuffers[mQueue[0].slot];
+ *fence = mQueue[0].fence;
+ mAcquired = true;
+ return NO_ERROR;
+}
+
+status_t BufferQueueInterposer::releaseBuffer(const sp<Fence>& fence) {
+ Mutex::Autolock lock(mMutex);
+ if (!mAcquired) {
+ BQI_LOGE("releaseBuffer: releasing a non-acquired buffer");
+ return BUFFER_NOT_ACQUIRED;
+ }
+ BQI_LOGV("releaseBuffer: releasing slot %d to sink", mQueue[0].slot);
+
+ const QueuedBuffer& b = mQueue[0];
+ status_t result = mSink->queueBuffer(b.slot,
+ QueueBufferInput(b.timestamp, b.crop, b.scalingMode,
+ b.transform, b.fence),
+ &mQueueBufferOutput);
+ mQueue.removeAt(0);
+ mAcquired = false;
+
+ return result;
+}
+
+status_t BufferQueueInterposer::flushQueuedBuffersLocked() {
+ if (mAcquired) {
+ BQI_LOGE("flushQueuedBuffersLocked: buffer acquired, can't flush");
+ return INVALID_OPERATION;
+ }
+
+ status_t result = NO_ERROR;
+ for (size_t i = 0; i < mQueue.size(); i++) {
+ const QueuedBuffer& b = mQueue[i];
+ BQI_LOGV("flushing queued slot %d to sink", b.slot);
+ status_t err = mSink->queueBuffer(b.slot,
+ QueueBufferInput(b.timestamp, b.crop, b.scalingMode,
+ b.transform, b.fence),
+ &mQueueBufferOutput);
+ if (err != NO_ERROR && result == NO_ERROR) // latch first error
+ result = err;
+ }
+ mQueue.clear();
+ return result;
+}
+
+// ---------------------------------------------------------------------------
+} // namespace android
+// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/DisplayHardware/BufferQueueInterposer.h b/services/surfaceflinger/DisplayHardware/BufferQueueInterposer.h
new file mode 100644
index 0000000..7208630
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/BufferQueueInterposer.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2013 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.
+ */
+
+#ifndef ANDROID_SF_BUFFERQUEUEINTERPOSER_H
+#define ANDROID_SF_BUFFERQUEUEINTERPOSER_H
+
+#include <gui/IGraphicBufferProducer.h>
+#include <utils/Mutex.h>
+#include <utils/Vector.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+// ---------------------------------------------------------------------------
+
+// BufferQueueInterposers introduce an extra stage between a buffer producer
+// (the source) and a buffer consumer (the sink), which communicate via the
+// IGraphicBufferProducer interface. It is designed to be as transparent as
+// possible to both endpoints, so that they can work the same whether an
+// interposer is present or not.
+//
+// When the interpose is present, the source queues buffers to the
+// IGraphicBufferProducer implemented by BufferQueueInterposer. A client of
+// the BufferQueueInterposer can acquire each buffer in turn and read or
+// modify it, releasing the buffer when finished. When the buffer is released,
+// the BufferQueueInterposer queues it to the original IGraphicBufferProducer
+// interface representing the sink.
+//
+// A BufferQueueInterposer can be used to do additional rendering to a buffer
+// before it is consumed -- essentially pipelining two producers. As an
+// example, SurfaceFlinger uses this to implement mixed GLES and HWC
+// compositing to the same buffer for virtual displays. If it used two separate
+// buffer queues, then in GLES-only or mixed GLES+HWC compositing, the HWC
+// would have to copy the GLES output buffer to the HWC output buffer, using
+// more bandwidth than having HWC do additional composition "in place" on the
+// GLES output buffer.
+//
+// The goal for this class is to be usable in a variety of situations and be
+// part of libgui. But both the interface and implementation need some
+// iteration before then, so for now it should only be used by
+// VirtualDisplaySurface, which is why it's currently in SurfaceFlinger.
+//
+// Some of the problems that still need to be solved are:
+//
+// - Refactor the interposer interface along with BufferQueue and ConsumerBase,
+// so that there is a common interface for the consumer end of a queue. The
+// existing interfaces have some problems when the implementation isn't the
+// final consumer.
+//
+// - The interposer needs at least one buffer in addition to those used by the
+// source and sink. setBufferCount and QueueBufferOutput both need to
+// account for this. It's not possible currently to do this generically,
+// since we can't find out how many buffers the source and sink need. (See
+// the horrible hack in the BufferQueueInterposer constructor).
+//
+// - Abandoning, disconnecting, and connecting need to pass through somehow.
+// There needs to be a way to tell the interposer client to release its
+// buffer immediately so it can be queued/released, e.g. when the source
+// calls disconnect().
+//
+// - Right now the source->BQI queue is synchronous even if the BQI->sink
+// queue is asynchronous. Need to figure out how asynchronous should behave
+// and implement that.
+
+class BufferQueueInterposer : public BnGraphicBufferProducer {
+public:
+ BufferQueueInterposer(const sp<IGraphicBufferProducer>& sink,
+ const String8& name);
+
+ //
+ // IGraphicBufferProducer interface
+ //
+ virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* outBuf);
+ virtual status_t setBufferCount(int bufferCount);
+ virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence,
+ uint32_t w, uint32_t h, uint32_t format, uint32_t usage);
+ virtual status_t queueBuffer(int slot,
+ const QueueBufferInput& input, QueueBufferOutput* output);
+ virtual void cancelBuffer(int slot, const sp<Fence>& fence);
+ virtual int query(int what, int* value);
+ virtual status_t setSynchronousMode(bool enabled);
+ virtual status_t connect(int api, QueueBufferOutput* output);
+ virtual status_t disconnect(int api);
+
+ //
+ // Interposer interface
+ //
+
+ enum {
+ NO_BUFFER_AVAILABLE = 2, // matches BufferQueue
+ BUFFER_NOT_ACQUIRED,
+ BUFFER_ALREADY_ACQUIRED,
+ };
+
+ // Acquire the oldest queued buffer. If no buffers are pending, returns
+ // NO_BUFFER_AVAILABLE. If a buffer is currently acquired, returns
+ // BUFFER_ALREADY_ACQUIRED.
+ status_t acquireBuffer(sp<GraphicBuffer>* buf, sp<Fence>* fence);
+
+ // Release the currently acquired buffer, queueing it to the sink. If the
+ // current buffer hasn't been acquired, returns BUFFER_NOT_ACQUIRED.
+ status_t releaseBuffer(const sp<Fence>& fence);
+
+ // pullEmptyBuffer dequeues a buffer from the sink, then immediately
+ // queues it to the interposer. This makes a buffer available for the
+ // client to acquire even if the source hasn't queued one.
+ status_t pullEmptyBuffer();
+
+private:
+ struct QueuedBuffer {
+ QueuedBuffer(): slot(-1) {}
+ QueuedBuffer(int slot, const QueueBufferInput& qbi): slot(slot) {
+ qbi.deflate(×tamp, &crop, &scalingMode, &transform, &fence);
+ }
+ int slot;
+ int64_t timestamp;
+ Rect crop;
+ int scalingMode;
+ uint32_t transform;
+ sp<Fence> fence;
+ };
+
+ virtual ~BufferQueueInterposer();
+ status_t flushQueuedBuffersLocked();
+
+ const sp<IGraphicBufferProducer> mSink;
+ String8 mName;
+
+ Mutex mMutex;
+ Vector<sp<GraphicBuffer> > mBuffers;
+ Vector<QueuedBuffer> mQueue;
+ bool mAcquired;
+ QueueBufferOutput mQueueBufferOutput;
+};
+
+// ---------------------------------------------------------------------------
+} // namespace android
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_SF_BUFFERQUEUEINTERPOSER_H
diff --git a/services/surfaceflinger/DisplayHardware/DisplaySurface.h b/services/surfaceflinger/DisplayHardware/DisplaySurface.h
new file mode 100644
index 0000000..2de6b4c
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/DisplaySurface.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2013 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.
+ */
+
+#ifndef ANDROID_SF_DISPLAY_SURFACE_H
+#define ANDROID_SF_DISPLAY_SURFACE_H
+
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <utils/StrongPointer.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+// ---------------------------------------------------------------------------
+
+class IGraphicBufferProducer;
+class String8;
+
+class DisplaySurface : public virtual RefBase {
+public:
+ virtual sp<IGraphicBufferProducer> getIGraphicBufferProducer() const = 0;
+
+ // Should be called when composition rendering is complete for a frame (but
+ // eglSwapBuffers hasn't necessarily been called). Required by certain
+ // older drivers for synchronization.
+ // TODO: Remove this when we drop support for HWC 1.0.
+ virtual status_t compositionComplete() = 0;
+
+ // Inform the surface that GLES composition is complete for this frame, and
+ // the surface should make sure that HWComposer has the correct buffer for
+ // this frame. Some implementations may only push a new buffer to
+ // HWComposer if GLES composition took place, others need to push a new
+ // buffer on every frame.
+ virtual status_t advanceFrame() = 0;
+
+ // setReleaseFenceFd stores a fence file descriptor that will signal when
+ // the current buffer is no longer being read. This fence will be returned
+ // to the producer when the current buffer is released by updateTexImage().
+ // Multiple fences can be set for a given buffer; they will be merged into
+ // a single union fence. The GLConsumer will close the file descriptor
+ // when finished with it.
+ virtual status_t setReleaseFenceFd(int fenceFd) = 0;
+
+ virtual void dump(String8& result) const = 0;
+
+protected:
+ DisplaySurface() {}
+ virtual ~DisplaySurface() {}
+};
+
+// ---------------------------------------------------------------------------
+} // namespace android
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_SF_DISPLAY_SURFACE_H
+
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 7557e3f..b5abaac 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -68,6 +68,17 @@
mBufferQueue->setDefaultMaxBufferCount(NUM_FRAMEBUFFER_SURFACE_BUFFERS);
}
+sp<IGraphicBufferProducer> FramebufferSurface::getIGraphicBufferProducer() const {
+ return getBufferQueue();
+}
+
+status_t FramebufferSurface::advanceFrame() {
+ // Once we remove FB HAL support, we can call nextBuffer() from here
+ // instead of using onFrameAvailable(). No real benefit, except it'll be
+ // more like VirtualDisplaySurface.
+ return NO_ERROR;
+}
+
status_t FramebufferSurface::nextBuffer(sp<GraphicBuffer>& outBuffer, sp<Fence>& outFence) {
Mutex::Autolock lock(mMutex);
@@ -134,7 +145,7 @@
if (fenceFd >= 0) {
sp<Fence> fence(new Fence(fenceFd));
if (mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT) {
- status_t err = addReleaseFence(mCurrentBufferSlot, fence);
+ err = addReleaseFence(mCurrentBufferSlot, fence);
ALOGE_IF(err, "setReleaseFenceFd: failed to add the fence: %s (%d)",
strerror(-err), err);
}
@@ -142,21 +153,38 @@
return err;
}
-status_t FramebufferSurface::setUpdateRectangle(const Rect& r)
-{
- return INVALID_OPERATION;
-}
-
status_t FramebufferSurface::compositionComplete()
{
return mHwc.fbCompositionComplete();
}
-void FramebufferSurface::dump(String8& result) {
- mHwc.fbDump(result);
+// Since DisplaySurface and ConsumerBase both have a method with this
+// signature, results will vary based on the static pointer type the caller is
+// using:
+// void dump(FrameBufferSurface* fbs, String8& s) {
+// // calls FramebufferSurface::dump()
+// fbs->dump(s);
+//
+// // calls ConsumerBase::dump() since it is non-virtual
+// static_cast<ConsumerBase*>(fbs)->dump(s);
+//
+// // calls FramebufferSurface::dump() since it is virtual
+// static_cast<DisplaySurface*>(fbs)->dump(s);
+// }
+// To make sure that all of these end up doing the same thing, we just redirect
+// to ConsumerBase::dump() here. It will take the internal lock, and then call
+// virtual dumpLocked(), which is where the real work happens.
+void FramebufferSurface::dump(String8& result) const {
ConsumerBase::dump(result);
}
+void FramebufferSurface::dumpLocked(String8& result, const char* prefix,
+ char* buffer, size_t SIZE) const
+{
+ mHwc.fbDump(result);
+ ConsumerBase::dumpLocked(result, prefix, buffer, SIZE);
+}
+
// ----------------------------------------------------------------------------
}; // namespace android
// ----------------------------------------------------------------------------
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
index b61b7f5..0aab742 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -22,6 +22,8 @@
#include <gui/ConsumerBase.h>
+#include "DisplaySurface.h"
+
// ---------------------------------------------------------------------------
namespace android {
// ---------------------------------------------------------------------------
@@ -32,23 +34,20 @@
// ---------------------------------------------------------------------------
-class FramebufferSurface : public ConsumerBase {
+class FramebufferSurface : public ConsumerBase,
+ public DisplaySurface {
public:
FramebufferSurface(HWComposer& hwc, int disp);
- bool isUpdateOnDemand() const { return false; }
- status_t setUpdateRectangle(const Rect& updateRect);
- status_t compositionComplete();
+ virtual sp<IGraphicBufferProducer> getIGraphicBufferProducer() const;
- virtual void dump(String8& result);
+ virtual status_t compositionComplete();
+ virtual status_t advanceFrame();
+ virtual status_t setReleaseFenceFd(int fenceFd);
- // setReleaseFenceFd stores a fence file descriptor that will signal when the
- // current buffer is no longer being read. This fence will be returned to
- // the producer when the current buffer is released by updateTexImage().
- // Multiple fences can be set for a given buffer; they will be merged into
- // a single union fence. The GLConsumer will close the file descriptor
- // when finished with it.
- status_t setReleaseFenceFd(int fenceFd);
+ // Implementation of DisplaySurface::dump(). Note that ConsumerBase also
+ // has a non-virtual dump() with the same signature.
+ virtual void dump(String8& result) const;
private:
virtual ~FramebufferSurface() { }; // this class cannot be overloaded
@@ -56,6 +55,9 @@
virtual void onFrameAvailable();
virtual void freeBufferLocked(int slotIndex);
+ virtual void dumpLocked(String8& result, const char* prefix,
+ char* buffer, size_t SIZE) const;
+
// nextBuffer waits for and then latches the next buffer from the
// BufferQueue and releases the previously latched buffer to the
// BufferQueue. The new buffer is returned in the 'buffer' argument.
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 11f65f6..96cfc14 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -41,7 +41,6 @@
#include <cutils/properties.h>
#include "Layer.h" // needed only for debugging
-#include "LayerBase.h"
#include "HWComposer.h"
#include "SurfaceFlinger.h"
#include <utils/CallStack.h>
@@ -100,7 +99,7 @@
bool needVSyncThread = true;
// Note: some devices may insist that the FB HAL be opened before HWC.
- loadFbHalModule();
+ int fberr = loadFbHalModule();
loadHwcModule();
if (mFbDev && mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
@@ -114,7 +113,8 @@
// If we have no HWC, or a pre-1.1 HWC, an FB dev is mandatory.
if ((!mHwc || !hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))
&& !mFbDev) {
- ALOGE("ERROR: failed to open framebuffer, aborting");
+ ALOGE("ERROR: failed to open framebuffer (%s), aborting",
+ strerror(-fberr));
abort();
}
@@ -235,20 +235,17 @@
}
// Load and prepare the FB HAL, which uses the gralloc module. Sets mFbDev.
-void HWComposer::loadFbHalModule()
+int HWComposer::loadFbHalModule()
{
hw_module_t const* module;
- if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) != 0) {
+ int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
+ if (err != 0) {
ALOGE("%s module not found", GRALLOC_HARDWARE_MODULE_ID);
- return;
+ return err;
}
- int err = framebuffer_open(module, &mFbDev);
- if (err) {
- ALOGE("framebuffer_open failed (%s)", strerror(-err));
- return;
- }
+ return framebuffer_open(module, &mFbDev);
}
status_t HWComposer::initCheck() const {
@@ -381,6 +378,7 @@
}
int32_t id = mAllocatedDisplayIDs.firstUnmarkedBit();
mAllocatedDisplayIDs.markBit(id);
+ mDisplayData[id].connected = true;
return id;
}
@@ -393,6 +391,7 @@
return BAD_INDEX;
}
mAllocatedDisplayIDs.clearBit(id);
+ mDisplayData[id].connected = false;
return NO_ERROR;
}
@@ -616,14 +615,14 @@
}
bool HWComposer::hasHwcComposition(int32_t id) const {
- if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id))
+ if (!mHwc || uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id))
return false;
return mDisplayData[id].hasOvComp;
}
bool HWComposer::hasGlesComposition(int32_t id) const {
- if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id))
- return false;
+ if (!mHwc || uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id))
+ return true;
return mDisplayData[id].hasFbComp;
}
@@ -654,6 +653,18 @@
mLists[0]->sur = eglGetCurrentSurface(EGL_DRAW);
}
+ // For virtual displays, the framebufferTarget buffer also serves as
+ // the HWC output buffer, so we need to copy the buffer handle and
+ // dup() the acquire fence.
+ for (size_t i=HWC_NUM_DISPLAY_TYPES; i<mNumDisplays; i++) {
+ DisplayData& disp(mDisplayData[i]);
+ if (disp.framebufferTarget) {
+ mLists[i]->outbuf = disp.framebufferTarget->handle;
+ mLists[i]->outbufAcquireFenceFd =
+ dup(disp.framebufferTarget->acquireFenceFd);
+ }
+ }
+
err = mHwc->set(mHwc, mNumDisplays, mLists);
for (size_t i=0 ; i<mNumDisplays ; i++) {
@@ -925,7 +936,7 @@
for (size_t i=0 ; i<mNumDisplays ; i++) {
const DisplayData& disp(mDisplayData[i]);
- const Vector< sp<LayerBase> >& visibleLayersSortedByZ =
+ const Vector< sp<Layer> >& visibleLayersSortedByZ =
mFlinger->getLayerSortedByZForHwcDisplay(i);
if (disp.connected) {
@@ -949,13 +960,11 @@
String8 name("unknown");
if (i < visibleLayersSortedByZ.size()) {
- const sp<LayerBase>& layer(visibleLayersSortedByZ[i]);
- if (layer->getLayer() != NULL) {
- const sp<GraphicBuffer>& buffer(
- layer->getLayer()->getActiveBuffer());
- if (buffer != NULL) {
- format = buffer->getPixelFormat();
- }
+ const sp<Layer>& layer(visibleLayersSortedByZ[i]);
+ const sp<GraphicBuffer>& buffer(
+ layer->getActiveBuffer());
+ if (buffer != NULL) {
+ format = buffer->getPixelFormat();
}
name = layer->getName();
}
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index f7ed1aa..fdbd2d9 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -47,7 +47,6 @@
class GraphicBuffer;
class Fence;
-class LayerBase;
class Region;
class String8;
class SurfaceFlinger;
@@ -113,7 +112,7 @@
// does this display have layers handled by GLES
bool hasGlesComposition(int32_t id) const;
- // get the releaseFence file descriptor for the given display
+ // get the releaseFence file descriptor for a display's framebuffer layer.
// the release fence is only valid after commit()
int getAndResetReleaseFenceFd(int32_t id);
@@ -266,7 +265,7 @@
private:
void loadHwcModule();
- void loadFbHalModule();
+ int loadFbHalModule();
LayerListIterator getLayerIterator(int32_t id, size_t index);
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
new file mode 100644
index 0000000..433e1eb
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2013 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 "VirtualDisplaySurface.h"
+#include "HWComposer.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+// ---------------------------------------------------------------------------
+
+VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, int disp,
+ const sp<IGraphicBufferProducer>& sink, const String8& name)
+: mHwc(hwc),
+ mDisplayId(disp),
+ mSource(new BufferQueueInterposer(sink, name)),
+ mName(name),
+ mReleaseFence(Fence::NO_FENCE)
+{}
+
+VirtualDisplaySurface::~VirtualDisplaySurface() {
+ if (mAcquiredBuffer != NULL) {
+ status_t result = mSource->releaseBuffer(mReleaseFence);
+ ALOGE_IF(result != NO_ERROR, "VirtualDisplaySurface \"%s\": "
+ "failed to release previous buffer: %d",
+ mName.string(), result);
+ }
+}
+
+sp<IGraphicBufferProducer> VirtualDisplaySurface::getIGraphicBufferProducer() const {
+ return mSource;
+}
+
+status_t VirtualDisplaySurface::compositionComplete() {
+ return NO_ERROR;
+}
+
+status_t VirtualDisplaySurface::advanceFrame() {
+ Mutex::Autolock lock(mMutex);
+ status_t result = NO_ERROR;
+
+ if (mAcquiredBuffer != NULL) {
+ result = mSource->releaseBuffer(mReleaseFence);
+ ALOGE_IF(result != NO_ERROR, "VirtualDisplaySurface \"%s\": "
+ "failed to release previous buffer: %d",
+ mName.string(), result);
+ mAcquiredBuffer.clear();
+ mReleaseFence = Fence::NO_FENCE;
+ }
+
+ sp<Fence> fence;
+ result = mSource->acquireBuffer(&mAcquiredBuffer, &fence);
+ if (result == BufferQueueInterposer::NO_BUFFER_AVAILABLE) {
+ result = mSource->pullEmptyBuffer();
+ if (result != NO_ERROR)
+ return result;
+ result = mSource->acquireBuffer(&mAcquiredBuffer, &fence);
+ }
+ if (result != NO_ERROR)
+ return result;
+
+ return mHwc.fbPost(mDisplayId, fence, mAcquiredBuffer);
+}
+
+status_t VirtualDisplaySurface::setReleaseFenceFd(int fenceFd) {
+ if (fenceFd >= 0) {
+ sp<Fence> fence(new Fence(fenceFd));
+ Mutex::Autolock lock(mMutex);
+ sp<Fence> mergedFence = Fence::merge(
+ String8::format("VirtualDisplaySurface \"%s\"",
+ mName.string()),
+ mReleaseFence, fence);
+ if (!mergedFence->isValid()) {
+ ALOGE("VirtualDisplaySurface \"%s\": failed to merge release fence",
+ mName.string());
+ // synchronization is broken, the best we can do is hope fences
+ // signal in order so the new fence will act like a union
+ mReleaseFence = fence;
+ return BAD_VALUE;
+ }
+ mReleaseFence = mergedFence;
+ }
+ return NO_ERROR;
+}
+
+void VirtualDisplaySurface::dump(String8& result) const {
+}
+
+// ---------------------------------------------------------------------------
+} // namespace android
+// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
new file mode 100644
index 0000000..66f8580
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2013 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.
+ */
+
+#ifndef ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H
+#define ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H
+
+#include "BufferQueueInterposer.h"
+#include "DisplaySurface.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+// ---------------------------------------------------------------------------
+
+class HWComposer;
+
+/* This DisplaySurface implementation uses a BufferQueueInterposer to pass
+ * partially- or fully-composited buffers from the OpenGL ES driver to
+ * HWComposer to use as the output buffer for virtual displays. Allowing HWC
+ * to compose into the same buffer that contains GLES results saves bandwidth
+ * compared to having two separate BufferQueues for frames with at least some
+ * GLES composition.
+ *
+ * The alternative would be to have two complete BufferQueues, one from GLES
+ * to HWC and one from HWC to the virtual display sink (e.g. video encoder).
+ * For GLES-only frames, the same bandwidth saving could be achieved if buffers
+ * could be acquired from the GLES->HWC queue and inserted into the HWC->sink
+ * queue. That would be complicated and doesn't help the mixed GLES+HWC case.
+ *
+ * On frames with no GLES composition, the VirtualDisplaySurface dequeues a
+ * buffer directly from the sink IGraphicBufferProducer and passes it to HWC,
+ * bypassing the GLES driver. This is only guaranteed to work if
+ * eglSwapBuffers doesn't immediately dequeue a buffer for the next frame,
+ * since we can't rely on being able to dequeue more than one buffer at a time.
+ *
+ * TODO(jessehall): Add a libgui test that ensures that EGL/GLES do lazy
+ * dequeBuffers; we've wanted to require that for other reasons anyway.
+ */
+class VirtualDisplaySurface : public DisplaySurface {
+public:
+ VirtualDisplaySurface(HWComposer& hwc, int disp,
+ const sp<IGraphicBufferProducer>& sink,
+ const String8& name);
+
+ virtual sp<IGraphicBufferProducer> getIGraphicBufferProducer() const;
+
+ virtual status_t compositionComplete();
+ virtual status_t advanceFrame();
+ virtual status_t setReleaseFenceFd(int fenceFd);
+ virtual void dump(String8& result) const;
+
+private:
+ virtual ~VirtualDisplaySurface();
+
+ // immutable after construction
+ HWComposer& mHwc;
+ int mDisplayId;
+ sp<BufferQueueInterposer> mSource;
+ String8 mName;
+
+ // mutable, must be synchronized with mMutex
+ Mutex mMutex;
+ sp<GraphicBuffer> mAcquiredBuffer;
+ sp<Fence> mReleaseFence;
+};
+
+// ---------------------------------------------------------------------------
+} // namespace android
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H
+
diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp
index edb9fa5..4d0fc79 100644
--- a/services/surfaceflinger/EventThread.cpp
+++ b/services/surfaceflinger/EventThread.cpp
@@ -41,7 +41,7 @@
mUseSoftwareVSync(false),
mDebugVsyncEnabled(false) {
- for (int32_t i=0 ; i<HWC_DISPLAY_TYPES_SUPPORTED ; i++) {
+ for (int32_t i=0 ; i<HWC_NUM_DISPLAY_TYPES ; i++) {
mVSyncEvent[i].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
mVSyncEvent[i].header.id = 0;
mVSyncEvent[i].header.timestamp = 0;
@@ -112,11 +112,11 @@
void EventThread::onVSyncReceived(int type, nsecs_t timestamp) {
- ALOGE_IF(type >= HWC_DISPLAY_TYPES_SUPPORTED,
- "received event for an invalid display (id=%d)", type);
+ ALOGE_IF(type >= HWC_NUM_DISPLAY_TYPES,
+ "received vsync event for an invalid display (id=%d)", type);
Mutex::Autolock _l(mLock);
- if (type < HWC_DISPLAY_TYPES_SUPPORTED) {
+ if (type < HWC_NUM_DISPLAY_TYPES) {
mVSyncEvent[type].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
mVSyncEvent[type].header.id = type;
mVSyncEvent[type].header.timestamp = timestamp;
@@ -126,11 +126,11 @@
}
void EventThread::onHotplugReceived(int type, bool connected) {
- ALOGE_IF(type >= HWC_DISPLAY_TYPES_SUPPORTED,
- "received event for an invalid display (id=%d)", type);
+ ALOGE_IF(type >= HWC_NUM_DISPLAY_TYPES,
+ "received hotplug event for an invalid display (id=%d)", type);
Mutex::Autolock _l(mLock);
- if (type < HWC_DISPLAY_TYPES_SUPPORTED) {
+ if (type < HWC_NUM_DISPLAY_TYPES) {
DisplayEventReceiver::Event event;
event.header.type = DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG;
event.header.id = type;
@@ -184,7 +184,7 @@
size_t vsyncCount = 0;
nsecs_t timestamp = 0;
- for (int32_t i=0 ; i<HWC_DISPLAY_TYPES_SUPPORTED ; i++) {
+ for (int32_t i=0 ; i<HWC_NUM_DISPLAY_TYPES ; i++) {
timestamp = mVSyncEvent[i].header.timestamp;
if (timestamp) {
// we have a vsync event to dispatch
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 439acb5..1677c76 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -50,45 +50,72 @@
// ---------------------------------------------------------------------------
-Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client)
- : LayerBaseClient(flinger, client),
+int32_t Layer::sSequence = 1;
+
+Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client,
+ const String8& name, uint32_t w, uint32_t h, uint32_t flags)
+ : contentDirty(false),
+ sequence(uint32_t(android_atomic_inc(&sSequence))),
+ mFlinger(flinger),
mTextureName(-1U),
+ mPremultipliedAlpha(true),
+ mName("unnamed"),
+ mDebug(false),
+ mFormat(PIXEL_FORMAT_NONE),
+ mGLExtensions(GLExtensions::getInstance()),
+ mOpaqueLayer(true),
+ mTransactionFlags(0),
mQueuedFrames(0),
mCurrentTransform(0),
mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
mCurrentOpacity(true),
mRefreshPending(false),
mFrameLatencyNeeded(false),
- mFormat(PIXEL_FORMAT_NONE),
- mGLExtensions(GLExtensions::getInstance()),
- mOpaqueLayer(true),
+ mFiltering(false),
+ mNeedsFiltering(false),
mSecure(false),
- mProtectedByApp(false)
+ mProtectedByApp(false),
+ mHasSurface(false),
+ mClientRef(client)
{
mCurrentCrop.makeInvalid();
glGenTextures(1, &mTextureName);
-}
-void Layer::onLayerDisplayed(const sp<const DisplayDevice>& hw,
- HWComposer::HWCLayerInterface* layer) {
- LayerBaseClient::onLayerDisplayed(hw, layer);
- if (layer) {
- mSurfaceFlingerConsumer->setReleaseFence(layer->getAndResetReleaseFenceFd());
- }
+ uint32_t layerFlags = 0;
+ if (flags & ISurfaceComposerClient::eHidden)
+ layerFlags = layer_state_t::eLayerHidden;
+
+ if (flags & ISurfaceComposerClient::eNonPremultiplied)
+ mPremultipliedAlpha = false;
+
+ mName = name;
+
+ mCurrentState.active.w = w;
+ mCurrentState.active.h = h;
+ mCurrentState.active.crop.makeInvalid();
+ mCurrentState.z = 0;
+ mCurrentState.alpha = 0xFF;
+ mCurrentState.layerStack = 0;
+ mCurrentState.flags = layerFlags;
+ mCurrentState.sequence = 0;
+ mCurrentState.transform.set(0, 0);
+ mCurrentState.requested = mCurrentState.active;
+
+ // drawing state & current state are identical
+ mDrawingState = mCurrentState;
}
void Layer::onFirstRef()
{
- LayerBaseClient::onFirstRef();
-
// Creates a custom BufferQueue for SurfaceFlingerConsumer to use
- sp<BufferQueue> bq = new SurfaceTextureLayer();
+ sp<BufferQueue> bq = new SurfaceTextureLayer(mFlinger);
mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(mTextureName, true,
GL_TEXTURE_EXTERNAL_OES, false, bq);
mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
mSurfaceFlingerConsumer->setFrameAvailableListener(this);
mSurfaceFlingerConsumer->setSynchronousMode(true);
+ mSurfaceFlingerConsumer->setName(mName);
#ifdef TARGET_DISABLE_TRIPLE_BUFFERING
#warning "disabling triple buffering"
@@ -101,68 +128,44 @@
updateTransformHint(hw);
}
-Layer::~Layer()
-{
+Layer::~Layer() {
+ sp<Client> c(mClientRef.promote());
+ if (c != 0) {
+ c->detachLayer(this);
+ }
mFlinger->deleteTextureAsync(mTextureName);
}
+// ---------------------------------------------------------------------------
+// callbacks
+// ---------------------------------------------------------------------------
+
+void Layer::onLayerDisplayed(const sp<const DisplayDevice>& hw,
+ HWComposer::HWCLayerInterface* layer) {
+ if (layer) {
+ layer->onDisplayed();
+ mSurfaceFlingerConsumer->setReleaseFence(layer->getAndResetReleaseFenceFd());
+ }
+}
+
void Layer::onFrameAvailable() {
android_atomic_inc(&mQueuedFrames);
mFlinger->signalLayerUpdate();
}
-// called with SurfaceFlinger::mStateLock as soon as the layer is entered
-// in the purgatory list
-void Layer::onRemoved()
-{
+// called with SurfaceFlinger::mStateLock from the drawing thread after
+// the layer has been remove from the current state list (and just before
+// it's removed from the drawing state list)
+void Layer::onRemoved() {
mSurfaceFlingerConsumer->abandon();
}
-void Layer::setName(const String8& name) {
- LayerBase::setName(name);
- mSurfaceFlingerConsumer->setName(name);
-}
+// ---------------------------------------------------------------------------
+// set-up
+// ---------------------------------------------------------------------------
-sp<ISurface> Layer::createSurface()
-{
- /*
- * This class provides an implementation of BnSurface (the "native" or
- * "remote" side of the Binder IPC interface ISurface), and mixes in
- * LayerCleaner to ensure that mFlinger->onLayerDestroyed() is called for
- * this layer when the BSurface is destroyed.
- *
- * The idea is to provide a handle to the Layer through ISurface that
- * is cleaned up automatically when the last reference to the ISurface
- * goes away. (The references will be held on the "proxy" side, while
- * the Layer exists on the "native" side.)
- *
- * The Layer has a reference to an instance of SurfaceFlinger's variant
- * of GLConsumer, which holds a reference to the BufferQueue. The
- * getSurfaceTexture() call returns a Binder interface reference for
- * the producer interface of the buffer queue associated with the Layer.
- */
- class BSurface : public BnSurface, public LayerCleaner {
- wp<const Layer> mOwner;
- virtual sp<IGraphicBufferProducer> getSurfaceTexture() const {
- sp<IGraphicBufferProducer> res;
- sp<const Layer> that( mOwner.promote() );
- if (that != NULL) {
- res = that->mSurfaceFlingerConsumer->getBufferQueue();
- }
- return res;
- }
- public:
- BSurface(const sp<SurfaceFlinger>& flinger,
- const sp<Layer>& layer)
- : LayerCleaner(flinger, layer), mOwner(layer) { }
- };
- sp<ISurface> sur(new BSurface(mFlinger, this));
- return sur;
-}
-
-wp<IBinder> Layer::getSurfaceTextureBinder() const
-{
- return mSurfaceFlingerConsumer->getBufferQueue()->asBinder();
+String8 Layer::getName() const {
+ return mName;
}
status_t Layer::setBuffers( uint32_t w, uint32_t h,
@@ -200,26 +203,117 @@
return NO_ERROR;
}
-Rect Layer::computeBufferCrop() const {
- // Start with the SurfaceFlingerConsumer's buffer crop...
+sp<IBinder> Layer::getHandle() {
+ Mutex::Autolock _l(mLock);
+
+ LOG_ALWAYS_FATAL_IF(mHasSurface,
+ "Layer::getHandle() has already been called");
+
+ mHasSurface = true;
+
+ /*
+ * The layer handle is just a BBinder object passed to the client
+ * (remote process) -- we don't keep any reference on our side such that
+ * the dtor is called when the remote side let go of its reference.
+ *
+ * LayerCleaner ensures that mFlinger->onLayerDestroyed() is called for
+ * this layer when the handle is destroyed.
+ */
+
+ class Handle : public BBinder, public LayerCleaner {
+ wp<const Layer> mOwner;
+ public:
+ Handle(const sp<SurfaceFlinger>& flinger, const sp<Layer>& layer)
+ : LayerCleaner(flinger, layer), mOwner(layer) {
+ }
+ };
+
+ return new Handle(mFlinger, this);
+}
+
+sp<BufferQueue> Layer::getBufferQueue() const {
+ return mSurfaceFlingerConsumer->getBufferQueue();
+}
+
+//virtual sp<IGraphicBufferProducer> getSurfaceTexture() const {
+// sp<IGraphicBufferProducer> res;
+// sp<const Layer> that( mOwner.promote() );
+// if (that != NULL) {
+// res = that->mSurfaceFlingerConsumer->getBufferQueue();
+// }
+// return res;
+//}
+
+// ---------------------------------------------------------------------------
+// h/w composer set-up
+// ---------------------------------------------------------------------------
+
+Rect Layer::getContentCrop() const {
+ // this is the crop rectangle that applies to the buffer
+ // itself (as opposed to the window)
Rect crop;
if (!mCurrentCrop.isEmpty()) {
+ // if the buffer crop is defined, we use that
crop = mCurrentCrop;
- } else if (mActiveBuffer != NULL){
- crop = Rect(mActiveBuffer->getWidth(), mActiveBuffer->getHeight());
+ } else if (mActiveBuffer != NULL) {
+ // otherwise we use the whole buffer
+ crop = mActiveBuffer->getBounds();
} else {
+ // if we don't have a buffer yet, we use an empty/invalid crop
crop.makeInvalid();
- return crop;
}
+ return crop;
+}
- // ... then reduce that in the same proportions as the window crop reduces
- // the window size.
- const State& s(drawingState());
+uint32_t Layer::getContentTransform() const {
+ return mCurrentTransform;
+}
+
+Rect Layer::computeBounds() const {
+ const Layer::State& s(drawingState());
+ Rect win(s.active.w, s.active.h);
if (!s.active.crop.isEmpty()) {
+ win.intersect(s.active.crop, &win);
+ }
+ return win;
+}
+
+Rect Layer::computeCrop(const sp<const DisplayDevice>& hw) const {
+ /*
+ * The way we compute the crop (aka. texture coordinates when we have a
+ * Layer) produces a different output from the GL code in
+ * drawWithOpenGL() due to HWC being limited to integers. The difference
+ * can be large if getContentTransform() contains a large scale factor.
+ * See comments in drawWithOpenGL() for more details.
+ */
+
+ // the content crop is the area of the content that gets scaled to the
+ // layer's size.
+ Rect crop(getContentCrop());
+
+ // the active.crop is the area of the window that gets cropped, but not
+ // scaled in any ways.
+ const State& s(drawingState());
+
+ // apply the projection's clipping to the window crop in
+ // layerstack space, and convert-back to layer space.
+ // if there are no window scaling (or content scaling) involved,
+ // this operation will map to full pixels in the buffer.
+ // NOTE: should we revert to GL composition if a scaling is involved
+ // since it cannot be represented in the HWC API?
+ Rect activeCrop(s.transform.transform(s.active.crop));
+ activeCrop.intersect(hw->getViewport(), &activeCrop);
+ activeCrop = s.transform.inverse().transform(activeCrop);
+
+ // paranoia: make sure the window-crop is constrained in the
+ // window's bounds
+ activeCrop.intersect(Rect(s.active.w, s.active.h), &activeCrop);
+
+ if (!activeCrop.isEmpty()) {
// Transform the window crop to match the buffer coordinate system,
// which means using the inverse of the current transform set on the
// SurfaceFlingerConsumer.
- uint32_t invTransform = mCurrentTransform;
+ uint32_t invTransform = getContentTransform();
int winWidth = s.active.w;
int winHeight = s.active.h;
if (invTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
@@ -228,17 +322,24 @@
winWidth = s.active.h;
winHeight = s.active.w;
}
- Rect winCrop = s.active.crop.transform(invTransform,
- s.active.w, s.active.h);
+ const Rect winCrop = activeCrop.transform(
+ invTransform, s.active.w, s.active.h);
+ // the code below essentially performs a scaled intersection
+ // of crop and winCrop
float xScale = float(crop.width()) / float(winWidth);
float yScale = float(crop.height()) / float(winHeight);
- crop.left += int(ceilf(float(winCrop.left) * xScale));
- crop.top += int(ceilf(float(winCrop.top) * yScale));
- crop.right -= int(ceilf(float(winWidth - winCrop.right) * xScale));
- crop.bottom -= int(ceilf(float(winHeight - winCrop.bottom) * yScale));
- }
+ int insetL = int(ceilf( winCrop.left * xScale));
+ int insetT = int(ceilf( winCrop.top * yScale));
+ int insetR = int(ceilf((winWidth - winCrop.right ) * xScale));
+ int insetB = int(ceilf((winHeight - winCrop.bottom) * yScale));
+
+ crop.left += insetL;
+ crop.top += insetT;
+ crop.right -= insetR;
+ crop.bottom -= insetB;
+ }
return crop;
}
@@ -246,7 +347,7 @@
const sp<const DisplayDevice>& hw,
HWComposer::HWCLayerInterface& layer)
{
- LayerBaseClient::setGeometry(hw, layer);
+ layer.setDefaultState();
// enable this layer
layer.setSkip(false);
@@ -255,7 +356,21 @@
layer.setSkip(true);
}
+ // this gives us only the "orientation" component of the transform
const State& s(drawingState());
+ if (!isOpaque() || s.alpha != 0xFF) {
+ layer.setBlending(mPremultipliedAlpha ?
+ HWC_BLENDING_PREMULT :
+ HWC_BLENDING_COVERAGE);
+ }
+
+ // apply the layer's transform, followed by the display's global transform
+ // here we're guaranteed that the layer's transform preserves rects
+ Rect frame(s.transform.transform(computeBounds()));
+ frame.intersect(hw->getViewport(), &frame);
+ const Transform& tr(hw->getTransform());
+ layer.setFrame(tr.transform(frame));
+ layer.setCrop(computeCrop(hw));
layer.setPlaneAlpha(s.alpha);
/*
@@ -267,23 +382,29 @@
*/
const Transform bufferOrientation(mCurrentTransform);
- const Transform tr(hw->getTransform() * s.transform * bufferOrientation);
+ const Transform transform(tr * s.transform * bufferOrientation);
// this gives us only the "orientation" component of the transform
- const uint32_t finalTransform = tr.getOrientation();
-
- // we can only handle simple transformation
- if (finalTransform & Transform::ROT_INVALID) {
+ const uint32_t orientation = transform.getOrientation();
+ if (orientation & Transform::ROT_INVALID) {
+ // we can only handle simple transformation
layer.setSkip(true);
} else {
- layer.setTransform(finalTransform);
+ layer.setTransform(orientation);
}
- layer.setCrop(computeBufferCrop());
}
void Layer::setPerFrameData(const sp<const DisplayDevice>& hw,
HWComposer::HWCLayerInterface& layer) {
- LayerBaseClient::setPerFrameData(hw, layer);
+ // we have to set the visible region on every frame because
+ // we currently free it during onLayerDisplayed(), which is called
+ // after HWComposer::commit() -- every frame.
+ // Apply this display's projection's viewport to the visible region
+ // before giving it to the HWC HAL.
+ const Transform& tr = hw->getTransform();
+ Region visible = tr.transform(visibleRegion.intersect(hw->getViewport()));
+ layer.setVisibleRegionScreen(visible);
+
// NOTE: buffer can be NULL if the client never drew into this
// layer yet, or if we ran out of memory
layer.setBuffer(mActiveBuffer);
@@ -308,6 +429,18 @@
layer.setAcquireFenceFd(fenceFd);
}
+// ---------------------------------------------------------------------------
+// drawing...
+// ---------------------------------------------------------------------------
+
+void Layer::draw(const sp<const DisplayDevice>& hw, const Region& clip) const {
+ onDraw(hw, clip);
+}
+
+void Layer::draw(const sp<const DisplayDevice>& hw) {
+ onDraw( hw, Region(hw->bounds()) );
+}
+
void Layer::onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const
{
ATRACE_CALL();
@@ -327,8 +460,8 @@
mFlinger->mDrawingState.layersSortedByZ);
const size_t count = drawingLayers.size();
for (size_t i=0 ; i<count ; ++i) {
- const sp<LayerBase>& layer(drawingLayers[i]);
- if (layer.get() == static_cast<LayerBase const*>(this))
+ const sp<Layer>& layer(drawingLayers[i]);
+ if (layer.get() == static_cast<Layer const*>(this))
break;
under.orSelf( hw->getTransform().transform(layer->visibleRegion) );
}
@@ -388,6 +521,119 @@
glDisable(GL_TEXTURE_2D);
}
+
+void Layer::clearWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip,
+ GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) const
+{
+ const uint32_t fbHeight = hw->getHeight();
+ glColor4f(red,green,blue,alpha);
+
+ glDisable(GL_TEXTURE_EXTERNAL_OES);
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_BLEND);
+
+ LayerMesh mesh;
+ computeGeometry(hw, &mesh);
+
+ glVertexPointer(2, GL_FLOAT, 0, mesh.getVertices());
+ glDrawArrays(GL_TRIANGLE_FAN, 0, mesh.getVertexCount());
+}
+
+void Layer::clearWithOpenGL(
+ const sp<const DisplayDevice>& hw, const Region& clip) const {
+ clearWithOpenGL(hw, clip, 0,0,0,0);
+}
+
+void Layer::drawWithOpenGL(
+ const sp<const DisplayDevice>& hw, const Region& clip) const {
+ const uint32_t fbHeight = hw->getHeight();
+ const State& s(drawingState());
+
+ GLenum src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
+ if (CC_UNLIKELY(s.alpha < 0xFF)) {
+ const GLfloat alpha = s.alpha * (1.0f/255.0f);
+ if (mPremultipliedAlpha) {
+ glColor4f(alpha, alpha, alpha, alpha);
+ } else {
+ glColor4f(1, 1, 1, alpha);
+ }
+ glEnable(GL_BLEND);
+ glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ } else {
+ glColor4f(1, 1, 1, 1);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ if (!isOpaque()) {
+ glEnable(GL_BLEND);
+ glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);
+ } else {
+ glDisable(GL_BLEND);
+ }
+ }
+
+ LayerMesh mesh;
+ computeGeometry(hw, &mesh);
+
+ // TODO: we probably want to generate the texture coords with the mesh
+ // here we assume that we only have 4 vertices
+
+ struct TexCoords {
+ GLfloat u;
+ GLfloat v;
+ };
+
+
+ /*
+ * NOTE: the way we compute the texture coordinates here produces
+ * different results than when we take the HWC path -- in the later case
+ * the "source crop" is rounded to texel boundaries.
+ * This can produce significantly different results when the texture
+ * is scaled by a large amount.
+ *
+ * The GL code below is more logical (imho), and the difference with
+ * HWC is due to a limitation of the HWC API to integers -- a question
+ * is suspend is wether we should ignore this problem or revert to
+ * GL composition when a buffer scaling is applied (maybe with some
+ * minimal value)? Or, we could make GL behave like HWC -- but this feel
+ * like more of a hack.
+ */
+ const Rect win(computeBounds());
+
+ GLfloat left = GLfloat(win.left) / GLfloat(s.active.w);
+ GLfloat top = GLfloat(win.top) / GLfloat(s.active.h);
+ GLfloat right = GLfloat(win.right) / GLfloat(s.active.w);
+ GLfloat bottom = GLfloat(win.bottom) / GLfloat(s.active.h);
+
+ TexCoords texCoords[4];
+ texCoords[0].u = left;
+ texCoords[0].v = top;
+ texCoords[1].u = left;
+ texCoords[1].v = bottom;
+ texCoords[2].u = right;
+ texCoords[2].v = bottom;
+ texCoords[3].u = right;
+ texCoords[3].v = top;
+ for (int i = 0; i < 4; i++) {
+ texCoords[i].v = 1.0f - texCoords[i].v;
+ }
+
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
+ glVertexPointer(2, GL_FLOAT, 0, mesh.getVertices());
+ glDrawArrays(GL_TRIANGLE_FAN, 0, mesh.getVertexCount());
+
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisable(GL_BLEND);
+}
+
+void Layer::setFiltering(bool filtering) {
+ mFiltering = filtering;
+}
+
+bool Layer::getFiltering() const {
+ return mFiltering;
+}
+
// As documented in libhardware header, formats in the range
// 0x100 - 0x1FF are specific to the HAL implementation, and
// are known to have no alpha channel
@@ -406,6 +652,29 @@
return (err || info.h_alpha <= info.l_alpha);
}
+// ----------------------------------------------------------------------------
+// local state
+// ----------------------------------------------------------------------------
+
+void Layer::computeGeometry(const sp<const DisplayDevice>& hw, LayerMesh* mesh) const
+{
+ const Layer::State& s(drawingState());
+ const Transform tr(hw->getTransform() * s.transform);
+ const uint32_t hw_h = hw->getHeight();
+ Rect win(s.active.w, s.active.h);
+ if (!s.active.crop.isEmpty()) {
+ win.intersect(s.active.crop, &win);
+ }
+ if (mesh) {
+ tr.transform(mesh->mVertices[0], win.left, win.top);
+ tr.transform(mesh->mVertices[1], win.left, win.bottom);
+ tr.transform(mesh->mVertices[2], win.right, win.bottom);
+ tr.transform(mesh->mVertices[3], win.right, win.top);
+ for (size_t i=0 ; i<4 ; i++) {
+ mesh->mVertices[i][1] = hw_h - mesh->mVertices[i][1];
+ }
+ }
+}
bool Layer::isOpaque() const
{
@@ -427,8 +696,39 @@
(activeBuffer->getUsage() & GRALLOC_USAGE_PROTECTED);
}
-uint32_t Layer::doTransaction(uint32_t flags)
-{
+bool Layer::isFixedSize() const {
+ return mCurrentScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE;
+}
+
+bool Layer::isCropped() const {
+ return !mCurrentCrop.isEmpty();
+}
+
+bool Layer::needsFiltering(const sp<const DisplayDevice>& hw) const {
+ return mNeedsFiltering || hw->needsFiltering();
+}
+
+void Layer::setVisibleRegion(const Region& visibleRegion) {
+ // always called from main thread
+ this->visibleRegion = visibleRegion;
+}
+
+void Layer::setCoveredRegion(const Region& coveredRegion) {
+ // always called from main thread
+ this->coveredRegion = coveredRegion;
+}
+
+void Layer::setVisibleNonTransparentRegion(const Region&
+ setVisibleNonTransparentRegion) {
+ // always called from main thread
+ this->visibleNonTransparentRegion = setVisibleNonTransparentRegion;
+}
+
+// ----------------------------------------------------------------------------
+// transaction
+// ----------------------------------------------------------------------------
+
+uint32_t Layer::doTransaction(uint32_t flags) {
ATRACE_CALL();
const Layer::State& front(drawingState());
@@ -487,7 +787,7 @@
(temp.requested.h != temp.active.h);
if (resizePending) {
- // don't let LayerBase::doTransaction update the drawing state
+ // don't let Layer::doTransaction update the drawing state
// if we have a pending resize, unless we are in fixed-size mode.
// the drawing state will be updated only once we receive a buffer
// with the correct size.
@@ -500,15 +800,117 @@
}
}
- return LayerBase::doTransaction(flags);
+ // always set active to requested, unless we're asked not to
+ // this is used by Layer, which special cases resizes.
+ if (flags & eDontUpdateGeometryState) {
+ } else {
+ Layer::State& editTemp(currentState());
+ editTemp.active = temp.requested;
+ }
+
+ if (front.active != temp.active) {
+ // invalidate and recompute the visible regions if needed
+ flags |= Layer::eVisibleRegion;
+ }
+
+ if (temp.sequence != front.sequence) {
+ // invalidate and recompute the visible regions if needed
+ flags |= eVisibleRegion;
+ this->contentDirty = true;
+
+ // we may use linear filtering, if the matrix scales us
+ const uint8_t type = temp.transform.getType();
+ mNeedsFiltering = (!temp.transform.preserveRects() ||
+ (type >= Transform::SCALE));
+ }
+
+ // Commit the transaction
+ commitTransaction();
+ return flags;
}
-bool Layer::isFixedSize() const {
- return mCurrentScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE;
+void Layer::commitTransaction() {
+ mDrawingState = mCurrentState;
}
-bool Layer::isCropped() const {
- return !mCurrentCrop.isEmpty();
+uint32_t Layer::getTransactionFlags(uint32_t flags) {
+ return android_atomic_and(~flags, &mTransactionFlags) & flags;
+}
+
+uint32_t Layer::setTransactionFlags(uint32_t flags) {
+ return android_atomic_or(flags, &mTransactionFlags);
+}
+
+bool Layer::setPosition(float x, float y) {
+ if (mCurrentState.transform.tx() == x && mCurrentState.transform.ty() == y)
+ return false;
+ mCurrentState.sequence++;
+ mCurrentState.transform.set(x, y);
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+bool Layer::setLayer(uint32_t z) {
+ if (mCurrentState.z == z)
+ return false;
+ mCurrentState.sequence++;
+ mCurrentState.z = z;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+bool Layer::setSize(uint32_t w, uint32_t h) {
+ if (mCurrentState.requested.w == w && mCurrentState.requested.h == h)
+ return false;
+ mCurrentState.requested.w = w;
+ mCurrentState.requested.h = h;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+bool Layer::setAlpha(uint8_t alpha) {
+ if (mCurrentState.alpha == alpha)
+ return false;
+ mCurrentState.sequence++;
+ mCurrentState.alpha = alpha;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+bool Layer::setMatrix(const layer_state_t::matrix22_t& matrix) {
+ mCurrentState.sequence++;
+ mCurrentState.transform.set(
+ matrix.dsdx, matrix.dsdy, matrix.dtdx, matrix.dtdy);
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+bool Layer::setTransparentRegionHint(const Region& transparent) {
+ mCurrentState.sequence++;
+ mCurrentState.transparentRegion = transparent;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+bool Layer::setFlags(uint8_t flags, uint8_t mask) {
+ const uint32_t newFlags = (mCurrentState.flags & ~mask) | (flags & mask);
+ if (mCurrentState.flags == newFlags)
+ return false;
+ mCurrentState.sequence++;
+ mCurrentState.flags = newFlags;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+bool Layer::setCrop(const Rect& crop) {
+ if (mCurrentState.requested.crop == crop)
+ return false;
+ mCurrentState.sequence++;
+ mCurrentState.requested.crop = crop;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
+bool Layer::setLayerStack(uint32_t layerStack) {
+ if (mCurrentState.layerStack == layerStack)
+ return false;
+ mCurrentState.sequence++;
+ mCurrentState.layerStack = layerStack;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
}
// ----------------------------------------------------------------------------
@@ -551,7 +953,9 @@
}
bool Layer::isVisible() const {
- return LayerBaseClient::isVisible() && (mActiveBuffer != NULL);
+ const Layer::State& s(mDrawingState);
+ return !(s.flags & layer_state_t::eLayerHidden) && s.alpha
+ && (mActiveBuffer != NULL);
}
Region Layer::latchBuffer(bool& recomputeVisibleRegions)
@@ -725,44 +1129,6 @@
return outDirtyRegion;
}
-void Layer::dump(String8& result, char* buffer, size_t SIZE) const
-{
- LayerBaseClient::dump(result, buffer, SIZE);
-
- sp<const GraphicBuffer> buf0(mActiveBuffer);
- uint32_t w0=0, h0=0, s0=0, f0=0;
- if (buf0 != 0) {
- w0 = buf0->getWidth();
- h0 = buf0->getHeight();
- s0 = buf0->getStride();
- f0 = buf0->format;
- }
- snprintf(buffer, SIZE,
- " "
- "format=%2d, activeBuffer=[%4ux%4u:%4u,%3X],"
- " queued-frames=%d, mRefreshPending=%d\n",
- mFormat, w0, h0, s0,f0,
- mQueuedFrames, mRefreshPending);
-
- result.append(buffer);
-
- if (mSurfaceFlingerConsumer != 0) {
- mSurfaceFlingerConsumer->dump(result, " ", buffer, SIZE);
- }
-}
-
-void Layer::dumpStats(String8& result, char* buffer, size_t SIZE) const
-{
- LayerBaseClient::dumpStats(result, buffer, SIZE);
- mFrameTracker.dump(result);
-}
-
-void Layer::clearStats()
-{
- LayerBaseClient::clearStats();
- mFrameTracker.clear();
-}
-
uint32_t Layer::getEffectiveUsage(uint32_t usage) const
{
// TODO: should we do something special if mSecure is set?
@@ -789,6 +1155,86 @@
mSurfaceFlingerConsumer->setTransformHint(orientation);
}
+// ----------------------------------------------------------------------------
+// debugging
+// ----------------------------------------------------------------------------
+
+void Layer::dump(String8& result, char* buffer, size_t SIZE) const
+{
+ const Layer::State& s(drawingState());
+
+ snprintf(buffer, SIZE,
+ "+ %s %p (%s)\n",
+ getTypeId(), this, getName().string());
+ result.append(buffer);
+
+ s.transparentRegion.dump(result, "transparentRegion");
+ visibleRegion.dump(result, "visibleRegion");
+ sp<Client> client(mClientRef.promote());
+
+ snprintf(buffer, SIZE,
+ " "
+ "layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), crop=(%4d,%4d,%4d,%4d), "
+ "isOpaque=%1d, invalidate=%1d, "
+ "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n"
+ " client=%p\n",
+ s.layerStack, s.z, s.transform.tx(), s.transform.ty(), s.active.w, s.active.h,
+ s.active.crop.left, s.active.crop.top,
+ s.active.crop.right, s.active.crop.bottom,
+ isOpaque(), contentDirty,
+ s.alpha, s.flags,
+ s.transform[0][0], s.transform[0][1],
+ s.transform[1][0], s.transform[1][1],
+ client.get());
+ result.append(buffer);
+
+ sp<const GraphicBuffer> buf0(mActiveBuffer);
+ uint32_t w0=0, h0=0, s0=0, f0=0;
+ if (buf0 != 0) {
+ w0 = buf0->getWidth();
+ h0 = buf0->getHeight();
+ s0 = buf0->getStride();
+ f0 = buf0->format;
+ }
+ snprintf(buffer, SIZE,
+ " "
+ "format=%2d, activeBuffer=[%4ux%4u:%4u,%3X],"
+ " queued-frames=%d, mRefreshPending=%d\n",
+ mFormat, w0, h0, s0,f0,
+ mQueuedFrames, mRefreshPending);
+
+ result.append(buffer);
+
+ if (mSurfaceFlingerConsumer != 0) {
+ mSurfaceFlingerConsumer->dump(result, " ", buffer, SIZE);
+ }
+}
+
+
+void Layer::shortDump(String8& result, char* scratch, size_t size) const {
+ Layer::dump(result, scratch, size);
+}
+
+void Layer::dumpStats(String8& result, char* buffer, size_t SIZE) const {
+ mFrameTracker.dump(result);
+}
+
+void Layer::clearStats() {
+ mFrameTracker.clear();
+}
+
+// ---------------------------------------------------------------------------
+
+Layer::LayerCleaner::LayerCleaner(const sp<SurfaceFlinger>& flinger,
+ const sp<Layer>& layer)
+ : mFlinger(flinger), mLayer(layer) {
+}
+
+Layer::LayerCleaner::~LayerCleaner() {
+ // destroy client resources
+ mFlinger->onLayerDestroyed(mLayer);
+}
+
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index a82767b..6bca941 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -20,112 +20,343 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Timers.h>
-
-#include <ui/GraphicBuffer.h>
-#include <ui/PixelFormat.h>
-
-#include <gui/ISurfaceComposerClient.h>
-
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES/gl.h>
#include <GLES/glext.h>
-#include "SurfaceFlingerConsumer.h"
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+#include <utils/Timers.h>
+
+#include <ui/GraphicBuffer.h>
+#include <ui/PixelFormat.h>
+#include <ui/Region.h>
+
+#include <gui/ISurfaceComposerClient.h>
+
+#include <private/gui/LayerState.h>
+
#include "FrameTracker.h"
-#include "LayerBase.h"
+#include "Client.h"
+#include "SurfaceFlinger.h"
+#include "SurfaceFlingerConsumer.h"
#include "SurfaceTextureLayer.h"
#include "Transform.h"
+#include "DisplayHardware/HWComposer.h"
+
namespace android {
// ---------------------------------------------------------------------------
class Client;
+class DisplayDevice;
+class GraphicBuffer;
+class SurfaceFlinger;
class GLExtensions;
// ---------------------------------------------------------------------------
/*
- * The Layer class is essentially a LayerBase combined with a BufferQueue.
* A new BufferQueue and a new SurfaceFlingerConsumer are created when the
* Layer is first referenced.
*
* This also implements onFrameAvailable(), which notifies SurfaceFlinger
* that new data has arrived.
*/
-class Layer : public LayerBaseClient,
- public SurfaceFlingerConsumer::FrameAvailableListener
-{
+class Layer : public SurfaceFlingerConsumer::FrameAvailableListener {
+ static int32_t sSequence;
+
public:
- Layer(SurfaceFlinger* flinger, const sp<Client>& client);
+ mutable bool contentDirty;
+ // regions below are in window-manager space
+ Region visibleRegion;
+ Region coveredRegion;
+ Region visibleNonTransparentRegion;
+ int32_t sequence;
+
+ enum { // flags for doTransaction()
+ eDontUpdateGeometryState = 0x00000001,
+ eVisibleRegion = 0x00000002,
+ };
+
+ struct Geometry {
+ uint32_t w;
+ uint32_t h;
+ Rect crop;
+ inline bool operator ==(const Geometry& rhs) const {
+ return (w == rhs.w && h == rhs.h && crop == rhs.crop);
+ }
+ inline bool operator !=(const Geometry& rhs) const {
+ return !operator ==(rhs);
+ }
+ };
+
+ struct State {
+ Geometry active;
+ Geometry requested;
+ uint32_t z;
+ uint32_t layerStack;
+ uint8_t alpha;
+ uint8_t flags;
+ uint8_t reserved[2];
+ int32_t sequence; // changes when visible regions can change
+ Transform transform;
+ Region transparentRegion;
+ };
+
+ class LayerMesh {
+ friend class Layer;
+ GLfloat mVertices[4][2];
+ size_t mNumVertices;
+ public:
+ LayerMesh() :
+ mNumVertices(4) {
+ }
+ GLfloat const* getVertices() const {
+ return &mVertices[0][0];
+ }
+ size_t getVertexCount() const {
+ return mNumVertices;
+ }
+ };
+
+ // -----------------------------------------------------------------------
+
+ Layer(SurfaceFlinger* flinger, const sp<Client>& client,
+ const String8& name, uint32_t w, uint32_t h, uint32_t flags);
virtual ~Layer();
+ // the this layer's size and format
+ status_t setBuffers(uint32_t w, uint32_t h, PixelFormat format, uint32_t flags);
+
+ // modify current state
+ bool setPosition(float x, float y);
+ bool setLayer(uint32_t z);
+ bool setSize(uint32_t w, uint32_t h);
+ bool setAlpha(uint8_t alpha);
+ bool setMatrix(const layer_state_t::matrix22_t& matrix);
+ bool setTransparentRegionHint(const Region& transparent);
+ bool setFlags(uint8_t flags, uint8_t mask);
+ bool setCrop(const Rect& crop);
+ bool setLayerStack(uint32_t layerStack);
+
+ void commitTransaction();
+
+ uint32_t getTransactionFlags(uint32_t flags);
+ uint32_t setTransactionFlags(uint32_t flags);
+
+ void computeGeometry(const sp<const DisplayDevice>& hw, LayerMesh* mesh) const;
+ Rect computeBounds() const;
+
+ sp<IBinder> getHandle();
+ sp<BufferQueue> getBufferQueue() const;
+ String8 getName() const;
+
+ // -----------------------------------------------------------------------
+
virtual const char* getTypeId() const { return "Layer"; }
- // the this layer's size and format
- status_t setBuffers(uint32_t w, uint32_t h,
- PixelFormat format, uint32_t flags=0);
-
- bool isFixedSize() const;
-
- // LayerBase interface
virtual void setGeometry(const sp<const DisplayDevice>& hw,
HWComposer::HWCLayerInterface& layer);
virtual void setPerFrameData(const sp<const DisplayDevice>& hw,
HWComposer::HWCLayerInterface& layer);
virtual void setAcquireFence(const sp<const DisplayDevice>& hw,
HWComposer::HWCLayerInterface& layer);
+
+ /*
+ * called after page-flip
+ */
virtual void onLayerDisplayed(const sp<const DisplayDevice>& hw,
HWComposer::HWCLayerInterface* layer);
+
+ /*
+ * called before composition.
+ * returns true if the layer has pending updates.
+ */
virtual bool onPreComposition();
+
+ /*
+ * called after composition.
+ */
virtual void onPostComposition();
+ /*
+ * draw - performs some global clipping optimizations
+ * and calls onDraw().
+ * Typically this method is not overridden, instead implement onDraw()
+ * to perform the actual drawing.
+ */
+ virtual void draw(const sp<const DisplayDevice>& hw, const Region& clip) const;
+ virtual void draw(const sp<const DisplayDevice>& hw);
+
+ /*
+ * onDraw - draws the surface.
+ */
virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const;
+
+ /*
+ * needsLinearFiltering - true if this surface's state requires filtering
+ */
+ virtual bool needsFiltering(const sp<const DisplayDevice>& hw) const;
+
+ /*
+ * doTransaction - process the transaction. This is a good place to figure
+ * out which attributes of the surface have changed.
+ */
virtual uint32_t doTransaction(uint32_t transactionFlags);
+
+ /*
+ * setVisibleRegion - called to set the new visible region. This gives
+ * a chance to update the new visible region or record the fact it changed.
+ */
+ virtual void setVisibleRegion(const Region& visibleRegion);
+
+ /*
+ * setCoveredRegion - called when the covered region changes. The covered
+ * region corresponds to any area of the surface that is covered
+ * (transparently or not) by another surface.
+ */
+ virtual void setCoveredRegion(const Region& coveredRegion);
+
+ /*
+ * setVisibleNonTransparentRegion - called when the visible and
+ * non-transparent region changes.
+ */
+ virtual void setVisibleNonTransparentRegion(const Region&
+ visibleNonTransparentRegion);
+
+ /*
+ * latchBuffer - called each time the screen is redrawn and returns whether
+ * the visible regions need to be recomputed (this is a fairly heavy
+ * operation, so this should be set only if needed). Typically this is used
+ * to figure out if the content or size of a surface has changed.
+ */
virtual Region latchBuffer(bool& recomputeVisibleRegions);
+
+ /*
+ * isOpaque - true if this surface is opaque
+ */
virtual bool isOpaque() const;
+
+ /*
+ * isSecure - true if this surface is secure, that is if it prevents
+ * screenshots or VNC servers.
+ */
virtual bool isSecure() const { return mSecure; }
+
+ /*
+ * isProtected - true if the layer may contain protected content in the
+ * GRALLOC_USAGE_PROTECTED sense.
+ */
virtual bool isProtected() const;
- virtual void onRemoved();
- virtual sp<Layer> getLayer() const { return const_cast<Layer*>(this); }
- virtual void setName(const String8& name);
+
+ /*
+ * isVisible - true if this layer is visible, false otherwise
+ */
virtual bool isVisible() const;
- // LayerBaseClient interface
- virtual wp<IBinder> getSurfaceTextureBinder() const;
+ /*
+ * isFixedSize - true if content has a fixed size
+ */
+ virtual bool isFixedSize() const;
- // only for debugging
- inline const sp<GraphicBuffer>& getActiveBuffer() const { return mActiveBuffer; }
+ /*
+ * called with the state lock when the surface is removed from the
+ * current list
+ */
+ virtual void onRemoved();
+
// Updates the transform hint in our SurfaceFlingerConsumer to match
// the current orientation of the display device.
virtual void updateTransformHint(const sp<const DisplayDevice>& hw) const;
-protected:
- virtual void onFirstRef();
+ /*
+ * returns the rectangle that crops the content of the layer and scales it
+ * to the layer's size.
+ */
+ virtual Rect getContentCrop() const;
+
+ /*
+ * returns the transform bits (90 rotation / h-flip / v-flip) of the
+ * layer's content
+ */
+ virtual uint32_t getContentTransform() const;
+
+ // -----------------------------------------------------------------------
+
+ void clearWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip) const;
+ void setFiltering(bool filtering);
+ bool getFiltering() const;
+
+ // only for debugging
+ inline const sp<GraphicBuffer>& getActiveBuffer() const { return mActiveBuffer; }
+
+ inline const State& drawingState() const { return mDrawingState; }
+ inline const State& currentState() const { return mCurrentState; }
+ inline State& currentState() { return mCurrentState; }
+
+
+ /* always call base class first */
virtual void dump(String8& result, char* scratch, size_t size) const;
+ virtual void shortDump(String8& result, char* scratch, size_t size) const;
virtual void dumpStats(String8& result, char* buffer, size_t SIZE) const;
virtual void clearStats();
+protected:
+ // constant
+ sp<SurfaceFlinger> mFlinger;
+
+ virtual void onFirstRef();
+
+ /*
+ * Trivial class, used to ensure that mFlinger->onLayerDestroyed(mLayer)
+ * is called.
+ */
+ class LayerCleaner {
+ sp<SurfaceFlinger> mFlinger;
+ wp<Layer> mLayer;
+ protected:
+ ~LayerCleaner();
+ public:
+ LayerCleaner(const sp<SurfaceFlinger>& flinger, const sp<Layer>& layer);
+ };
+
+
private:
- // Creates an instance of ISurface for this Layer.
- virtual sp<ISurface> createSurface();
-
- uint32_t getEffectiveUsage(uint32_t usage) const;
- bool isCropped() const;
- Rect computeBufferCrop() const;
- static bool getOpacityForFormat(uint32_t format);
-
// Interface implementation for SurfaceFlingerConsumer::FrameAvailableListener
virtual void onFrameAvailable();
+
+ uint32_t getEffectiveUsage(uint32_t usage) const;
+ Rect computeCrop(const sp<const DisplayDevice>& hw) const;
+ bool isCropped() const;
+ static bool getOpacityForFormat(uint32_t format);
+
+ // drawing
+ void clearWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip,
+ GLclampf r, GLclampf g, GLclampf b, GLclampf alpha) const;
+ void drawWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip) const;
+
+
// -----------------------------------------------------------------------
// constants
sp<SurfaceFlingerConsumer> mSurfaceFlingerConsumer;
GLuint mTextureName;
+ bool mPremultipliedAlpha;
+ String8 mName;
+ mutable bool mDebug;
+ PixelFormat mFormat;
+ const GLExtensions& mGLExtensions;
+ bool mOpaqueLayer;
+
+ // these are protected by an external lock
+ State mCurrentState;
+ State mDrawingState;
+ volatile int32_t mTransactionFlags;
// thread-safe
volatile int32_t mQueuedFrames;
@@ -139,15 +370,20 @@
bool mCurrentOpacity;
bool mRefreshPending;
bool mFrameLatencyNeeded;
-
- // constants
- PixelFormat mFormat;
- const GLExtensions& mGLExtensions;
- bool mOpaqueLayer;
+ // Whether filtering is forced on or not
+ bool mFiltering;
+ // Whether filtering is needed b/c of the drawingstate
+ bool mNeedsFiltering;
// page-flip thread (currently main thread)
- bool mSecure; // no screenshots
+ bool mSecure; // no screenshots
bool mProtectedByApp; // application requires protected path to external sink
+
+ // protected by mLock
+ mutable Mutex mLock;
+ // Set to true once we've returned this surface's handle
+ mutable bool mHasSurface;
+ const wp<Client> mClientRef;
};
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
deleted file mode 100644
index dfdbf30..0000000
--- a/services/surfaceflinger/LayerBase.cpp
+++ /dev/null
@@ -1,565 +0,0 @@
-/*
- * Copyright (C) 2007 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 <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-
-#include <GLES/gl.h>
-#include <GLES/glext.h>
-
-#include <hardware/hardware.h>
-
-#include "clz.h"
-#include "Client.h"
-#include "LayerBase.h"
-#include "Layer.h"
-#include "SurfaceFlinger.h"
-#include "DisplayDevice.h"
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-int32_t LayerBase::sSequence = 1;
-
-LayerBase::LayerBase(SurfaceFlinger* flinger)
- : contentDirty(false),
- sequence(uint32_t(android_atomic_inc(&sSequence))),
- mFlinger(flinger), mFiltering(false),
- mNeedsFiltering(false),
- mTransactionFlags(0),
- mPremultipliedAlpha(true), mName("unnamed"), mDebug(false)
-{
-}
-
-LayerBase::~LayerBase()
-{
-}
-
-void LayerBase::setName(const String8& name) {
- mName = name;
-}
-
-String8 LayerBase::getName() const {
- return mName;
-}
-
-void LayerBase::initStates(uint32_t w, uint32_t h, uint32_t flags)
-{
- uint32_t layerFlags = 0;
- if (flags & ISurfaceComposerClient::eHidden)
- layerFlags = layer_state_t::eLayerHidden;
-
- if (flags & ISurfaceComposerClient::eNonPremultiplied)
- mPremultipliedAlpha = false;
-
- mCurrentState.active.w = w;
- mCurrentState.active.h = h;
- mCurrentState.active.crop.makeInvalid();
- mCurrentState.z = 0;
- mCurrentState.alpha = 0xFF;
- mCurrentState.layerStack = 0;
- mCurrentState.flags = layerFlags;
- mCurrentState.sequence = 0;
- mCurrentState.transform.set(0, 0);
- mCurrentState.requested = mCurrentState.active;
-
- // drawing state & current state are identical
- mDrawingState = mCurrentState;
-}
-
-bool LayerBase::needsFiltering(const sp<const DisplayDevice>& hw) const {
- return mNeedsFiltering || hw->needsFiltering();
-}
-
-void LayerBase::commitTransaction() {
- mDrawingState = mCurrentState;
-}
-void LayerBase::forceVisibilityTransaction() {
- // this can be called without SurfaceFlinger.mStateLock, but if we
- // can atomically increment the sequence number, it doesn't matter.
- android_atomic_inc(&mCurrentState.sequence);
- requestTransaction();
-}
-bool LayerBase::requestTransaction() {
- int32_t old = setTransactionFlags(eTransactionNeeded);
- return ((old & eTransactionNeeded) == 0);
-}
-uint32_t LayerBase::getTransactionFlags(uint32_t flags) {
- return android_atomic_and(~flags, &mTransactionFlags) & flags;
-}
-uint32_t LayerBase::setTransactionFlags(uint32_t flags) {
- return android_atomic_or(flags, &mTransactionFlags);
-}
-
-bool LayerBase::setPosition(float x, float y) {
- if (mCurrentState.transform.tx() == x && mCurrentState.transform.ty() == y)
- return false;
- mCurrentState.sequence++;
- mCurrentState.transform.set(x, y);
- requestTransaction();
- return true;
-}
-bool LayerBase::setLayer(uint32_t z) {
- if (mCurrentState.z == z)
- return false;
- mCurrentState.sequence++;
- mCurrentState.z = z;
- requestTransaction();
- return true;
-}
-bool LayerBase::setSize(uint32_t w, uint32_t h) {
- if (mCurrentState.requested.w == w && mCurrentState.requested.h == h)
- return false;
- mCurrentState.requested.w = w;
- mCurrentState.requested.h = h;
- requestTransaction();
- return true;
-}
-bool LayerBase::setAlpha(uint8_t alpha) {
- if (mCurrentState.alpha == alpha)
- return false;
- mCurrentState.sequence++;
- mCurrentState.alpha = alpha;
- requestTransaction();
- return true;
-}
-bool LayerBase::setMatrix(const layer_state_t::matrix22_t& matrix) {
- mCurrentState.sequence++;
- mCurrentState.transform.set(
- matrix.dsdx, matrix.dsdy, matrix.dtdx, matrix.dtdy);
- requestTransaction();
- return true;
-}
-bool LayerBase::setTransparentRegionHint(const Region& transparent) {
- mCurrentState.sequence++;
- mCurrentState.transparentRegion = transparent;
- requestTransaction();
- return true;
-}
-bool LayerBase::setFlags(uint8_t flags, uint8_t mask) {
- const uint32_t newFlags = (mCurrentState.flags & ~mask) | (flags & mask);
- if (mCurrentState.flags == newFlags)
- return false;
- mCurrentState.sequence++;
- mCurrentState.flags = newFlags;
- requestTransaction();
- return true;
-}
-bool LayerBase::setCrop(const Rect& crop) {
- if (mCurrentState.requested.crop == crop)
- return false;
- mCurrentState.sequence++;
- mCurrentState.requested.crop = crop;
- requestTransaction();
- return true;
-}
-
-bool LayerBase::setLayerStack(uint32_t layerStack) {
- if (mCurrentState.layerStack == layerStack)
- return false;
- mCurrentState.sequence++;
- mCurrentState.layerStack = layerStack;
- requestTransaction();
- return true;
-}
-
-void LayerBase::setVisibleRegion(const Region& visibleRegion) {
- // always called from main thread
- this->visibleRegion = visibleRegion;
-}
-
-void LayerBase::setCoveredRegion(const Region& coveredRegion) {
- // always called from main thread
- this->coveredRegion = coveredRegion;
-}
-
-void LayerBase::setVisibleNonTransparentRegion(const Region&
- setVisibleNonTransparentRegion) {
- // always called from main thread
- this->visibleNonTransparentRegion = setVisibleNonTransparentRegion;
-}
-
-uint32_t LayerBase::doTransaction(uint32_t flags)
-{
- const Layer::State& front(drawingState());
- const Layer::State& temp(currentState());
-
- // always set active to requested, unless we're asked not to
- // this is used by Layer, which special cases resizes.
- if (flags & eDontUpdateGeometryState) {
- } else {
- Layer::State& editTemp(currentState());
- editTemp.active = temp.requested;
- }
-
- if (front.active != temp.active) {
- // invalidate and recompute the visible regions if needed
- flags |= Layer::eVisibleRegion;
- }
-
- if (temp.sequence != front.sequence) {
- // invalidate and recompute the visible regions if needed
- flags |= eVisibleRegion;
- this->contentDirty = true;
-
- // we may use linear filtering, if the matrix scales us
- const uint8_t type = temp.transform.getType();
- mNeedsFiltering = (!temp.transform.preserveRects() ||
- (type >= Transform::SCALE));
- }
-
- // Commit the transaction
- commitTransaction();
- return flags;
-}
-
-void LayerBase::computeGeometry(const sp<const DisplayDevice>& hw, LayerMesh* mesh) const
-{
- const Layer::State& s(drawingState());
- const Transform tr(hw->getTransform() * s.transform);
- const uint32_t hw_h = hw->getHeight();
- Rect win(s.active.w, s.active.h);
- if (!s.active.crop.isEmpty()) {
- win.intersect(s.active.crop, &win);
- }
- if (mesh) {
- tr.transform(mesh->mVertices[0], win.left, win.top);
- tr.transform(mesh->mVertices[1], win.left, win.bottom);
- tr.transform(mesh->mVertices[2], win.right, win.bottom);
- tr.transform(mesh->mVertices[3], win.right, win.top);
- for (size_t i=0 ; i<4 ; i++) {
- mesh->mVertices[i][1] = hw_h - mesh->mVertices[i][1];
- }
- }
-}
-
-Rect LayerBase::computeBounds() const {
- const Layer::State& s(drawingState());
- Rect win(s.active.w, s.active.h);
- if (!s.active.crop.isEmpty()) {
- win.intersect(s.active.crop, &win);
- }
- return s.transform.transform(win);
-}
-
-Region LayerBase::latchBuffer(bool& recomputeVisibleRegions) {
- Region result;
- return result;
-}
-
-void LayerBase::setGeometry(
- const sp<const DisplayDevice>& hw,
- HWComposer::HWCLayerInterface& layer)
-{
- layer.setDefaultState();
-
- // this gives us only the "orientation" component of the transform
- const State& s(drawingState());
- const uint32_t finalTransform = s.transform.getOrientation();
- // we can only handle simple transformation
- if (finalTransform & Transform::ROT_INVALID) {
- layer.setTransform(0);
- } else {
- layer.setTransform(finalTransform);
- }
-
- if (!isOpaque() || s.alpha != 0xFF) {
- layer.setBlending(mPremultipliedAlpha ?
- HWC_BLENDING_PREMULT :
- HWC_BLENDING_COVERAGE);
- }
-
- const Transform& tr = hw->getTransform();
- Rect transformedBounds(computeBounds());
- transformedBounds = tr.transform(transformedBounds);
-
- // scaling is already applied in transformedBounds
- layer.setFrame(transformedBounds);
- layer.setCrop(transformedBounds.getBounds());
-}
-
-void LayerBase::setPerFrameData(const sp<const DisplayDevice>& hw,
- HWComposer::HWCLayerInterface& layer) {
- // we have to set the visible region on every frame because
- // we currently free it during onLayerDisplayed(), which is called
- // after HWComposer::commit() -- every frame.
- const Transform& tr = hw->getTransform();
- layer.setVisibleRegionScreen(tr.transform(visibleRegion));
-}
-
-void LayerBase::setAcquireFence(const sp<const DisplayDevice>& hw,
- HWComposer::HWCLayerInterface& layer) {
- layer.setAcquireFenceFd(-1);
-}
-
-void LayerBase::onLayerDisplayed(const sp<const DisplayDevice>& hw,
- HWComposer::HWCLayerInterface* layer) {
- if (layer) {
- layer->onDisplayed();
- }
-}
-
-void LayerBase::setFiltering(bool filtering)
-{
- mFiltering = filtering;
-}
-
-bool LayerBase::getFiltering() const
-{
- return mFiltering;
-}
-
-bool LayerBase::isVisible() const {
- const Layer::State& s(mDrawingState);
- return !(s.flags & layer_state_t::eLayerHidden) && s.alpha;
-}
-
-void LayerBase::draw(const sp<const DisplayDevice>& hw, const Region& clip) const
-{
- onDraw(hw, clip);
-}
-
-void LayerBase::draw(const sp<const DisplayDevice>& hw)
-{
- onDraw( hw, Region(hw->bounds()) );
-}
-
-void LayerBase::clearWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip,
- GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) const
-{
- const uint32_t fbHeight = hw->getHeight();
- glColor4f(red,green,blue,alpha);
-
- glDisable(GL_TEXTURE_EXTERNAL_OES);
- glDisable(GL_TEXTURE_2D);
- glDisable(GL_BLEND);
-
- LayerMesh mesh;
- computeGeometry(hw, &mesh);
-
- glVertexPointer(2, GL_FLOAT, 0, mesh.getVertices());
- glDrawArrays(GL_TRIANGLE_FAN, 0, mesh.getVertexCount());
-}
-
-void LayerBase::clearWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip) const
-{
- clearWithOpenGL(hw, clip, 0,0,0,0);
-}
-
-void LayerBase::drawWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip) const
-{
- const uint32_t fbHeight = hw->getHeight();
- const State& s(drawingState());
-
- GLenum src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
- if (CC_UNLIKELY(s.alpha < 0xFF)) {
- const GLfloat alpha = s.alpha * (1.0f/255.0f);
- if (mPremultipliedAlpha) {
- glColor4f(alpha, alpha, alpha, alpha);
- } else {
- glColor4f(1, 1, 1, alpha);
- }
- glEnable(GL_BLEND);
- glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);
- glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
- } else {
- glColor4f(1, 1, 1, 1);
- glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
- if (!isOpaque()) {
- glEnable(GL_BLEND);
- glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);
- } else {
- glDisable(GL_BLEND);
- }
- }
-
- LayerMesh mesh;
- computeGeometry(hw, &mesh);
-
- // TODO: we probably want to generate the texture coords with the mesh
- // here we assume that we only have 4 vertices
-
- struct TexCoords {
- GLfloat u;
- GLfloat v;
- };
-
- Rect win(s.active.w, s.active.h);
- if (!s.active.crop.isEmpty()) {
- win.intersect(s.active.crop, &win);
- }
-
- GLfloat left = GLfloat(win.left) / GLfloat(s.active.w);
- GLfloat top = GLfloat(win.top) / GLfloat(s.active.h);
- GLfloat right = GLfloat(win.right) / GLfloat(s.active.w);
- GLfloat bottom = GLfloat(win.bottom) / GLfloat(s.active.h);
-
- TexCoords texCoords[4];
- texCoords[0].u = left;
- texCoords[0].v = top;
- texCoords[1].u = left;
- texCoords[1].v = bottom;
- texCoords[2].u = right;
- texCoords[2].v = bottom;
- texCoords[3].u = right;
- texCoords[3].v = top;
- for (int i = 0; i < 4; i++) {
- texCoords[i].v = 1.0f - texCoords[i].v;
- }
-
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
- glVertexPointer(2, GL_FLOAT, 0, mesh.getVertices());
- glDrawArrays(GL_TRIANGLE_FAN, 0, mesh.getVertexCount());
-
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- glDisable(GL_BLEND);
-}
-
-void LayerBase::dump(String8& result, char* buffer, size_t SIZE) const
-{
- const Layer::State& s(drawingState());
-
- snprintf(buffer, SIZE,
- "+ %s %p (%s)\n",
- getTypeId(), this, getName().string());
- result.append(buffer);
-
- s.transparentRegion.dump(result, "transparentRegion");
- visibleRegion.dump(result, "visibleRegion");
-
- snprintf(buffer, SIZE,
- " "
- "layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), crop=(%4d,%4d,%4d,%4d), "
- "isOpaque=%1d, needsDithering=%1d, invalidate=%1d, "
- "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n",
- s.layerStack, s.z, s.transform.tx(), s.transform.ty(), s.active.w, s.active.h,
- s.active.crop.left, s.active.crop.top,
- s.active.crop.right, s.active.crop.bottom,
- isOpaque(), needsDithering(), contentDirty,
- s.alpha, s.flags,
- s.transform[0][0], s.transform[0][1],
- s.transform[1][0], s.transform[1][1]);
- result.append(buffer);
-}
-
-void LayerBase::shortDump(String8& result, char* scratch, size_t size) const {
- LayerBase::dump(result, scratch, size);
-}
-
-void LayerBase::dumpStats(String8& result, char* scratch, size_t SIZE) const {
-}
-
-void LayerBase::clearStats() {
-}
-
-sp<LayerBaseClient> LayerBase::getLayerBaseClient() const {
- return 0;
-}
-
-sp<Layer> LayerBase::getLayer() const {
- return 0;
-}
-
-// ---------------------------------------------------------------------------
-
-LayerBaseClient::LayerBaseClient(SurfaceFlinger* flinger,
- const sp<Client>& client)
- : LayerBase(flinger),
- mHasSurface(false),
- mClientRef(client)
-{
-}
-
-LayerBaseClient::~LayerBaseClient()
-{
- sp<Client> c(mClientRef.promote());
- if (c != 0) {
- c->detachLayer(this);
- }
-}
-
-sp<ISurface> LayerBaseClient::createSurface()
-{
- class BSurface : public BnSurface, public LayerCleaner {
- virtual sp<IGraphicBufferProducer> getSurfaceTexture() const { return 0; }
- public:
- BSurface(const sp<SurfaceFlinger>& flinger,
- const sp<LayerBaseClient>& layer)
- : LayerCleaner(flinger, layer) { }
- };
- sp<ISurface> sur(new BSurface(mFlinger, this));
- return sur;
-}
-
-sp<ISurface> LayerBaseClient::getSurface()
-{
- sp<ISurface> s;
- Mutex::Autolock _l(mLock);
-
- LOG_ALWAYS_FATAL_IF(mHasSurface,
- "LayerBaseClient::getSurface() has already been called");
-
- mHasSurface = true;
- s = createSurface();
- mClientSurfaceBinder = s->asBinder();
- return s;
-}
-
-wp<IBinder> LayerBaseClient::getSurfaceBinder() const {
- return mClientSurfaceBinder;
-}
-
-wp<IBinder> LayerBaseClient::getSurfaceTextureBinder() const {
- return 0;
-}
-
-void LayerBaseClient::dump(String8& result, char* buffer, size_t SIZE) const
-{
- LayerBase::dump(result, buffer, SIZE);
- sp<Client> client(mClientRef.promote());
- snprintf(buffer, SIZE, " client=%p\n", client.get());
- result.append(buffer);
-}
-
-
-void LayerBaseClient::shortDump(String8& result, char* scratch, size_t size) const
-{
- LayerBaseClient::dump(result, scratch, size);
-}
-
-// ---------------------------------------------------------------------------
-
-LayerBaseClient::LayerCleaner::LayerCleaner(const sp<SurfaceFlinger>& flinger,
- const sp<LayerBaseClient>& layer)
- : mFlinger(flinger), mLayer(layer) {
-}
-
-LayerBaseClient::LayerCleaner::~LayerCleaner() {
- // destroy client resources
- mFlinger->onLayerDestroyed(mLayer);
-}
-
-// ---------------------------------------------------------------------------
-
-}; // namespace android
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
deleted file mode 100644
index c2624df..0000000
--- a/services/surfaceflinger/LayerBase.h
+++ /dev/null
@@ -1,386 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-#ifndef ANDROID_LAYER_BASE_H
-#define ANDROID_LAYER_BASE_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-#include <GLES/gl.h>
-
-#include <utils/RefBase.h>
-#include <utils/String8.h>
-
-#include <ui/Region.h>
-
-#include <gui/ISurfaceComposerClient.h>
-
-#include <private/gui/LayerState.h>
-
-#include "Transform.h"
-#include "DisplayHardware/HWComposer.h"
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-class Client;
-class DisplayDevice;
-class GraphicBuffer;
-class Layer;
-class LayerBaseClient;
-class SurfaceFlinger;
-
-// ---------------------------------------------------------------------------
-
-/*
- * Layers are rectangular graphic entities, internal to SurfaceFlinger.
- * They have properties including width, height, Z-depth, and 2D
- * transformations (chiefly translation and 90-degree rotations).
- *
- * Layers are organized into "layer stacks". Each layer is a member of
- * exactly one layer stack, identified by an integer in Layer::State. A
- * given layer stack may appear on more than one display.
- *
- * Notable subclasses (below LayerBaseClient) include Layer, LayerDim, and
- * LayerScreenshot.
- */
-class LayerBase : virtual public RefBase
-{
- static int32_t sSequence;
-
-public:
- LayerBase(SurfaceFlinger* flinger);
-
- mutable bool contentDirty;
- // regions below are in window-manager space
- Region visibleRegion;
- Region coveredRegion;
- Region visibleNonTransparentRegion;
- int32_t sequence;
-
- struct Geometry {
- uint32_t w;
- uint32_t h;
- Rect crop;
- inline bool operator == (const Geometry& rhs) const {
- return (w==rhs.w && h==rhs.h && crop==rhs.crop);
- }
- inline bool operator != (const Geometry& rhs) const {
- return !operator == (rhs);
- }
- };
-
- struct State {
- Geometry active;
- Geometry requested;
- uint32_t z;
- uint32_t layerStack;
- uint8_t alpha;
- uint8_t flags;
- uint8_t reserved[2];
- int32_t sequence; // changes when visible regions can change
- Transform transform;
- Region transparentRegion;
- };
-
- class LayerMesh {
- friend class LayerBase;
- GLfloat mVertices[4][2];
- size_t mNumVertices;
- public:
- LayerMesh() : mNumVertices(4) { }
- GLfloat const* getVertices() const {
- return &mVertices[0][0];
- }
- size_t getVertexCount() const {
- return mNumVertices;
- }
- };
-
- virtual void setName(const String8& name);
- String8 getName() const;
-
- // modify current state
- bool setPosition(float x, float y);
- bool setLayer(uint32_t z);
- bool setSize(uint32_t w, uint32_t h);
- bool setAlpha(uint8_t alpha);
- bool setMatrix(const layer_state_t::matrix22_t& matrix);
- bool setTransparentRegionHint(const Region& transparent);
- bool setFlags(uint8_t flags, uint8_t mask);
- bool setCrop(const Rect& crop);
- bool setLayerStack(uint32_t layerStack);
-
- void commitTransaction();
- bool requestTransaction();
- void forceVisibilityTransaction();
-
- uint32_t getTransactionFlags(uint32_t flags);
- uint32_t setTransactionFlags(uint32_t flags);
-
- void computeGeometry(const sp<const DisplayDevice>& hw, LayerMesh* mesh) const;
- Rect computeBounds() const;
-
-
- virtual sp<LayerBaseClient> getLayerBaseClient() const;
- virtual sp<Layer> getLayer() const;
-
- virtual const char* getTypeId() const { return "LayerBase"; }
-
- virtual void setGeometry(const sp<const DisplayDevice>& hw,
- HWComposer::HWCLayerInterface& layer);
- virtual void setPerFrameData(const sp<const DisplayDevice>& hw,
- HWComposer::HWCLayerInterface& layer);
- virtual void setAcquireFence(const sp<const DisplayDevice>& hw,
- HWComposer::HWCLayerInterface& layer);
-
- /**
- * draw - performs some global clipping optimizations
- * and calls onDraw().
- * Typically this method is not overridden, instead implement onDraw()
- * to perform the actual drawing.
- */
- virtual void draw(const sp<const DisplayDevice>& hw, const Region& clip) const;
- virtual void draw(const sp<const DisplayDevice>& hw);
-
- /**
- * onDraw - draws the surface.
- */
- virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const = 0;
-
- /**
- * initStates - called just after construction
- */
- virtual void initStates(uint32_t w, uint32_t h, uint32_t flags);
-
- /**
- * doTransaction - process the transaction. This is a good place to figure
- * out which attributes of the surface have changed.
- */
- virtual uint32_t doTransaction(uint32_t transactionFlags);
-
- /**
- * setVisibleRegion - called to set the new visible region. This gives
- * a chance to update the new visible region or record the fact it changed.
- */
- virtual void setVisibleRegion(const Region& visibleRegion);
-
- /**
- * setCoveredRegion - called when the covered region changes. The covered
- * region corresponds to any area of the surface that is covered
- * (transparently or not) by another surface.
- */
- virtual void setCoveredRegion(const Region& coveredRegion);
-
- /**
- * setVisibleNonTransparentRegion - called when the visible and
- * non-transparent region changes.
- */
- virtual void setVisibleNonTransparentRegion(const Region&
- visibleNonTransparentRegion);
-
- /**
- * latchBuffer - called each time the screen is redrawn and returns whether
- * the visible regions need to be recomputed (this is a fairly heavy
- * operation, so this should be set only if needed). Typically this is used
- * to figure out if the content or size of a surface has changed.
- */
- virtual Region latchBuffer(bool& recomputeVisibleRegions);
-
- /**
- * isOpaque - true if this surface is opaque
- */
- virtual bool isOpaque() const { return true; }
-
- /**
- * needsDithering - true if this surface needs dithering
- */
- virtual bool needsDithering() const { return false; }
-
- /**
- * needsLinearFiltering - true if this surface's state requires filtering
- */
- virtual bool needsFiltering(const sp<const DisplayDevice>& hw) const;
-
- /**
- * isSecure - true if this surface is secure, that is if it prevents
- * screenshots or VNC servers.
- */
- virtual bool isSecure() const { return false; }
-
- /**
- * isProtected - true if the layer may contain protected content in the
- * GRALLOC_USAGE_PROTECTED sense.
- */
- virtual bool isProtected() const { return false; }
-
- /*
- * isVisible - true if this layer is visibile, false otherwise
- */
- virtual bool isVisible() const;
-
- /** called with the state lock when the surface is removed from the
- * current list */
- virtual void onRemoved() { }
-
- /** called after page-flip
- */
- virtual void onLayerDisplayed(const sp<const DisplayDevice>& hw,
- HWComposer::HWCLayerInterface* layer);
-
- /** called before composition.
- * returns true if the layer has pending updates.
- */
- virtual bool onPreComposition() { return false; }
-
- /** called before composition.
- */
- virtual void onPostComposition() { }
-
- /**
- * Updates the GLConsumer's transform hint, for layers that have
- * a GLConsumer.
- */
- virtual void updateTransformHint(const sp<const DisplayDevice>& hw) const { }
-
- /** always call base class first */
- virtual void dump(String8& result, char* scratch, size_t size) const;
- virtual void shortDump(String8& result, char* scratch, size_t size) const;
- virtual void dumpStats(String8& result, char* buffer, size_t SIZE) const;
- virtual void clearStats();
-
-
- enum { // flags for doTransaction()
- eDontUpdateGeometryState = 0x00000001,
- eVisibleRegion = 0x00000002,
- };
-
-
- inline const State& drawingState() const { return mDrawingState; }
- inline const State& currentState() const { return mCurrentState; }
- inline State& currentState() { return mCurrentState; }
-
- void clearWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip) const;
-
- void setFiltering(bool filtering);
- bool getFiltering() const;
-
-protected:
- void clearWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip,
- GLclampf r, GLclampf g, GLclampf b, GLclampf alpha) const;
- void drawWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip) const;
-
- sp<SurfaceFlinger> mFlinger;
-
-private:
- // accessed only in the main thread
- // Whether filtering is forced on or not
- bool mFiltering;
-
- // Whether filtering is needed b/c of the drawingstate
- bool mNeedsFiltering;
-
-protected:
- // these are protected by an external lock
- State mCurrentState;
- State mDrawingState;
- volatile int32_t mTransactionFlags;
-
- // don't change, don't need a lock
- bool mPremultipliedAlpha;
- String8 mName;
- mutable bool mDebug;
-
-
-public:
- // called from class SurfaceFlinger
- virtual ~LayerBase();
-
-private:
- LayerBase(const LayerBase& rhs);
-};
-
-
-// ---------------------------------------------------------------------------
-
-/*
- * This adds some additional fields and methods to support some Binder IPC
- * interactions. In particular, the LayerBaseClient's lifetime can be
- * managed by references to an ISurface object in another process.
- */
-class LayerBaseClient : public LayerBase
-{
-public:
- LayerBaseClient(SurfaceFlinger* flinger, const sp<Client>& client);
-
- virtual ~LayerBaseClient();
-
- // Creates an ISurface associated with this object. This may only be
- // called once (see also getSurfaceBinder()).
- sp<ISurface> getSurface();
-
- // Returns the Binder object for the ISurface associated with
- // this object.
- wp<IBinder> getSurfaceBinder() const;
-
- virtual wp<IBinder> getSurfaceTextureBinder() const;
-
- virtual sp<LayerBaseClient> getLayerBaseClient() const {
- return const_cast<LayerBaseClient*>(this); }
-
- virtual const char* getTypeId() const { return "LayerBaseClient"; }
-
-protected:
- virtual void dump(String8& result, char* scratch, size_t size) const;
- virtual void shortDump(String8& result, char* scratch, size_t size) const;
-
- /*
- * Trivial class, used to ensure that mFlinger->onLayerDestroyed(mLayer)
- * is called.
- */
- class LayerCleaner {
- sp<SurfaceFlinger> mFlinger;
- wp<LayerBaseClient> mLayer;
- protected:
- ~LayerCleaner();
- public:
- LayerCleaner(const sp<SurfaceFlinger>& flinger,
- const sp<LayerBaseClient>& layer);
- };
-
-private:
- virtual sp<ISurface> createSurface();
-
- mutable Mutex mLock;
-
- // Set to true if an ISurface has been associated with this object.
- mutable bool mHasSurface;
-
- // The ISurface's Binder object, set by getSurface().
- wp<IBinder> mClientSurfaceBinder;
-
- const wp<Client> mClientRef;
-};
-
-// ---------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_LAYER_BASE_H
diff --git a/services/surfaceflinger/LayerDim.cpp b/services/surfaceflinger/LayerDim.cpp
index 25caa0a..36bafdb 100644
--- a/services/surfaceflinger/LayerDim.cpp
+++ b/services/surfaceflinger/LayerDim.cpp
@@ -33,13 +33,12 @@
namespace android {
// ---------------------------------------------------------------------------
-LayerDim::LayerDim(SurfaceFlinger* flinger, const sp<Client>& client)
- : LayerBaseClient(flinger, client)
-{
+LayerDim::LayerDim(SurfaceFlinger* flinger, const sp<Client>& client,
+ const String8& name, uint32_t w, uint32_t h, uint32_t flags)
+ : Layer(flinger, client, name, w, h, flags) {
}
-LayerDim::~LayerDim()
-{
+LayerDim::~LayerDim() {
}
void LayerDim::onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const
@@ -71,6 +70,12 @@
}
}
+bool LayerDim::isVisible() const {
+ const Layer::State& s(drawingState());
+ return !(s.flags & layer_state_t::eLayerHidden) && s.alpha;
+}
+
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/surfaceflinger/LayerDim.h b/services/surfaceflinger/LayerDim.h
index 06f312d..e19bf52 100644
--- a/services/surfaceflinger/LayerDim.h
+++ b/services/surfaceflinger/LayerDim.h
@@ -23,16 +23,17 @@
#include <EGL/egl.h>
#include <EGL/eglext.h>
-#include "LayerBase.h"
+#include "Layer.h"
// ---------------------------------------------------------------------------
namespace android {
-class LayerDim : public LayerBaseClient
+class LayerDim : public Layer
{
public:
- LayerDim(SurfaceFlinger* flinger, const sp<Client>& client);
+ LayerDim(SurfaceFlinger* flinger, const sp<Client>& client,
+ const String8& name, uint32_t w, uint32_t h, uint32_t flags);
virtual ~LayerDim();
virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const;
@@ -41,6 +42,9 @@
virtual bool isProtectedByApp() const { return false; }
virtual bool isProtectedByDRM() const { return false; }
virtual const char* getTypeId() const { return "LayerDim"; }
+
+ virtual bool isFixedSize() const { return true; }
+ virtual bool isVisible() const;
};
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/LayerScreenshot.cpp b/services/surfaceflinger/LayerScreenshot.cpp
deleted file mode 100644
index f8009b3..0000000
--- a/services/surfaceflinger/LayerScreenshot.cpp
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * 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 <GLES/gl.h>
-#include <GLES/glext.h>
-
-#include <utils/Errors.h>
-#include <utils/Log.h>
-
-#include <ui/GraphicBuffer.h>
-
-#include "LayerScreenshot.h"
-#include "SurfaceFlinger.h"
-#include "DisplayDevice.h"
-
-
-namespace android {
-// ---------------------------------------------------------------------------
-
-LayerScreenshot::LayerScreenshot(SurfaceFlinger* flinger,
- const sp<Client>& client)
- : LayerBaseClient(flinger, client),
- mTextureName(0), mFlinger(flinger), mIsSecure(false)
-{
-}
-
-LayerScreenshot::~LayerScreenshot()
-{
- if (mTextureName) {
- mFlinger->deleteTextureAsync(mTextureName);
- }
-}
-
-status_t LayerScreenshot::captureLocked(int32_t layerStack) {
- GLfloat u, v;
- status_t result = mFlinger->renderScreenToTextureLocked(layerStack,
- &mTextureName, &u, &v);
- if (result != NO_ERROR) {
- return result;
- }
- initTexture(u, v);
-
- // Currently screenshot always comes from the default display
- mIsSecure = mFlinger->getDefaultDisplayDevice()->getSecureLayerVisible();
-
- 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);
-
- // Currently screenshot always comes from the default display
- mIsSecure = mFlinger->getDefaultDisplayDevice()->getSecureLayerVisible();
-
- 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 & ISurfaceComposerClient::eHidden)) {
- capture();
- }
- if (flags & ISurfaceComposerClient::eSecure) {
- ALOGW("ignoring surface flag eSecure - LayerScreenshot is considered "
- "secure iff it captures the contents of a secure surface.");
- }
-}
-
-uint32_t LayerScreenshot::doTransaction(uint32_t flags)
-{
- const LayerBase::State& draw(drawingState());
- const LayerBase::State& curr(currentState());
-
- if (draw.flags & layer_state_t::eLayerHidden) {
- if (!(curr.flags & layer_state_t::eLayerHidden)) {
- // we're going from hidden to visible
- status_t err = captureLocked(curr.layerStack);
- if (err != NO_ERROR) {
- ALOGW("createScreenshotSurface failed (%s)", strerror(-err));
- }
- }
- } else if (curr.flags & layer_state_t::eLayerHidden) {
- // we're going from visible to hidden
- if (mTextureName) {
- glDeleteTextures(1, &mTextureName);
- mTextureName = 0;
- }
- }
- return LayerBaseClient::doTransaction(flags);
-}
-
-void LayerScreenshot::onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const
-{
- const State& s(drawingState());
- if (s.alpha>0) {
- const GLfloat alpha = s.alpha/255.0f;
- const uint32_t fbHeight = hw->getHeight();
-
- if (s.alpha == 0xFF) {
- glDisable(GL_BLEND);
- glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
- } else {
- glEnable(GL_BLEND);
- glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
- glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
- }
-
- GLuint texName = mTextureName;
- if (isSecure() && !hw->isSecure()) {
- texName = mFlinger->getProtectedTexName();
- }
-
- LayerMesh mesh;
- computeGeometry(hw, &mesh);
-
- glColor4f(alpha, alpha, alpha, alpha);
-
- glDisable(GL_TEXTURE_EXTERNAL_OES);
- glEnable(GL_TEXTURE_2D);
-
- glBindTexture(GL_TEXTURE_2D, texName);
- glMatrixMode(GL_TEXTURE);
- glLoadIdentity();
- glMatrixMode(GL_MODELVIEW);
-
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glTexCoordPointer(2, GL_FLOAT, 0, mTexCoords);
- glVertexPointer(2, GL_FLOAT, 0, mesh.getVertices());
- glDrawArrays(GL_TRIANGLE_FAN, 0, mesh.getVertexCount());
-
- glDisable(GL_BLEND);
- glDisable(GL_TEXTURE_2D);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- }
-}
-
-// ---------------------------------------------------------------------------
-
-}; // namespace android
diff --git a/services/surfaceflinger/LayerScreenshot.h b/services/surfaceflinger/LayerScreenshot.h
deleted file mode 100644
index 38cbd88..0000000
--- a/services/surfaceflinger/LayerScreenshot.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef ANDROID_LAYER_SCREENSHOT_H
-#define ANDROID_LAYER_SCREENSHOT_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-
-#include "LayerBase.h"
-
-// ---------------------------------------------------------------------------
-
-namespace android {
-
-class LayerScreenshot : public LayerBaseClient
-{
- GLuint mTextureName;
- GLfloat mTexCoords[8];
- sp<SurfaceFlinger> mFlinger;
- bool mIsSecure;
-public:
- LayerScreenshot(SurfaceFlinger* flinger, const sp<Client>& client);
- virtual ~LayerScreenshot();
-
- status_t capture();
-
- virtual void initStates(uint32_t w, uint32_t h, uint32_t flags);
- virtual uint32_t doTransaction(uint32_t flags);
- virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const;
- virtual bool isOpaque() const { return false; }
- virtual bool isSecure() const { return mIsSecure; }
- virtual bool isProtectedByApp() const { return false; }
- virtual bool isProtectedByDRM() const { return false; }
- virtual const char* getTypeId() const { return "LayerScreenshot"; }
-
-private:
- status_t captureLocked(int32_t layerStack);
- void initTexture(GLfloat u, GLfloat v);
-};
-
-// ---------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_LAYER_SCREENSHOT_H
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index ee3e93b..8546920 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -62,11 +62,11 @@
#include "GLExtensions.h"
#include "Layer.h"
#include "LayerDim.h"
-#include "LayerScreenshot.h"
#include "SurfaceFlinger.h"
#include "DisplayHardware/FramebufferSurface.h"
#include "DisplayHardware/HWComposer.h"
+#include "DisplayHardware/VirtualDisplaySurface.h"
#define EGL_VERSION_HW_ANDROID 0x3143
@@ -502,11 +502,9 @@
createBuiltinDisplayLocked(type);
wp<IBinder> token = mBuiltinDisplays[i];
- sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, i);
- sp<Surface> stc = new Surface(
- static_cast< sp<IGraphicBufferProducer> >(fbs->getBufferQueue()));
sp<DisplayDevice> hw = new DisplayDevice(this,
- type, isSecure, token, stc, fbs, mEGLConfig);
+ type, isSecure, token, new FramebufferSurface(*mHwc, i),
+ mEGLConfig);
if (i > DisplayDevice::DISPLAY_PRIMARY) {
// FIXME: currently we don't get blank/unblank requests
// for displays other than the main display, so we always
@@ -575,46 +573,7 @@
const sp<IGraphicBufferProducer>& bufferProducer) const {
Mutex::Autolock _l(mStateLock);
sp<IBinder> surfaceTextureBinder(bufferProducer->asBinder());
-
- // We want to determine whether the IGraphicBufferProducer was created by
- // SurfaceFlinger. Check to see if we can find it in the layer list.
- const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
- size_t count = currentLayers.size();
- for (size_t i=0 ; i<count ; i++) {
- const sp<LayerBase>& layer(currentLayers[i]);
- sp<LayerBaseClient> lbc(layer->getLayerBaseClient());
- if (lbc != NULL) {
- // If this is an instance of Layer (as opposed to, say, LayerDim),
- // we will get the consumer interface of SurfaceFlingerConsumer's
- // BufferQueue. If it's the same Binder object as the graphic
- // buffer producer interface, return success.
- wp<IBinder> lbcBinder = lbc->getSurfaceTextureBinder();
- if (lbcBinder == surfaceTextureBinder) {
- return true;
- }
- }
- }
-
- // Check the layers in the purgatory. This check is here so that if a
- // GLConsumer gets destroyed before all the clients are done using it,
- // the error will not be reported as "surface XYZ is not authenticated", but
- // will instead fail later on when the client tries to use the surface,
- // which should be reported as "surface XYZ returned an -ENODEV". The
- // purgatorized layers are no less authentic than the visible ones, so this
- // should not cause any harm.
- size_t purgatorySize = mLayerPurgatory.size();
- for (size_t i=0 ; i<purgatorySize ; i++) {
- const sp<LayerBase>& layer(mLayerPurgatory.itemAt(i));
- sp<LayerBaseClient> lbc(layer->getLayerBaseClient());
- if (lbc != NULL) {
- wp<IBinder> lbcBinder = lbc->getSurfaceTextureBinder();
- if (lbcBinder == surfaceTextureBinder) {
- return true;
- }
- }
- }
-
- return false;
+ return mGraphicBufferProducerList.indexOf(surfaceTextureBinder) >= 0;
}
status_t SurfaceFlinger::getDisplayInfo(const sp<IBinder>& display, DisplayInfo* info) {
@@ -915,7 +874,7 @@
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
Region opaqueRegion;
Region dirtyRegion;
- Vector< sp<LayerBase> > layersSortedByZ;
+ Vector< sp<Layer> > layersSortedByZ;
const sp<DisplayDevice>& hw(mDisplays[dpy]);
const Transform& tr(hw->getTransform());
const Rect bounds(hw->getBounds());
@@ -925,7 +884,7 @@
const size_t count = currentLayers.size();
for (size_t i=0 ; i<count ; i++) {
- const sp<LayerBase>& layer(currentLayers[i]);
+ const sp<Layer>& layer(currentLayers[i]);
const Layer::State& s(layer->drawingState());
if (s.layerStack == hw->getLayerStack()) {
Region drawRegion(tr.transform(
@@ -955,14 +914,14 @@
sp<const DisplayDevice> hw(mDisplays[dpy]);
const int32_t id = hw->getHwcDisplayId();
if (id >= 0) {
- const Vector< sp<LayerBase> >& currentLayers(
+ const Vector< sp<Layer> >& currentLayers(
hw->getVisibleLayersSortedByZ());
const size_t count = currentLayers.size();
if (hwc.createWorkList(id, count) == NO_ERROR) {
HWComposer::LayerListIterator cur = hwc.begin(id);
const HWComposer::LayerListIterator end = hwc.end(id);
for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
- const sp<LayerBase>& layer(currentLayers[i]);
+ const sp<Layer>& layer(currentLayers[i]);
layer->setGeometry(hw, *cur);
if (mDebugDisableHWC || mDebugRegion) {
cur->setSkip(true);
@@ -978,7 +937,7 @@
sp<const DisplayDevice> hw(mDisplays[dpy]);
const int32_t id = hw->getHwcDisplayId();
if (id >= 0) {
- const Vector< sp<LayerBase> >& currentLayers(
+ const Vector< sp<Layer> >& currentLayers(
hw->getVisibleLayersSortedByZ());
const size_t count = currentLayers.size();
HWComposer::LayerListIterator cur = hwc.begin(id);
@@ -988,7 +947,7 @@
* update the per-frame h/w composer data for each layer
* and build the transparent region of the FB
*/
- const sp<LayerBase>& layer(currentLayers[i]);
+ const sp<Layer>& layer(currentLayers[i]);
layer->setPerFrameData(hw, *cur);
}
}
@@ -1042,7 +1001,7 @@
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
sp<const DisplayDevice> hw(mDisplays[dpy]);
- const Vector< sp<LayerBase> >& currentLayers(hw->getVisibleLayersSortedByZ());
+ const Vector< sp<Layer> >& currentLayers(hw->getVisibleLayersSortedByZ());
hw->onSwapBuffersCompleted(hwc);
const size_t count = currentLayers.size();
int32_t id = hw->getHwcDisplayId();
@@ -1098,7 +1057,7 @@
if (transactionFlags & eTraversalNeeded) {
for (size_t i=0 ; i<count ; i++) {
- const sp<LayerBase>& layer(currentLayers[i]);
+ const sp<Layer>& layer(currentLayers[i]);
uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
if (!trFlags) continue;
@@ -1139,7 +1098,8 @@
DisplayDevice::makeCurrent(mEGLDisplay, hw, mEGLContext);
mDisplays.removeItem(draw.keyAt(i));
getHwComposer().disconnectDisplay(draw[i].type);
- mEventThread->onHotplugReceived(draw[i].type, false);
+ if (draw[i].type < DisplayDevice::NUM_DISPLAY_TYPES)
+ mEventThread->onHotplugReceived(draw[i].type, false);
} else {
ALOGW("trying to remove the main display");
}
@@ -1181,10 +1141,14 @@
if (draw.indexOfKey(curr.keyAt(i)) < 0) {
const DisplayDeviceState& state(curr[i]);
- sp<FramebufferSurface> fbs;
- sp<Surface> stc;
- if (!state.isVirtualDisplay()) {
-
+ sp<DisplaySurface> dispSurface;
+ if (state.isVirtualDisplay()) {
+ if (state.surface != NULL) {
+ dispSurface = new VirtualDisplaySurface(
+ *mHwc, state.type, state.surface,
+ state.displayName);
+ }
+ } else {
ALOGE_IF(state.surface!=NULL,
"adding a supported display, but rendering "
"surface is provided (%p), ignoring it",
@@ -1192,27 +1156,21 @@
// for supported (by hwc) displays we provide our
// own rendering surface
- fbs = new FramebufferSurface(*mHwc, state.type);
- stc = new Surface(
- static_cast< sp<IGraphicBufferProducer> >(
- fbs->getBufferQueue()));
- } else {
- if (state.surface != NULL) {
- stc = new Surface(state.surface);
- }
+ dispSurface = new FramebufferSurface(*mHwc, state.type);
}
const wp<IBinder>& display(curr.keyAt(i));
- if (stc != NULL) {
+ if (dispSurface != NULL) {
sp<DisplayDevice> hw = new DisplayDevice(this,
- state.type, state.isSecure, display, stc, fbs,
- mEGLConfig);
+ state.type, state.isSecure, display,
+ dispSurface, mEGLConfig);
hw->setLayerStack(state.layerStack);
hw->setProjection(state.orientation,
state.viewport, state.frame);
hw->setDisplayName(state.displayName);
mDisplays.add(display, hw);
- mEventThread->onHotplugReceived(state.type, true);
+ if (state.type < DisplayDevice::NUM_DISPLAY_TYPES)
+ mEventThread->onHotplugReceived(state.type, true);
}
}
}
@@ -1245,8 +1203,8 @@
// NOTE: we rely on the fact that layers are sorted by
// layerStack first (so we don't have to traverse the list
// of displays for every layer).
- const sp<LayerBase>& layerBase(currentLayers[i]);
- uint32_t layerStack = layerBase->drawingState().layerStack;
+ const sp<Layer>& layer(currentLayers[i]);
+ uint32_t layerStack = layer->drawingState().layerStack;
if (i==0 || currentlayerStack != layerStack) {
currentlayerStack = layerStack;
// figure out if this layerstack is mirrored
@@ -1268,7 +1226,7 @@
if (disp != NULL) {
// presumably this means this layer is using a layerStack
// that is not visible on any display
- layerBase->updateTransformHint(disp);
+ layer->updateTransformHint(disp);
}
}
}
@@ -1291,7 +1249,7 @@
mVisibleRegionsDirty = true;
const size_t count = previousLayers.size();
for (size_t i=0 ; i<count ; i++) {
- const sp<LayerBase>& layer(previousLayers[i]);
+ const sp<Layer>& layer(previousLayers[i]);
if (currentLayers.indexOf(layer) < 0) {
// this layer is not visible anymore
// TODO: we could traverse the tree from front to back and
@@ -1342,12 +1300,12 @@
size_t i = currentLayers.size();
while (i--) {
- const sp<LayerBase>& layer = currentLayers[i];
+ const sp<Layer>& layer = currentLayers[i];
// start with the whole surface at its current location
const Layer::State& s(layer->drawingState());
- // only consider the layers on the given later stack
+ // only consider the layers on the given layer stack
if (s.layerStack != layerStack)
continue;
@@ -1384,7 +1342,7 @@
// handle hidden surfaces by setting the visible region to empty
if (CC_LIKELY(layer->isVisible())) {
const bool translucent = !layer->isOpaque();
- Rect bounds(layer->computeBounds());
+ Rect bounds(s.transform.transform(layer->computeBounds()));
visibleRegion.set(bounds);
if (!visibleRegion.isEmpty()) {
// Remove the transparent area from the visible region
@@ -1485,7 +1443,7 @@
const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
const size_t count = currentLayers.size();
for (size_t i=0 ; i<count ; i++) {
- const sp<LayerBase>& layer(currentLayers[i]);
+ const sp<Layer>& layer(currentLayers[i]);
const Region dirty(layer->latchBuffer(visibleRegions));
const Layer::State& s(layer->drawingState());
invalidateLayerStack(s.layerStack, dirty);
@@ -1607,13 +1565,13 @@
* and then, render the layers targeted at the framebuffer
*/
- const Vector< sp<LayerBase> >& layers(hw->getVisibleLayersSortedByZ());
+ const Vector< sp<Layer> >& layers(hw->getVisibleLayersSortedByZ());
const size_t count = layers.size();
const Transform& tr = hw->getTransform();
if (cur != end) {
// we're using h/w composer
for (size_t i=0 ; i<count && cur!=end ; ++i, ++cur) {
- const sp<LayerBase>& layer(layers[i]);
+ const sp<Layer>& layer(layers[i]);
const Region clip(dirty.intersect(tr.transform(layer->visibleRegion)));
if (!clip.isEmpty()) {
switch (cur->getCompositionType()) {
@@ -1645,7 +1603,7 @@
} else {
// we're not using h/w composer
for (size_t i=0 ; i<count ; ++i) {
- const sp<LayerBase>& layer(layers[i]);
+ const sp<Layer>& layer(layers[i]);
const Region clip(dirty.intersect(
tr.transform(layer->visibleRegion)));
if (!clip.isEmpty()) {
@@ -1684,7 +1642,8 @@
void SurfaceFlinger::addClientLayer(const sp<Client>& client,
const sp<IBinder>& handle,
- const sp<LayerBaseClient>& lbc)
+ const sp<IGraphicBufferProducer>& gbc,
+ const sp<Layer>& lbc)
{
// attach this layer to the client
client->attachLayer(handle, lbc);
@@ -1692,45 +1651,22 @@
// add this layer to the current state list
Mutex::Autolock _l(mStateLock);
mCurrentState.layersSortedByZ.add(lbc);
+ mGraphicBufferProducerList.add(gbc->asBinder());
}
-status_t SurfaceFlinger::removeLayer(const sp<LayerBase>& layer)
+status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer)
{
Mutex::Autolock _l(mStateLock);
- status_t err = purgatorizeLayer_l(layer);
- if (err == NO_ERROR)
- setTransactionFlags(eTransactionNeeded);
- return err;
-}
-
-status_t SurfaceFlinger::removeLayer_l(const sp<LayerBase>& layerBase)
-{
- ssize_t index = mCurrentState.layersSortedByZ.remove(layerBase);
+ ssize_t index = mCurrentState.layersSortedByZ.remove(layer);
if (index >= 0) {
+ mLayersPendingRemoval.push(layer);
mLayersRemoved = true;
+ setTransactionFlags(eTransactionNeeded);
return NO_ERROR;
}
return status_t(index);
}
-status_t SurfaceFlinger::purgatorizeLayer_l(const sp<LayerBase>& layerBase)
-{
- // First add the layer to the purgatory list, which makes sure it won't
- // go away, then remove it from the main list (through a transaction).
- ssize_t err = removeLayer_l(layerBase);
- if (err >= 0) {
- mLayerPurgatory.add(layerBase);
- }
-
- mLayersPendingRemoval.push(layerBase);
-
- // it's possible that we don't find a layer, because it might
- // have been destroyed already -- this is not technically an error
- // from the user because there is a race between Client::destroySurface(),
- // ~Client() and ~ISurface().
- return (err == NAME_NOT_FOUND) ? status_t(NO_ERROR) : err;
-}
-
uint32_t SurfaceFlinger::peekTransactionFlags(uint32_t flags)
{
return android_atomic_release_load(&mTransactionFlags);
@@ -1873,7 +1809,7 @@
const layer_state_t& s)
{
uint32_t flags = 0;
- sp<LayerBaseClient> layer(client->getLayerUser(s.surface));
+ sp<Layer> layer(client->getLayerUser(s.surface));
if (layer != 0) {
const uint32_t what = s.what;
if (what & layer_state_t::ePositionChanged) {
@@ -1931,52 +1867,49 @@
return flags;
}
-sp<ISurface> SurfaceFlinger::createLayer(
+status_t SurfaceFlinger::createLayer(
const String8& name,
const sp<Client>& client,
- uint32_t w, uint32_t h, PixelFormat format,
- uint32_t flags)
+ uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
+ sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp)
{
- sp<LayerBaseClient> layer;
- sp<ISurface> surfaceHandle;
-
+ //ALOGD("createLayer for (%d x %d), name=%s", w, h, name.string());
if (int32_t(w|h) < 0) {
ALOGE("createLayer() failed, w or h is negative (w=%d, h=%d)",
int(w), int(h));
- return surfaceHandle;
+ return BAD_VALUE;
}
- //ALOGD("createLayer for (%d x %d), name=%s", w, h, name.string());
+ status_t result = NO_ERROR;
+
+ sp<Layer> layer;
+
switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
case ISurfaceComposerClient::eFXSurfaceNormal:
- layer = createNormalLayer(client, w, h, flags, format);
+ result = createNormalLayer(client,
+ name, w, h, flags, format,
+ handle, gbp, &layer);
break;
- case ISurfaceComposerClient::eFXSurfaceBlur:
case ISurfaceComposerClient::eFXSurfaceDim:
- layer = createDimLayer(client, w, h, flags);
+ result = createDimLayer(client,
+ name, w, h, flags,
+ handle, gbp, &layer);
break;
- case ISurfaceComposerClient::eFXSurfaceScreenshot:
- layer = createScreenshotLayer(client, w, h, flags);
+ default:
+ result = BAD_VALUE;
break;
}
- if (layer != 0) {
- layer->initStates(w, h, flags);
- layer->setName(name);
- surfaceHandle = layer->getSurface();
- if (surfaceHandle != 0) {
- addClientLayer(client, surfaceHandle->asBinder(), layer);
- }
+ if (result == NO_ERROR) {
+ addClientLayer(client, *handle, *gbp, layer);
setTransactionFlags(eTransactionNeeded);
}
-
- return surfaceHandle;
+ return result;
}
-sp<Layer> SurfaceFlinger::createNormalLayer(
- const sp<Client>& client,
- uint32_t w, uint32_t h, uint32_t flags,
- PixelFormat& format)
+status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client,
+ const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
+ sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
{
// initialize the surfaces
switch (format) {
@@ -1998,71 +1931,48 @@
format = PIXEL_FORMAT_RGBA_8888;
#endif
- sp<Layer> layer = new Layer(this, client);
- status_t err = layer->setBuffers(w, h, format, flags);
- if (CC_LIKELY(err != NO_ERROR)) {
- ALOGE("createNormalLayer() failed (%s)", strerror(-err));
- layer.clear();
+ *outLayer = new Layer(this, client, name, w, h, flags);
+ status_t err = (*outLayer)->setBuffers(w, h, format, flags);
+ if (err == NO_ERROR) {
+ *handle = (*outLayer)->getHandle();
+ *gbp = (*outLayer)->getBufferQueue();
}
- return layer;
+
+ ALOGE_IF(err, "createNormalLayer() failed (%s)", strerror(-err));
+ return err;
}
-sp<LayerDim> SurfaceFlinger::createDimLayer(
- const sp<Client>& client,
- uint32_t w, uint32_t h, uint32_t flags)
+status_t SurfaceFlinger::createDimLayer(const sp<Client>& client,
+ const String8& name, uint32_t w, uint32_t h, uint32_t flags,
+ sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
{
- sp<LayerDim> layer = new LayerDim(this, client);
- return layer;
-}
-
-sp<LayerScreenshot> SurfaceFlinger::createScreenshotLayer(
- const sp<Client>& client,
- uint32_t w, uint32_t h, uint32_t flags)
-{
- sp<LayerScreenshot> layer = new LayerScreenshot(this, client);
- return layer;
+ *outLayer = new LayerDim(this, client, name, w, h, flags);
+ *handle = (*outLayer)->getHandle();
+ *gbp = (*outLayer)->getBufferQueue();
+ return NO_ERROR;
}
status_t SurfaceFlinger::onLayerRemoved(const sp<Client>& client, const sp<IBinder>& handle)
{
- /*
- * called by the window manager, when a surface should be marked for
- * destruction.
- *
- * The surface is removed from the current and drawing lists, but placed
- * in the purgatory queue, so it's not destroyed right-away (we need
- * to wait for all client's references to go away first).
- */
-
- status_t err = NAME_NOT_FOUND;
- Mutex::Autolock _l(mStateLock);
- sp<LayerBaseClient> layer = client->getLayerUser(handle);
-
- if (layer != 0) {
- err = purgatorizeLayer_l(layer);
- if (err == NO_ERROR) {
- setTransactionFlags(eTransactionNeeded);
- }
+ // called by the window manager when it wants to remove a Layer
+ status_t err = NO_ERROR;
+ sp<Layer> l(client->getLayerUser(handle));
+ if (l != NULL) {
+ err = removeLayer(l);
+ ALOGE_IF(err<0 && err != NAME_NOT_FOUND,
+ "error removing layer=%p (%s)", l.get(), strerror(-err));
}
return err;
}
-status_t SurfaceFlinger::onLayerDestroyed(const wp<LayerBaseClient>& layer)
+status_t SurfaceFlinger::onLayerDestroyed(const wp<Layer>& layer)
{
- // called by ~ISurface() when all references are gone
+ // called by ~LayerCleaner() when all references to the IBinder (handle)
+ // are gone
status_t err = NO_ERROR;
- sp<LayerBaseClient> l(layer.promote());
+ sp<Layer> l(layer.promote());
if (l != NULL) {
- Mutex::Autolock _l(mStateLock);
- err = removeLayer_l(l);
- if (err == NAME_NOT_FOUND) {
- // The surface wasn't in the current list, which means it was
- // removed already, which means it is in the purgatory,
- // and need to be removed from there.
- ssize_t idx = mLayerPurgatory.remove(l);
- ALOGE_IF(idx < 0,
- "layer=%p is not in the purgatory list", l.get());
- }
+ err = removeLayer(l);
ALOGE_IF(err<0 && err != NAME_NOT_FOUND,
"error removing layer=%p (%s)", l.get(), strerror(-err));
}
@@ -2072,12 +1982,14 @@
// ---------------------------------------------------------------------------
void SurfaceFlinger::onInitializeDisplays() {
- // reset screen orientation
+ // reset screen orientation and use primary layer stack
Vector<ComposerState> state;
Vector<DisplayState> displays;
DisplayState d;
- d.what = DisplayState::eDisplayProjectionChanged;
+ d.what = DisplayState::eDisplayProjectionChanged |
+ DisplayState::eLayerStackChanged;
d.token = mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY];
+ d.layerStack = 0;
d.orientation = DisplayState::eOrientationDefault;
d.frame.makeInvalid();
d.viewport.makeInvalid();
@@ -2266,7 +2178,7 @@
const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
const size_t count = currentLayers.size();
for (size_t i=0 ; i<count ; i++) {
- const sp<LayerBase>& layer(currentLayers[i]);
+ const sp<Layer>& layer(currentLayers[i]);
snprintf(buffer, SIZE, "%s\n", layer->getName().string());
result.append(buffer);
}
@@ -2291,7 +2203,7 @@
const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
const size_t count = currentLayers.size();
for (size_t i=0 ; i<count ; i++) {
- const sp<LayerBase>& layer(currentLayers[i]);
+ const sp<Layer>& layer(currentLayers[i]);
if (name == layer->getName()) {
layer->dumpStats(result, buffer, SIZE);
}
@@ -2311,7 +2223,7 @@
const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
const size_t count = currentLayers.size();
for (size_t i=0 ; i<count ; i++) {
- const sp<LayerBase>& layer(currentLayers[i]);
+ const sp<Layer>& layer(currentLayers[i]);
if (name.isEmpty() || (name == layer->getName())) {
layer->clearStats();
}
@@ -2367,23 +2279,11 @@
snprintf(buffer, SIZE, "Visible layers (count = %d)\n", count);
result.append(buffer);
for (size_t i=0 ; i<count ; i++) {
- const sp<LayerBase>& layer(currentLayers[i]);
+ const sp<Layer>& layer(currentLayers[i]);
layer->dump(result, buffer, SIZE);
}
/*
- * Dump the layers in the purgatory
- */
-
- const size_t purgatorySize = mLayerPurgatory.size();
- snprintf(buffer, SIZE, "Purgatory state (%d entries)\n", purgatorySize);
- result.append(buffer);
- for (size_t i=0 ; i<purgatorySize ; i++) {
- const sp<LayerBase>& layer(mLayerPurgatory.itemAt(i));
- layer->shortDump(result, buffer, SIZE);
- }
-
- /*
* Dump Display state
*/
@@ -2468,7 +2368,7 @@
alloc.dump(result);
}
-const Vector< sp<LayerBase> >&
+const Vector< sp<Layer> >&
SurfaceFlinger::getLayerSortedByZForHwcDisplay(int disp) {
// Note: mStateLock is held here
return getDisplayDevice( getBuiltInDisplay(disp) )->getVisibleLayersSortedByZ();
@@ -2497,6 +2397,7 @@
{
switch (code) {
case CREATE_CONNECTION:
+ case CREATE_DISPLAY:
case SET_TRANSACTION_STATE:
case BOOT_FINISHED:
case BLANK:
@@ -2603,101 +2504,82 @@
}
// ---------------------------------------------------------------------------
-
-status_t SurfaceFlinger::renderScreenToTexture(uint32_t layerStack,
- GLuint* textureName, GLfloat* uOut, GLfloat* vOut)
-{
- Mutex::Autolock _l(mStateLock);
- return renderScreenToTextureLocked(layerStack, textureName, uOut, vOut);
-}
-
-status_t SurfaceFlinger::renderScreenToTextureLocked(uint32_t layerStack,
- GLuint* textureName, GLfloat* uOut, GLfloat* vOut)
-{
- ATRACE_CALL();
-
- if (!GLExtensions::getInstance().haveFramebufferObject())
- return INVALID_OPERATION;
-
- // get screen geometry
- // FIXME: figure out what it means to have a screenshot texture w/ multi-display
- sp<const DisplayDevice> hw(getDefaultDisplayDevice());
- const uint32_t hw_w = hw->getWidth();
- const uint32_t hw_h = hw->getHeight();
- GLfloat u = 1;
- GLfloat v = 1;
-
- // make sure to clear all GL error flags
- while ( glGetError() != GL_NO_ERROR ) ;
-
- // create a FBO
- GLuint name, tname;
- glGenTextures(1, &tname);
- glBindTexture(GL_TEXTURE_2D, tname);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
- hw_w, hw_h, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
- if (glGetError() != GL_NO_ERROR) {
- while ( glGetError() != GL_NO_ERROR ) ;
- GLint tw = (2 << (31 - clz(hw_w)));
- GLint th = (2 << (31 - clz(hw_h)));
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
- tw, th, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
- u = GLfloat(hw_w) / tw;
- v = GLfloat(hw_h) / th;
- }
- glGenFramebuffersOES(1, &name);
- glBindFramebufferOES(GL_FRAMEBUFFER_OES, name);
- glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES,
- GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, tname, 0);
-
- DisplayDevice::setViewportAndProjection(hw);
-
- // redraw the screen entirely...
- glDisable(GL_TEXTURE_EXTERNAL_OES);
- glDisable(GL_TEXTURE_2D);
- glClearColor(0,0,0,1);
- glClear(GL_COLOR_BUFFER_BIT);
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
- const Vector< sp<LayerBase> >& layers(hw->getVisibleLayersSortedByZ());
- const size_t count = layers.size();
- for (size_t i=0 ; i<count ; ++i) {
- const sp<LayerBase>& layer(layers[i]);
- layer->draw(hw);
- }
-
- hw->compositionComplete();
-
- // back to main framebuffer
- glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
- glDeleteFramebuffersOES(1, &name);
-
- *textureName = tname;
- *uOut = u;
- *vOut = v;
- return NO_ERROR;
-}
-
+// Capture screen into an IGraphiBufferProducer
// ---------------------------------------------------------------------------
-status_t SurfaceFlinger::captureScreenImplLocked(const sp<IBinder>& display,
- sp<IMemoryHeap>* heap,
- uint32_t* w, uint32_t* h, PixelFormat* f,
- uint32_t sw, uint32_t sh,
+status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
+ const sp<IGraphicBufferProducer>& producer,
+ uint32_t reqWidth, uint32_t reqHeight,
+ uint32_t minLayerZ, uint32_t maxLayerZ,
+ bool isCpuConsumer) {
+
+ if (CC_UNLIKELY(display == 0))
+ return BAD_VALUE;
+
+ if (CC_UNLIKELY(producer == 0))
+ return BAD_VALUE;
+
+ class MessageCaptureScreen : public MessageBase {
+ SurfaceFlinger* flinger;
+ sp<IBinder> display;
+ sp<IGraphicBufferProducer> producer;
+ uint32_t reqWidth, reqHeight;
+ uint32_t minLayerZ,maxLayerZ;
+ bool isCpuConsumer;
+ status_t result;
+ public:
+ MessageCaptureScreen(SurfaceFlinger* flinger,
+ const sp<IBinder>& display,
+ const sp<IGraphicBufferProducer>& producer,
+ uint32_t reqWidth, uint32_t reqHeight,
+ uint32_t minLayerZ, uint32_t maxLayerZ, bool isCpuConsumer)
+ : flinger(flinger), display(display), producer(producer),
+ reqWidth(reqWidth), reqHeight(reqHeight),
+ minLayerZ(minLayerZ), maxLayerZ(maxLayerZ),
+ isCpuConsumer(isCpuConsumer),
+ result(PERMISSION_DENIED)
+ {
+ }
+ status_t getResult() const {
+ return result;
+ }
+ virtual bool handler() {
+ Mutex::Autolock _l(flinger->mStateLock);
+ sp<const DisplayDevice> hw(flinger->getDisplayDevice(display));
+ // TODO: if we know the GL->CPU path works, we can call
+ // captureScreenImplLocked() directly, instead of using the
+ // "CpuConsumer" version, which is much less efficient -- it is
+ // however needed by some older drivers.
+ if (isCpuConsumer) {
+ result = flinger->captureScreenImplCpuConsumerLocked(hw,
+ producer, reqWidth, reqHeight, minLayerZ, maxLayerZ);
+ } else {
+ result = flinger->captureScreenImplLocked(hw,
+ producer, reqWidth, reqHeight, minLayerZ, maxLayerZ);
+ }
+ return true;
+ }
+ };
+
+ sp<MessageBase> msg = new MessageCaptureScreen(this,
+ display, producer, reqWidth, reqHeight, minLayerZ, maxLayerZ,
+ isCpuConsumer);
+ status_t res = postMessageSync(msg);
+ if (res == NO_ERROR) {
+ res = static_cast<MessageCaptureScreen*>( msg.get() )->getResult();
+ }
+ return res;
+}
+
+status_t SurfaceFlinger::captureScreenImplLocked(
+ const sp<const DisplayDevice>& hw,
+ const sp<IGraphicBufferProducer>& producer,
+ uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ)
{
ATRACE_CALL();
- status_t result = PERMISSION_DENIED;
-
- if (!GLExtensions::getInstance().haveFramebufferObject()) {
- return INVALID_OPERATION;
- }
-
// get screen geometry
- sp<const DisplayDevice> hw(getDisplayDevice(display));
const uint32_t hw_w = hw->getWidth();
const uint32_t hw_h = hw->getHeight();
@@ -2707,162 +2589,199 @@
return PERMISSION_DENIED;
}
- if ((sw > hw_w) || (sh > hw_h)) {
- ALOGE("size mismatch (%d, %d) > (%d, %d)", sw, sh, hw_w, hw_h);
+ if ((reqWidth > hw_w) || (reqHeight > hw_h)) {
+ ALOGE("size mismatch (%d, %d) > (%d, %d)",
+ reqWidth, reqHeight, hw_w, hw_h);
return BAD_VALUE;
}
- sw = (!sw) ? hw_w : sw;
- sh = (!sh) ? hw_h : sh;
- const size_t size = sw * sh * 4;
- const bool filtering = sw != hw_w || sh != hw_h;
+ reqWidth = (!reqWidth) ? hw_w : reqWidth;
+ reqHeight = (!reqHeight) ? hw_h : reqHeight;
+ const bool filtering = reqWidth != hw_w || reqWidth != hw_h;
-// ALOGD("screenshot: sw=%d, sh=%d, minZ=%d, maxZ=%d",
-// sw, sh, minLayerZ, maxLayerZ);
+ // Create a surface to render into
+ sp<Surface> surface = new Surface(producer);
+ ANativeWindow* const window = surface.get();
+
+ // set the buffer size to what the user requested
+ native_window_set_buffers_user_dimensions(window, reqWidth, reqHeight);
+
+ // and create the corresponding EGLSurface
+ EGLSurface eglSurface = eglCreateWindowSurface(
+ mEGLDisplay, mEGLConfig, window, NULL);
+ if (eglSurface == EGL_NO_SURFACE) {
+ ALOGE("captureScreenImplLocked: eglCreateWindowSurface() failed 0x%4x",
+ eglGetError());
+ return BAD_VALUE;
+ }
+
+ if (!eglMakeCurrent(mEGLDisplay, eglSurface, eglSurface, mEGLContext)) {
+ ALOGE("captureScreenImplLocked: eglMakeCurrent() failed 0x%4x",
+ eglGetError());
+ eglDestroySurface(mEGLDisplay, eglSurface);
+ return BAD_VALUE;
+ }
// make sure to clear all GL error flags
while ( glGetError() != GL_NO_ERROR ) ;
- // create a FBO
- GLuint name, tname;
- glGenRenderbuffersOES(1, &tname);
- glBindRenderbufferOES(GL_RENDERBUFFER_OES, tname);
- glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_RGBA8_OES, sw, sh);
+ // set-up our viewport
+ glViewport(0, 0, reqWidth, reqHeight);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrthof(0, hw_w, 0, hw_h, 0, 1);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
- glGenFramebuffersOES(1, &name);
- glBindFramebufferOES(GL_FRAMEBUFFER_OES, name);
- glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES,
- GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, tname);
+ // redraw the screen entirely...
+ glDisable(GL_TEXTURE_EXTERNAL_OES);
+ glDisable(GL_TEXTURE_2D);
+ glClearColor(0,0,0,1);
+ glClear(GL_COLOR_BUFFER_BIT);
- GLenum status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
-
- if (status == GL_FRAMEBUFFER_COMPLETE_OES) {
-
- // invert everything, b/c glReadPixel() below will invert the FB
- GLint viewport[4];
- glGetIntegerv(GL_VIEWPORT, viewport);
- glViewport(0, 0, sw, sh);
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadIdentity();
- glOrthof(0, hw_w, hw_h, 0, 0, 1);
- glMatrixMode(GL_MODELVIEW);
-
- // redraw the screen entirely...
- glClearColor(0,0,0,1);
- glClear(GL_COLOR_BUFFER_BIT);
-
- const Vector< sp<LayerBase> >& layers(hw->getVisibleLayersSortedByZ());
- const size_t count = layers.size();
- for (size_t i=0 ; i<count ; ++i) {
- const sp<LayerBase>& layer(layers[i]);
- const uint32_t z = layer->drawingState().z;
- if (z >= minLayerZ && z <= maxLayerZ) {
- if (filtering) layer->setFiltering(true);
- layer->draw(hw);
- if (filtering) layer->setFiltering(false);
- }
- }
-
- // check for errors and return screen capture
- if (glGetError() != GL_NO_ERROR) {
- // error while rendering
- result = INVALID_OPERATION;
- } else {
- // allocate shared memory large enough to hold the
- // screen capture
- sp<MemoryHeapBase> base(
- new MemoryHeapBase(size, 0, "screen-capture") );
- void* const ptr = base->getBase();
- if (ptr != MAP_FAILED) {
- // capture the screen with glReadPixels()
- ScopedTrace _t(ATRACE_TAG, "glReadPixels");
- glReadPixels(0, 0, sw, sh, GL_RGBA, GL_UNSIGNED_BYTE, ptr);
- if (glGetError() == GL_NO_ERROR) {
- *heap = base;
- *w = sw;
- *h = sh;
- *f = PIXEL_FORMAT_RGBA_8888;
- result = NO_ERROR;
+ const LayerVector& layers( mDrawingState.layersSortedByZ );
+ const size_t count = layers.size();
+ for (size_t i=0 ; i<count ; ++i) {
+ const sp<Layer>& layer(layers[i]);
+ const Layer::State& state(layer->drawingState());
+ if (state.layerStack == hw->getLayerStack()) {
+ if (state.z >= minLayerZ && state.z <= maxLayerZ) {
+ if (layer->isVisible()) {
+ if (filtering) layer->setFiltering(true);
+ layer->draw(hw);
+ if (filtering) layer->setFiltering(false);
}
- } else {
- result = NO_MEMORY;
}
}
- glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- } else {
- result = BAD_VALUE;
}
- // release FBO resources
- glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
- glDeleteRenderbuffersOES(1, &tname);
- glDeleteFramebuffersOES(1, &name);
-
+ // compositionComplete is needed for older driver
hw->compositionComplete();
-// ALOGD("screenshot: result = %s", result<0 ? strerror(result) : "OK");
+ // and finishing things up...
+ if (eglSwapBuffers(mEGLDisplay, eglSurface) != EGL_TRUE) {
+ ALOGE("captureScreenImplLocked: eglSwapBuffers() failed 0x%4x",
+ eglGetError());
+ eglDestroySurface(mEGLDisplay, eglSurface);
+ return BAD_VALUE;
+ }
- return result;
+ eglDestroySurface(mEGLDisplay, eglSurface);
+
+ return NO_ERROR;
}
-status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
- sp<IMemoryHeap>* heap,
- uint32_t* width, uint32_t* height, PixelFormat* format,
- uint32_t sw, uint32_t sh,
+status_t SurfaceFlinger::captureScreenImplCpuConsumerLocked(
+ const sp<const DisplayDevice>& hw,
+ const sp<IGraphicBufferProducer>& producer,
+ uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ)
{
- if (CC_UNLIKELY(display == 0))
- return BAD_VALUE;
+ ATRACE_CALL();
- if (!GLExtensions::getInstance().haveFramebufferObject())
+ if (!GLExtensions::getInstance().haveFramebufferObject()) {
return INVALID_OPERATION;
-
- class MessageCaptureScreen : public MessageBase {
- SurfaceFlinger* flinger;
- sp<IBinder> display;
- sp<IMemoryHeap>* heap;
- uint32_t* w;
- uint32_t* h;
- PixelFormat* f;
- uint32_t sw;
- uint32_t sh;
- uint32_t minLayerZ;
- uint32_t maxLayerZ;
- status_t result;
- public:
- MessageCaptureScreen(SurfaceFlinger* flinger, const sp<IBinder>& display,
- sp<IMemoryHeap>* heap, uint32_t* w, uint32_t* h, PixelFormat* f,
- uint32_t sw, uint32_t sh,
- uint32_t minLayerZ, uint32_t maxLayerZ)
- : flinger(flinger), display(display),
- heap(heap), w(w), h(h), f(f), sw(sw), sh(sh),
- minLayerZ(minLayerZ), maxLayerZ(maxLayerZ),
- result(PERMISSION_DENIED)
- {
- }
- status_t getResult() const {
- return result;
- }
- virtual bool handler() {
- Mutex::Autolock _l(flinger->mStateLock);
- result = flinger->captureScreenImplLocked(display,
- heap, w, h, f, sw, sh, minLayerZ, maxLayerZ);
- return true;
- }
- };
-
- sp<MessageBase> msg = new MessageCaptureScreen(this,
- display, heap, width, height, format, sw, sh, minLayerZ, maxLayerZ);
- status_t res = postMessageSync(msg);
- if (res == NO_ERROR) {
- res = static_cast<MessageCaptureScreen*>( msg.get() )->getResult();
}
- return res;
+
+ // create the texture that will receive the screenshot, later we'll
+ // attach a FBO to it so we can call glReadPixels().
+ GLuint tname;
+ glGenTextures(1, &tname);
+ glBindTexture(GL_TEXTURE_2D, tname);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ // the GLConsumer will provide the BufferQueue
+ sp<GLConsumer> consumer = new GLConsumer(tname, true, GL_TEXTURE_2D);
+ consumer->getBufferQueue()->setDefaultBufferFormat(HAL_PIXEL_FORMAT_RGBA_8888);
+
+ // call the new screenshot taking code, passing a BufferQueue to it
+ status_t result = captureScreenImplLocked(hw,
+ consumer->getBufferQueue(), reqWidth, reqHeight, minLayerZ, maxLayerZ);
+
+ if (result == NO_ERROR) {
+ result = consumer->updateTexImage();
+ if (result == NO_ERROR) {
+ // create a FBO
+ GLuint name;
+ glGenFramebuffersOES(1, &name);
+ glBindFramebufferOES(GL_FRAMEBUFFER_OES, name);
+ glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES,
+ GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, tname, 0);
+
+ reqWidth = consumer->getCurrentBuffer()->getWidth();
+ reqHeight = consumer->getCurrentBuffer()->getHeight();
+
+ {
+ // in this block we render the screenshot into the
+ // CpuConsumer using glReadPixels from our GLConsumer,
+ // Some older drivers don't support the GL->CPU path so
+ // have to wrap it with a CPU->CPU path, which is what
+ // glReadPixels essentially is
+
+ sp<Surface> sur = new Surface(producer);
+ ANativeWindow* window = sur.get();
+ ANativeWindowBuffer* buffer;
+ void* vaddr;
+
+ if (native_window_api_connect(window,
+ NATIVE_WINDOW_API_CPU) == NO_ERROR) {
+ int err = 0;
+ err = native_window_set_buffers_dimensions(window,
+ reqWidth, reqHeight);
+ err |= native_window_set_buffers_format(window,
+ HAL_PIXEL_FORMAT_RGBA_8888);
+ err |= native_window_set_usage(window,
+ GRALLOC_USAGE_SW_READ_OFTEN |
+ GRALLOC_USAGE_SW_WRITE_OFTEN);
+
+ if (err == NO_ERROR) {
+ if (native_window_dequeue_buffer_and_wait(window,
+ &buffer) == NO_ERROR) {
+ sp<GraphicBuffer> buf =
+ static_cast<GraphicBuffer*>(buffer);
+ if (buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN,
+ &vaddr) == NO_ERROR) {
+ if (buffer->stride != int(reqWidth)) {
+ // we're unlucky here, glReadPixels is
+ // not able to deal with a stride not
+ // equal to the width.
+ uint32_t* tmp = new uint32_t[reqWidth*reqHeight];
+ if (tmp != NULL) {
+ glReadPixels(0, 0, reqWidth, reqHeight,
+ GL_RGBA, GL_UNSIGNED_BYTE, tmp);
+ for (size_t y=0 ; y<reqHeight ; y++) {
+ memcpy((uint32_t*)vaddr + y*buffer->stride,
+ tmp + y*reqWidth, reqWidth*4);
+ }
+ delete [] tmp;
+ }
+ } else {
+ glReadPixels(0, 0, reqWidth, reqHeight,
+ GL_RGBA, GL_UNSIGNED_BYTE, vaddr);
+ }
+ buf->unlock();
+ }
+ window->queueBuffer(window, buffer, -1);
+ }
+ }
+ native_window_api_disconnect(window, NATIVE_WINDOW_API_CPU);
+ }
+ }
+
+ // back to main framebuffer
+ glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
+ glDeleteFramebuffersOES(1, &name);
+ }
+ }
+
+ glDeleteTextures(1, &tname);
+
+ DisplayDevice::makeCurrent(mEGLDisplay,
+ getDefaultDisplayDevice(), mEGLContext);
+
+ return result;
}
// ---------------------------------------------------------------------------
@@ -2871,15 +2790,15 @@
}
SurfaceFlinger::LayerVector::LayerVector(const LayerVector& rhs)
- : SortedVector<sp<LayerBase> >(rhs) {
+ : SortedVector<sp<Layer> >(rhs) {
}
int SurfaceFlinger::LayerVector::do_compare(const void* lhs,
const void* rhs) const
{
// sort layers per layer-stack, then by z-order and finally by sequence
- const sp<LayerBase>& l(*reinterpret_cast<const sp<LayerBase>*>(lhs));
- const sp<LayerBase>& r(*reinterpret_cast<const sp<LayerBase>*>(rhs));
+ const sp<Layer>& l(*reinterpret_cast<const sp<Layer>*>(lhs));
+ const sp<Layer>& r(*reinterpret_cast<const sp<Layer>*>(rhs));
uint32_t ls = l->currentState().layerStack;
uint32_t rs = r->currentState().layerStack;
@@ -2901,7 +2820,7 @@
}
SurfaceFlinger::DisplayDeviceState::DisplayDeviceState(DisplayDevice::DisplayType type)
- : type(type), layerStack(0), orientation(0) {
+ : type(type), layerStack(DisplayDevice::NO_LAYER_STACK), orientation(0) {
viewport.makeInvalid();
frame.makeInvalid();
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index e67f3f1..2aacfe7 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -60,10 +60,7 @@
class EventThread;
class IGraphicBufferAlloc;
class Layer;
-class LayerBase;
-class LayerBaseClient;
class LayerDim;
-class LayerScreenshot;
class Surface;
// ---------------------------------------------------------------------------
@@ -103,14 +100,6 @@
// force full composition on all displays
void repaintEverything();
- // renders content on given display to a texture. thread-safe version.
- status_t renderScreenToTexture(uint32_t layerStack, GLuint* textureName,
- GLfloat* uOut, GLfloat* vOut);
-
- // renders content on given display to a texture, w/o acquiring main lock
- status_t renderScreenToTextureLocked(uint32_t layerStack, GLuint* textureName,
- GLfloat* uOut, GLfloat* vOut);
-
// returns the default Display
sp<const DisplayDevice> getDefaultDisplayDevice() const {
return getDisplayDevice(mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY]);
@@ -133,15 +122,13 @@
// for debugging only
// TODO: this should be made accessible only to HWComposer
- const Vector< sp<LayerBase> >& getLayerSortedByZForHwcDisplay(int disp);
+ const Vector< sp<Layer> >& getLayerSortedByZForHwcDisplay(int disp);
private:
friend class Client;
friend class DisplayEventConnection;
- friend class LayerBase;
- friend class LayerBaseClient;
friend class Layer;
- friend class LayerScreenshot;
+ friend class SurfaceTextureLayer;
// We're reference counted, never destroy SurfaceFlinger directly
virtual ~SurfaceFlinger();
@@ -150,7 +137,7 @@
* Internal data structures
*/
- class LayerVector : public SortedVector<sp<LayerBase> > {
+ class LayerVector : public SortedVector< sp<Layer> > {
public:
LayerVector();
LayerVector(const LayerVector& rhs);
@@ -198,10 +185,10 @@
virtual bool authenticateSurfaceTexture(
const sp<IGraphicBufferProducer>& bufferProducer) const;
virtual sp<IDisplayEventConnection> createDisplayEventConnection();
- virtual status_t captureScreen(const sp<IBinder>& display, sp<IMemoryHeap>* heap,
- uint32_t* width, uint32_t* height, PixelFormat* format,
- uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ,
- uint32_t maxLayerZ);
+ virtual status_t captureScreen(const sp<IBinder>& display,
+ const sp<IGraphicBufferProducer>& producer,
+ uint32_t reqWidth, uint32_t reqHeight,
+ uint32_t minLayerZ, uint32_t maxLayerZ, bool isCpuConsumer);
// called when screen needs to turn off
virtual void blank(const sp<IBinder>& display);
// called when screen is turning back on
@@ -267,38 +254,36 @@
/* ------------------------------------------------------------------------
* Layer management
*/
- sp<ISurface> createLayer(const String8& name, const sp<Client>& client,
- uint32_t w, uint32_t h, PixelFormat format, uint32_t flags);
+ status_t createLayer(const String8& name, const sp<Client>& client,
+ uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
+ sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp);
- sp<Layer> createNormalLayer(const sp<Client>& client,
- uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format);
+ status_t createNormalLayer(const sp<Client>& client, const String8& name,
+ uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
+ sp<IBinder>* outHandle, sp<IGraphicBufferProducer>* outGbp,
+ sp<Layer>* outLayer);
- sp<LayerDim> createDimLayer(const sp<Client>& client,
- uint32_t w, uint32_t h, uint32_t flags);
-
- sp<LayerScreenshot> createScreenshotLayer(const sp<Client>& client,
- uint32_t w, uint32_t h, uint32_t flags);
+ status_t createDimLayer(const sp<Client>& client, const String8& name,
+ uint32_t w, uint32_t h, uint32_t flags, sp<IBinder>* outHandle,
+ sp<IGraphicBufferProducer>* outGbp, sp<Layer>* outLayer);
// called in response to the window-manager calling
// ISurfaceComposerClient::destroySurface()
- // The specified layer is first placed in a purgatory list
- // until all references from the client are released.
status_t onLayerRemoved(const sp<Client>& client, const sp<IBinder>& handle);
// called when all clients have released all their references to
// this layer meaning it is entirely safe to destroy all
// resources associated to this layer.
- status_t onLayerDestroyed(const wp<LayerBaseClient>& layer);
+ status_t onLayerDestroyed(const wp<Layer>& layer);
// remove a layer from SurfaceFlinger immediately
- status_t removeLayer(const sp<LayerBase>& layer);
+ status_t removeLayer(const sp<Layer>& layer);
// add a layer to SurfaceFlinger
- void addClientLayer(const sp<Client>& client, const sp<IBinder>& handle,
- const sp<LayerBaseClient>& lbc);
-
- status_t removeLayer_l(const sp<LayerBase>& layer);
- status_t purgatorizeLayer_l(const sp<LayerBase>& layer);
+ void addClientLayer(const sp<Client>& client,
+ const sp<IBinder>& handle,
+ const sp<IGraphicBufferProducer>& gbc,
+ const sp<Layer>& lbc);
/* ------------------------------------------------------------------------
* Boot animation, on/off animations and screen capture
@@ -306,10 +291,18 @@
void startBootAnim();
- status_t captureScreenImplLocked(const sp<IBinder>& display, sp<IMemoryHeap>* heap,
- uint32_t* width, uint32_t* height, PixelFormat* format,
- uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ,
- uint32_t maxLayerZ);
+ status_t captureScreenImplLocked(
+ const sp<const DisplayDevice>& hw,
+ const sp<IGraphicBufferProducer>& producer,
+ uint32_t reqWidth, uint32_t reqHeight,
+ uint32_t minLayerZ, uint32_t maxLayerZ);
+
+ status_t captureScreenImplCpuConsumerLocked(
+ const sp<const DisplayDevice>& hw,
+ const sp<IGraphicBufferProducer>& producer,
+ uint32_t reqWidth, uint32_t reqHeight,
+ uint32_t minLayerZ, uint32_t maxLayerZ);
+
/* ------------------------------------------------------------------------
* EGL
@@ -404,10 +397,10 @@
State mCurrentState;
volatile int32_t mTransactionFlags;
Condition mTransactionCV;
- SortedVector<sp<LayerBase> > mLayerPurgatory;
bool mTransactionPending;
bool mAnimTransactionPending;
- Vector<sp<LayerBase> > mLayersPendingRemoval;
+ Vector< sp<Layer> > mLayersPendingRemoval;
+ SortedVector< wp<IBinder> > mGraphicBufferProducerList;
// protected by mStateLock (but we could use another lock)
bool mLayersRemoved;
@@ -456,7 +449,7 @@
// protected by mDestroyedLayerLock;
mutable Mutex mDestroyedLayerLock;
- Vector<LayerBase const *> mDestroyedLayers;
+ Vector<Layer const *> mDestroyedLayers;
/* ------------------------------------------------------------------------
* Feature prototyping
diff --git a/services/surfaceflinger/SurfaceTextureLayer.cpp b/services/surfaceflinger/SurfaceTextureLayer.cpp
index 395c8c8..d0f0dae 100644
--- a/services/surfaceflinger/SurfaceTextureLayer.cpp
+++ b/services/surfaceflinger/SurfaceTextureLayer.cpp
@@ -20,17 +20,35 @@
#include <utils/Errors.h>
+#include "SurfaceFlinger.h"
#include "SurfaceTextureLayer.h"
namespace android {
// ---------------------------------------------------------------------------
-SurfaceTextureLayer::SurfaceTextureLayer()
- : BufferQueue(true) {
+SurfaceTextureLayer::SurfaceTextureLayer(const sp<SurfaceFlinger>& flinger)
+ : BufferQueue(true), flinger(flinger) {
}
SurfaceTextureLayer::~SurfaceTextureLayer() {
+ // remove ourselves from SurfaceFlinger's list. We do this asynchronously
+ // because we don't know where this dtor is called from, it could be
+ // called with the mStateLock held, leading to a dead-lock (it actually
+ // happens).
+ class MessageCleanUpList : public MessageBase {
+ sp<SurfaceFlinger> flinger;
+ wp<IBinder> gbp;
+ public:
+ MessageCleanUpList(const sp<SurfaceFlinger>& flinger, const wp<IBinder>& gbp)
+ : flinger(flinger), gbp(gbp) { }
+ virtual bool handler() {
+ Mutex::Autolock _l(flinger->mStateLock);
+ flinger->mGraphicBufferProducerList.remove(gbp);
+ return true;
+ }
+ };
+ flinger->postMessageAsync( new MessageCleanUpList(flinger, this) );
}
status_t SurfaceTextureLayer::connect(int api, QueueBufferOutput* output) {
diff --git a/services/surfaceflinger/SurfaceTextureLayer.h b/services/surfaceflinger/SurfaceTextureLayer.h
index a75ccf4..13cff2f 100644
--- a/services/surfaceflinger/SurfaceTextureLayer.h
+++ b/services/surfaceflinger/SurfaceTextureLayer.h
@@ -28,15 +28,16 @@
// ---------------------------------------------------------------------------
class Layer;
+class SurfaceFlinger;
/*
* This is a thin wrapper around BufferQueue, used by the Layer class.
*/
-class SurfaceTextureLayer : public BufferQueue
-{
+class SurfaceTextureLayer : public BufferQueue {
+ sp<SurfaceFlinger> flinger;
public:
- SurfaceTextureLayer();
- ~SurfaceTextureLayer();
+ SurfaceTextureLayer(const sp<SurfaceFlinger>& flinger);
+ virtual ~SurfaceTextureLayer();
// After calling the superclass connect(), set or clear synchronous
// mode appropriately for the specified API.
diff --git a/services/surfaceflinger/Transform.cpp b/services/surfaceflinger/Transform.cpp
index aca90e0..315720e 100644
--- a/services/surfaceflinger/Transform.cpp
+++ b/services/surfaceflinger/Transform.cpp
@@ -298,6 +298,44 @@
return mType;
}
+Transform Transform::inverse() const {
+ // our 3x3 matrix is always of the form of a 2x2 transformation
+ // followed by a translation: T*M, therefore:
+ // (T*M)^-1 = M^-1 * T^-1
+ Transform result;
+ if (mType <= TRANSLATE) {
+ // 1 0 x
+ // 0 1 y
+ // 0 0 1
+ result = *this;
+ result.mMatrix[2][0] = -result.mMatrix[2][0];
+ result.mMatrix[2][1] = -result.mMatrix[2][1];
+ } else {
+ // a c x
+ // b d y
+ // 0 0 1
+ const mat33& M(mMatrix);
+ const float a = M[0][0];
+ const float b = M[1][0];
+ const float c = M[0][1];
+ const float d = M[1][1];
+ const float x = M[2][0];
+ const float y = M[2][1];
+
+ Transform R, T;
+ const float idet = 1.0 / (a*d - b*c);
+ R.mMatrix[0][0] = d*idet; R.mMatrix[0][1] = -c*idet;
+ R.mMatrix[1][0] = -b*idet; R.mMatrix[1][1] = a*idet;
+ R.mType = mType &= ~TRANSLATE;
+
+ T.mMatrix[2][0] = -x;
+ T.mMatrix[2][1] = -y;
+ T.mType = TRANSLATE;
+ result = R * T;
+ }
+ return result;
+}
+
uint32_t Transform::getType() const {
return type() & 0xFF;
}
diff --git a/services/surfaceflinger/Transform.h b/services/surfaceflinger/Transform.h
index 4fe261a..c4efade 100644
--- a/services/surfaceflinger/Transform.h
+++ b/services/surfaceflinger/Transform.h
@@ -80,6 +80,8 @@
Rect transform(const Rect& bounds) const;
Transform operator * (const Transform& rhs) const;
+ Transform inverse() const;
+
// for debugging
void dump(const char* name) const;
diff --git a/services/surfaceflinger/tests/surface/Android.mk b/services/surfaceflinger/tests/surface/Android.mk
deleted file mode 100644
index c59060e..0000000
--- a/services/surfaceflinger/tests/surface/Android.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- surface.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libutils \
- libbinder \
- libui \
- libgui
-
-LOCAL_MODULE:= test-surface
-
-LOCAL_MODULE_TAGS := tests
-
-include $(BUILD_EXECUTABLE)
diff --git a/services/surfaceflinger/tests/surface/surface.cpp b/services/surfaceflinger/tests/surface/surface.cpp
deleted file mode 100644
index 9c41cc3..0000000
--- a/services/surfaceflinger/tests/surface/surface.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2010 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 <cutils/memory.h>
-
-#include <utils/Log.h>
-
-#include <binder/IPCThreadState.h>
-#include <binder/ProcessState.h>
-#include <binder/IServiceManager.h>
-
-#include <gui/Surface.h>
-#include <gui/SurfaceComposerClient.h>
-
-using namespace android;
-
-int main(int argc, char** argv)
-{
- // set up the thread-pool
- sp<ProcessState> proc(ProcessState::self());
- ProcessState::self()->startThreadPool();
-
- // create a client to surfaceflinger
- sp<SurfaceComposerClient> client = new SurfaceComposerClient();
-
- sp<SurfaceControl> surfaceControl = client->createSurface(
- String8("surface"), 160, 240, PIXEL_FORMAT_RGB_565, 0);
- SurfaceComposerClient::openGlobalTransaction();
- surfaceControl->setLayer(100000);
- SurfaceComposerClient::closeGlobalTransaction();
-
- // pretend it went cross-process
- Parcel parcel;
- SurfaceControl::writeSurfaceToParcel(surfaceControl, &parcel);
- parcel.setDataPosition(0);
- sp<Surface> surface = Surface::readFromParcel(parcel);
- ANativeWindow* window = surface.get();
-
- printf("window=%p\n", window);
-
- int err = native_window_set_buffer_count(window, 8);
- ANativeWindowBuffer* buffer;
-
- for (int i=0 ; i<8 ; i++) {
- window->dequeueBuffer(window, &buffer);
- printf("buffer %d: %p\n", i, buffer);
- }
-
- printf("test complete. CTRL+C to finish.\n");
-
- IPCThreadState::self()->joinThreadPool();
- return 0;
-}