Merge "Refactor menu internals."
diff --git a/include/ui/Input.h b/include/ui/Input.h
index 0dc29c8..9b92c73 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -620,6 +620,11 @@
// Oldest sample to consider when calculating the velocity.
static const nsecs_t MAX_AGE = 200 * 1000000; // 200 ms
+ // When the total duration of the window of samples being averaged is less
+ // than the window size, the resulting velocity is scaled to reduce the impact
+ // of overestimation in short traces.
+ static const nsecs_t MIN_WINDOW = 100 * 1000000; // 100 ms
+
// The minimum duration between samples when estimating velocity.
static const nsecs_t MIN_DURATION = 10 * 1000000; // 10 ms
diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp
index bbe579e..a95f432 100644
--- a/libs/ui/Input.cpp
+++ b/libs/ui/Input.cpp
@@ -832,6 +832,7 @@
const Position& oldestPosition =
oldestMovement.positions[oldestMovement.idBits.getIndexOfBit(id)];
nsecs_t lastDuration = 0;
+
while (numTouches-- > 1) {
if (++index == HISTORY_SIZE) {
index = 0;
@@ -858,6 +859,14 @@
// Make sure we used at least one sample.
if (samplesUsed != 0) {
+ // Scale the velocity linearly if the window of samples is small.
+ nsecs_t totalDuration = newestMovement.eventTime - oldestMovement.eventTime;
+ if (totalDuration < MIN_WINDOW) {
+ float scale = float(totalDuration) / float(MIN_WINDOW);
+ accumVx *= scale;
+ accumVy *= scale;
+ }
+
*outVx = accumVx;
*outVy = accumVy;
return true;
diff --git a/libs/utils/Looper.cpp b/libs/utils/Looper.cpp
index d5dd126..b54fb9d 100644
--- a/libs/utils/Looper.cpp
+++ b/libs/utils/Looper.cpp
@@ -662,7 +662,8 @@
#endif
void Looper::sendMessage(const sp<MessageHandler>& handler, const Message& message) {
- sendMessageAtTime(LLONG_MIN, handler, message);
+ nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+ sendMessageAtTime(now, handler, message);
}
void Looper::sendMessageDelayed(nsecs_t uptimeDelay, const sp<MessageHandler>& handler,
diff --git a/opengl/libs/GLES2_dbg/Android.mk b/opengl/libs/GLES2_dbg/Android.mk
index 853cce6..9f6e68c 100644
--- a/opengl/libs/GLES2_dbg/Android.mk
+++ b/opengl/libs/GLES2_dbg/Android.mk
@@ -45,3 +45,5 @@
LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)
+
+include $(LOCAL_PATH)/test/Android.mk
diff --git a/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py b/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py
index 914ea24..57e008c 100755
--- a/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py
+++ b/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py
@@ -142,6 +142,7 @@
TimeMode = 1; // arg0 = SYSTEM_TIME_* in utils/Timers.h
ExpectResponse = 2; // arg0 = enum Function, arg1 = true/false
CaptureSwap = 3; // arg0 = number of eglSwapBuffers to glReadPixels
+ GLConstant = 4; // arg0 = GLenum, arg1 = constant; send GL impl. constants
};
optional Prop prop = 21; // used with SETPROP, value in arg0
optional float clock = 22; // wall clock in seconds
diff --git a/opengl/libs/GLES2_dbg/src/dbgcontext.cpp b/opengl/libs/GLES2_dbg/src/dbgcontext.cpp
index fe93874..7f5b27b 100644
--- a/opengl/libs/GLES2_dbg/src/dbgcontext.cpp
+++ b/opengl/libs/GLES2_dbg/src/dbgcontext.cpp
@@ -25,11 +25,11 @@
namespace android
{
-static pthread_key_t sEGLThreadLocalStorageKey = -1;
+pthread_key_t dbgEGLThreadLocalStorageKey = -1;
DbgContext * getDbgContextThreadSpecific()
{
- tls_t* tls = (tls_t*)pthread_getspecific(sEGLThreadLocalStorageKey);
+ tls_t* tls = (tls_t*)pthread_getspecific(dbgEGLThreadLocalStorageKey);
return tls->dbg;
}
@@ -63,7 +63,7 @@
DbgContext * CreateDbgContext(const pthread_key_t EGLThreadLocalStorageKey,
const unsigned version, const gl_hooks_t * const hooks)
{
- sEGLThreadLocalStorageKey = EGLThreadLocalStorageKey;
+ dbgEGLThreadLocalStorageKey = EGLThreadLocalStorageKey;
assert(version < 2);
assert(GL_NO_ERROR == hooks->gl.glGetError());
GLint MAX_VERTEX_ATTRIBS = 0;
@@ -71,7 +71,24 @@
GLint readFormat, readType;
hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &readFormat);
hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &readType);
- return new DbgContext(version, hooks, MAX_VERTEX_ATTRIBS, readFormat, readType);
+ DbgContext * const dbg = new DbgContext(version, hooks, MAX_VERTEX_ATTRIBS, readFormat, readType);
+
+ glesv2debugger::Message msg, cmd;
+ msg.set_context_id(reinterpret_cast<int>(dbg));
+ msg.set_expect_response(false);
+ msg.set_type(msg.Response);
+ msg.set_function(msg.SETPROP);
+ msg.set_prop(msg.GLConstant);
+ msg.set_arg0(GL_MAX_VERTEX_ATTRIBS);
+ msg.set_arg1(MAX_VERTEX_ATTRIBS);
+ Send(msg, cmd);
+
+ GLint MAX_COMBINED_TEXTURE_IMAGE_UNITS = 0;
+ hooks->gl.glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &MAX_COMBINED_TEXTURE_IMAGE_UNITS);
+ msg.set_arg0(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS);
+ msg.set_arg1(MAX_COMBINED_TEXTURE_IMAGE_UNITS);
+ Send(msg, cmd);
+ return dbg;
}
void DestroyDbgContext(DbgContext * const dbg)
@@ -149,6 +166,37 @@
}
}
+unsigned char * DbgContext::Decompress(const void * in, const unsigned int inLen,
+ unsigned int * const outLen)
+{
+ assert(inLen > 4 * 3);
+ if (inLen < 4 * 3)
+ return NULL;
+ *outLen = *(uint32_t *)in;
+ unsigned char * const out = (unsigned char *)malloc(*outLen);
+ unsigned int outPos = 0;
+ const unsigned char * const end = (const unsigned char *)in + inLen;
+ for (const unsigned char * inData = (const unsigned char *)in + 4; inData < end; ) {
+ const uint32_t chunkOut = *(uint32_t *)inData;
+ inData += 4;
+ const uint32_t chunkIn = *(uint32_t *)inData;
+ inData += 4;
+ if (chunkIn > 0) {
+ assert(inData + chunkIn <= end);
+ assert(outPos + chunkOut <= *outLen);
+ outPos += lzf_decompress(inData, chunkIn, out + outPos, chunkOut);
+ inData += chunkIn;
+ } else {
+ assert(inData + chunkOut <= end);
+ assert(outPos + chunkOut <= *outLen);
+ memcpy(out + outPos, inData, chunkOut);
+ inData += chunkOut;
+ outPos += chunkOut;
+ }
+ }
+ return out;
+}
+
void * DbgContext::GetReadPixelsBuffer(const unsigned size)
{
if (lzf_refBufSize < size + 8) {
diff --git a/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp b/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp
index 40478c3..50f70f7 100644
--- a/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp
+++ b/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp
@@ -477,6 +477,7 @@
case 1:
case 2:
case 3:
+ case 4:
return true;
default:
return false;
@@ -488,6 +489,7 @@
const Message_Prop Message::TimeMode;
const Message_Prop Message::ExpectResponse;
const Message_Prop Message::CaptureSwap;
+const Message_Prop Message::GLConstant;
const Message_Prop Message::Prop_MIN;
const Message_Prop Message::Prop_MAX;
const int Message::Prop_ARRAYSIZE;
@@ -975,7 +977,7 @@
if (input->ExpectTag(208)) goto parse_image_width;
break;
}
-
+
// optional int32 image_width = 26;
case 26: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -991,7 +993,7 @@
if (input->ExpectTag(216)) goto parse_image_height;
break;
}
-
+
// optional int32 image_height = 27;
case 27: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -1139,12 +1141,12 @@
if (_has_bit(18)) {
::google::protobuf::internal::WireFormatLite::WriteInt32(26, this->image_width(), output);
}
-
+
// optional int32 image_height = 27;
if (_has_bit(19)) {
::google::protobuf::internal::WireFormatLite::WriteInt32(27, this->image_height(), output);
}
-
+
}
int Message::ByteSize() const {
@@ -1282,14 +1284,14 @@
::google::protobuf::internal::WireFormatLite::Int32Size(
this->image_width());
}
-
+
// optional int32 image_height = 27;
if (has_image_height()) {
total_size += 2 +
::google::protobuf::internal::WireFormatLite::Int32Size(
this->image_height());
}
-
+
// optional float time = 11;
if (has_time()) {
total_size += 1 + 4;
diff --git a/opengl/libs/GLES2_dbg/src/debugger_message.pb.h b/opengl/libs/GLES2_dbg/src/debugger_message.pb.h
index 4ccfebb..5c94664 100644
--- a/opengl/libs/GLES2_dbg/src/debugger_message.pb.h
+++ b/opengl/libs/GLES2_dbg/src/debugger_message.pb.h
@@ -258,11 +258,12 @@
Message_Prop_CaptureDraw = 0,
Message_Prop_TimeMode = 1,
Message_Prop_ExpectResponse = 2,
- Message_Prop_CaptureSwap = 3
+ Message_Prop_CaptureSwap = 3,
+ Message_Prop_GLConstant = 4
};
bool Message_Prop_IsValid(int value);
const Message_Prop Message_Prop_Prop_MIN = Message_Prop_CaptureDraw;
-const Message_Prop Message_Prop_Prop_MAX = Message_Prop_CaptureSwap;
+const Message_Prop Message_Prop_Prop_MAX = Message_Prop_GLConstant;
const int Message_Prop_Prop_ARRAYSIZE = Message_Prop_Prop_MAX + 1;
// ===================================================================
@@ -544,6 +545,7 @@
static const Prop TimeMode = Message_Prop_TimeMode;
static const Prop ExpectResponse = Message_Prop_ExpectResponse;
static const Prop CaptureSwap = Message_Prop_CaptureSwap;
+ static const Prop GLConstant = Message_Prop_GLConstant;
static inline bool Prop_IsValid(int value) {
return Message_Prop_IsValid(value);
}
@@ -691,14 +693,14 @@
static const int kImageWidthFieldNumber = 26;
inline ::google::protobuf::int32 image_width() const;
inline void set_image_width(::google::protobuf::int32 value);
-
+
// optional int32 image_height = 27;
inline bool has_image_height() const;
inline void clear_image_height();
static const int kImageHeightFieldNumber = 27;
inline ::google::protobuf::int32 image_height() const;
inline void set_image_height(::google::protobuf::int32 value);
-
+
// optional float time = 11;
inline bool has_time() const;
inline void clear_time();
diff --git a/opengl/libs/GLES2_dbg/src/header.h b/opengl/libs/GLES2_dbg/src/header.h
index c9e6c41..f2b1fa6 100644
--- a/opengl/libs/GLES2_dbg/src/header.h
+++ b/opengl/libs/GLES2_dbg/src/header.h
@@ -73,8 +73,9 @@
};
struct DbgContext {
-private:
static const unsigned int LZF_CHUNK_SIZE = 256 * 1024;
+
+private:
char * lzf_buf; // malloc / free; for lzf chunk compression and other uses
// used as buffer and reference frame for ReadPixels; malloc/free
@@ -129,6 +130,8 @@
void Fetch(const unsigned index, std::string * const data) const;
void Compress(const void * in_data, unsigned in_len, std::string * const outStr);
+ static unsigned char * Decompress(const void * in, const unsigned int inLen,
+ unsigned int * const outLen); // malloc/free
void * GetReadPixelsBuffer(const unsigned size);
bool IsReadPixelBuffer(const void * const ptr) {
return ptr == lzf_ref[lzf_readIndex];
diff --git a/opengl/libs/GLES2_dbg/src/server.cpp b/opengl/libs/GLES2_dbg/src/server.cpp
index f13d6cc..0c711bf 100644
--- a/opengl/libs/GLES2_dbg/src/server.cpp
+++ b/opengl/libs/GLES2_dbg/src/server.cpp
@@ -159,8 +159,17 @@
float Send(const glesv2debugger::Message & msg, glesv2debugger::Message & cmd)
{
+ // TODO: use per DbgContext send/receive buffer and async socket
+ // instead of mutex and blocking io; watch out for large messages
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
- pthread_mutex_lock(&mutex); // TODO: this is just temporary
+ struct Autolock {
+ Autolock() {
+ pthread_mutex_lock(&mutex);
+ }
+ ~Autolock() {
+ pthread_mutex_unlock(&mutex);
+ }
+ } autolock;
if (msg.function() != glesv2debugger::Message_Function_ACK)
assert(msg.has_context_id() && msg.context_id() != 0);
@@ -176,7 +185,6 @@
Die("MAX_FILE_SIZE reached");
}
}
- pthread_mutex_unlock(&mutex);
return 0;
}
int sent = -1;
@@ -186,13 +194,17 @@
Die("Failed to send message length");
}
nsecs_t c0 = systemTime(timeMode);
- sent = send(clientSock, str.c_str(), str.length(), 0);
+ sent = send(clientSock, str.data(), str.length(), 0);
float t = (float)ns2ms(systemTime(timeMode) - c0);
if (sent != str.length()) {
LOGD("actual sent=%d expected=%d clientSock=%d", sent, str.length(), clientSock);
Die("Failed to send message");
}
-
+ // TODO: factor Receive & TryReceive out and into MessageLoop, or add control argument.
+ // mean while, if server is sending a SETPROP then don't try to receive,
+ // because server will not be processing received command
+ if (msg.function() == msg.SETPROP)
+ return t;
// try to receive commands even though not expecting response,
// since client can send SETPROP and other commands anytime
if (!msg.expect_response()) {
@@ -204,8 +216,6 @@
}
} else
Receive(cmd);
-
- pthread_mutex_unlock(&mutex);
return t;
}
@@ -246,8 +256,9 @@
msg.set_function(function);
// when not exectResponse, set cmd to CONTINUE then SKIP
+ // cmd will be overwritten by received command
cmd.set_function(glesv2debugger::Message_Function_CONTINUE);
- cmd.set_expect_response(false);
+ cmd.set_expect_response(expectResponse);
glesv2debugger::Message_Function oldCmd = cmd.function();
Send(msg, cmd);
expectResponse = cmd.expect_response();
diff --git a/opengl/libs/GLES2_dbg/src/vertex.cpp b/opengl/libs/GLES2_dbg/src/vertex.cpp
index 7edc050..029ee3b 100644
--- a/opengl/libs/GLES2_dbg/src/vertex.cpp
+++ b/opengl/libs/GLES2_dbg/src/vertex.cpp
@@ -43,10 +43,8 @@
void * pixels = NULL;
int viewport[4] = {};
- if (!expectResponse) {
- cmd.set_function(glesv2debugger::Message_Function_CONTINUE);
- cmd.set_expect_response(false);
- }
+ cmd.set_function(glesv2debugger::Message_Function_CONTINUE);
+ cmd.set_expect_response(expectResponse);
glesv2debugger::Message_Function oldCmd = cmd.function();
Send(msg, cmd);
expectResponse = cmd.expect_response();
@@ -61,8 +59,6 @@
msg.set_function(glesv2debugger::Message_Function_glDrawArrays);
msg.set_type(glesv2debugger::Message_Type_AfterCall);
msg.set_expect_response(expectResponse);
- if (!expectResponse)
- cmd.set_function(glesv2debugger::Message_Function_SKIP);
if (!expectResponse) {
cmd.set_function(glesv2debugger::Message_Function_SKIP);
cmd.set_expect_response(false);
@@ -154,10 +150,8 @@
void * pixels = NULL;
int viewport[4] = {};
- if (!expectResponse) {
- cmd.set_function(glesv2debugger::Message_Function_CONTINUE);
- cmd.set_expect_response(false);
- }
+ cmd.set_function(glesv2debugger::Message_Function_CONTINUE);
+ cmd.set_expect_response(expectResponse);
glesv2debugger::Message_Function oldCmd = cmd.function();
Send(msg, cmd);
expectResponse = cmd.expect_response();
@@ -172,8 +166,6 @@
msg.set_function(glesv2debugger::Message_Function_glDrawElements);
msg.set_type(glesv2debugger::Message_Type_AfterCall);
msg.set_expect_response(expectResponse);
- if (!expectResponse)
- cmd.set_function(glesv2debugger::Message_Function_SKIP);
if (!expectResponse) {
cmd.set_function(glesv2debugger::Message_Function_SKIP);
cmd.set_expect_response(false);
diff --git a/opengl/libs/GLES2_dbg/test/Android.mk b/opengl/libs/GLES2_dbg/test/Android.mk
new file mode 100644
index 0000000..14a84b4
--- /dev/null
+++ b/opengl/libs/GLES2_dbg/test/Android.mk
@@ -0,0 +1,39 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH) \
+ $(LOCAL_PATH)/../src \
+ $(LOCAL_PATH)/../../ \
+ external/gtest/include \
+ external/stlport/stlport \
+ external/protobuf/src \
+ bionic \
+ external \
+#
+
+LOCAL_SRC_FILES:= \
+ test_main.cpp \
+ test_server.cpp \
+ test_socket.cpp \
+#
+
+LOCAL_SHARED_LIBRARIES := libcutils libutils libGLESv2_dbg libstlport
+LOCAL_STATIC_LIBRARIES := libgtest libprotobuf-cpp-2.3.0-lite liblzf
+LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE:= libGLESv2_dbg_test
+
+ifeq ($(ARCH_ARM_HAVE_TLS_REGISTER),true)
+ LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
+endif
+ifneq ($(TARGET_SIMULATOR),true)
+ LOCAL_C_INCLUDES += bionic/libc/private
+endif
+
+LOCAL_CFLAGS += -DLOG_TAG=\"libEGL\"
+LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+LOCAL_CFLAGS += -fvisibility=hidden
+
+include $(BUILD_EXECUTABLE)
+
diff --git a/opengl/libs/GLES2_dbg/test/test_main.cpp b/opengl/libs/GLES2_dbg/test/test_main.cpp
new file mode 100644
index 0000000..058bea4
--- /dev/null
+++ b/opengl/libs/GLES2_dbg/test/test_main.cpp
@@ -0,0 +1,234 @@
+/*
+ ** Copyright 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 "header.h"
+#include "gtest/gtest.h"
+#include "hooks.h"
+
+namespace
+{
+
+// The fixture for testing class Foo.
+class DbgContextTest : public ::testing::Test
+{
+protected:
+ android::DbgContext dbg;
+ gl_hooks_t hooks;
+
+ DbgContextTest()
+ : dbg(1, &hooks, 32, GL_RGBA, GL_UNSIGNED_BYTE) {
+ // You can do set-up work for each test here.
+ hooks.gl.glGetError = GetError;
+ }
+
+ static GLenum GetError() {
+ return GL_NO_ERROR;
+ }
+
+ virtual ~DbgContextTest() {
+ // You can do clean-up work that doesn't throw exceptions here.
+ }
+
+ // If the constructor and destructor are not enough for setting up
+ // and cleaning up each test, you can define the following methods:
+
+ virtual void SetUp() {
+ // Code here will be called immediately after the constructor (right
+ // before each test).
+ }
+
+ virtual void TearDown() {
+ // Code here will be called immediately after each test (right
+ // before the destructor).
+ }
+};
+
+TEST_F(DbgContextTest, GetReadPixelBuffer)
+{
+ const unsigned int bufferSize = 512;
+ // test that it's allocating two buffers and swapping them
+ void * const buffer0 = dbg.GetReadPixelsBuffer(bufferSize);
+ ASSERT_NE((void *)NULL, buffer0);
+ for (unsigned int i = 0; i < bufferSize / sizeof(unsigned int); i++) {
+ EXPECT_EQ(0, ((unsigned int *)buffer0)[i])
+ << "GetReadPixelsBuffer should allocate and zero";
+ ((unsigned int *)buffer0)[i] = i * 13;
+ }
+
+ void * const buffer1 = dbg.GetReadPixelsBuffer(bufferSize);
+ ASSERT_NE((void *)NULL, buffer1);
+ EXPECT_NE(buffer0, buffer1);
+ for (unsigned int i = 0; i < bufferSize / sizeof(unsigned int); i++) {
+ EXPECT_EQ(0, ((unsigned int *)buffer1)[i])
+ << "GetReadPixelsBuffer should allocate and zero";
+ ((unsigned int *)buffer1)[i] = i * 17;
+ }
+
+ void * const buffer2 = dbg.GetReadPixelsBuffer(bufferSize);
+ EXPECT_EQ(buffer2, buffer0);
+ for (unsigned int i = 0; i < bufferSize / sizeof(unsigned int); i++)
+ EXPECT_EQ(i * 13, ((unsigned int *)buffer2)[i])
+ << "GetReadPixelsBuffer should swap buffers";
+
+ void * const buffer3 = dbg.GetReadPixelsBuffer(bufferSize);
+ EXPECT_EQ(buffer3, buffer1);
+ for (unsigned int i = 0; i < bufferSize / sizeof(unsigned int); i++)
+ EXPECT_EQ(i * 17, ((unsigned int *)buffer3)[i])
+ << "GetReadPixelsBuffer should swap buffers";
+
+ void * const buffer4 = dbg.GetReadPixelsBuffer(bufferSize);
+ EXPECT_NE(buffer3, buffer4);
+ EXPECT_EQ(buffer0, buffer2);
+ EXPECT_EQ(buffer1, buffer3);
+ EXPECT_EQ(buffer2, buffer4);
+
+ // it reallocs as necessary; 0 size may result in NULL
+ for (unsigned int i = 0; i < 42; i++) {
+ void * const buffer = dbg.GetReadPixelsBuffer(((i & 7)) << 20);
+ EXPECT_NE((void *)NULL, buffer)
+ << "should be able to get a variety of reasonable sizes";
+ EXPECT_TRUE(dbg.IsReadPixelBuffer(buffer));
+ }
+}
+
+TEST_F(DbgContextTest, CompressReadPixelBuffer)
+{
+ const unsigned int bufferSize = dbg.LZF_CHUNK_SIZE * 4 + 33;
+ std::string out;
+ unsigned char * buffer = (unsigned char *)dbg.GetReadPixelsBuffer(bufferSize);
+ for (unsigned int i = 0; i < bufferSize; i++)
+ buffer[i] = i * 13;
+ dbg.CompressReadPixelBuffer(&out);
+ uint32_t decompSize = 0;
+ ASSERT_LT(12, out.length()); // at least written chunk header
+ ASSERT_EQ(bufferSize, *(uint32_t *)out.data())
+ << "total decompressed size should be as requested in GetReadPixelsBuffer";
+ for (unsigned int i = 4; i < out.length();) {
+ const uint32_t outSize = *(uint32_t *)(out.data() + i);
+ i += 4;
+ const uint32_t inSize = *(uint32_t *)(out.data() + i);
+ i += 4;
+ if (inSize == 0)
+ i += outSize; // chunk not compressed
+ else
+ i += inSize; // skip the actual compressed chunk
+ decompSize += outSize;
+ }
+ ASSERT_EQ(bufferSize, decompSize);
+ decompSize = 0;
+
+ unsigned char * decomp = dbg.Decompress(out.data(), out.length(), &decompSize);
+ ASSERT_EQ(decompSize, bufferSize);
+ for (unsigned int i = 0; i < bufferSize; i++)
+ EXPECT_EQ((unsigned char)(i * 13), decomp[i]) << "xor with 0 ref is identity";
+ free(decomp);
+
+ buffer = (unsigned char *)dbg.GetReadPixelsBuffer(bufferSize);
+ for (unsigned int i = 0; i < bufferSize; i++)
+ buffer[i] = i * 13;
+ out.clear();
+ dbg.CompressReadPixelBuffer(&out);
+ decompSize = 0;
+ decomp = dbg.Decompress(out.data(), out.length(), &decompSize);
+ ASSERT_EQ(decompSize, bufferSize);
+ for (unsigned int i = 0; i < bufferSize; i++)
+ EXPECT_EQ(0, decomp[i]) << "xor with same ref is 0";
+ free(decomp);
+
+ buffer = (unsigned char *)dbg.GetReadPixelsBuffer(bufferSize);
+ for (unsigned int i = 0; i < bufferSize; i++)
+ buffer[i] = i * 19;
+ out.clear();
+ dbg.CompressReadPixelBuffer(&out);
+ decompSize = 0;
+ decomp = dbg.Decompress(out.data(), out.length(), &decompSize);
+ ASSERT_EQ(decompSize, bufferSize);
+ for (unsigned int i = 0; i < bufferSize; i++)
+ EXPECT_EQ((unsigned char)(i * 13) ^ (unsigned char)(i * 19), decomp[i])
+ << "xor ref";
+ free(decomp);
+}
+
+TEST_F(DbgContextTest, UseProgram)
+{
+ static const GLuint _program = 74568;
+ static const struct Attribute {
+ const char * name;
+ GLint location;
+ GLint size;
+ GLenum type;
+ } _attributes [] = {
+ {"aaa", 2, 2, GL_FLOAT_VEC2},
+ {"bb", 6, 2, GL_FLOAT_MAT2},
+ {"c", 1, 1, GL_FLOAT},
+ };
+ static const unsigned int _attributeCount = sizeof(_attributes) / sizeof(*_attributes);
+ struct GL {
+ static void GetProgramiv(GLuint program, GLenum pname, GLint* params) {
+ EXPECT_EQ(_program, program);
+ ASSERT_NE((GLint *)NULL, params);
+ switch (pname) {
+ case GL_ACTIVE_ATTRIBUTES:
+ *params = _attributeCount;
+ return;
+ case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
+ *params = 4; // includes NULL terminator
+ return;
+ default:
+ ADD_FAILURE() << "not handled pname: " << pname;
+ }
+ }
+
+ static GLint GetAttribLocation(GLuint program, const GLchar* name) {
+ EXPECT_EQ(_program, program);
+ for (unsigned int i = 0; i < _attributeCount; i++)
+ if (!strcmp(name, _attributes[i].name))
+ return _attributes[i].location;
+ ADD_FAILURE() << "unknown attribute name: " << name;
+ return -1;
+ }
+
+ static void GetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize,
+ GLsizei* length, GLint* size, GLenum* type, GLchar* name) {
+ EXPECT_EQ(_program, program);
+ ASSERT_LT(index, _attributeCount);
+ const Attribute & att = _attributes[index];
+ ASSERT_GE(bufsize, strlen(att.name) + 1);
+ ASSERT_NE((GLint *)NULL, size);
+ ASSERT_NE((GLenum *)NULL, type);
+ ASSERT_NE((GLchar *)NULL, name);
+ strcpy(name, att.name);
+ if (length)
+ *length = strlen(name) + 1;
+ *size = att.size;
+ *type = att.type;
+ }
+ };
+ hooks.gl.glGetProgramiv = GL::GetProgramiv;
+ hooks.gl.glGetAttribLocation = GL::GetAttribLocation;
+ hooks.gl.glGetActiveAttrib = GL::GetActiveAttrib;
+ dbg.glUseProgram(_program);
+ EXPECT_EQ(10, dbg.maxAttrib);
+ dbg.glUseProgram(0);
+ EXPECT_EQ(0, dbg.maxAttrib);
+}
+} // namespace
+
+int main(int argc, char **argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/opengl/libs/GLES2_dbg/test/test_server.cpp b/opengl/libs/GLES2_dbg/test/test_server.cpp
new file mode 100644
index 0000000..b6401e0
--- /dev/null
+++ b/opengl/libs/GLES2_dbg/test/test_server.cpp
@@ -0,0 +1,251 @@
+/*
+ ** Copyright 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 "header.h"
+#include "gtest/gtest.h"
+#include "egl_tls.h"
+#include "hooks.h"
+
+namespace android
+{
+extern FILE * file;
+extern unsigned int MAX_FILE_SIZE;
+extern pthread_key_t dbgEGLThreadLocalStorageKey;
+};
+
+// tmpfile fails, so need to manually make a writable file first
+static const char * filePath = "/data/local/tmp/dump.gles2dbg";
+
+class ServerFileTest : public ::testing::Test
+{
+protected:
+ ServerFileTest() { }
+
+ virtual ~ServerFileTest() { }
+
+ virtual void SetUp() {
+ MAX_FILE_SIZE = 8 << 20;
+ ASSERT_EQ((FILE *)NULL, file);
+ file = fopen("/data/local/tmp/dump.gles2dbg", "wb+");
+ ASSERT_NE((FILE *)NULL, file) << "make sure file is writable: "
+ << filePath;
+ }
+
+ virtual void TearDown() {
+ ASSERT_NE((FILE *)NULL, file);
+ fclose(file);
+ file = NULL;
+ }
+
+ void Read(glesv2debugger::Message & msg) const {
+ msg.Clear();
+ uint32_t len = 0;
+ ASSERT_EQ(sizeof(len), fread(&len, 1, sizeof(len), file));
+ ASSERT_GT(len, 0u);
+ char * buffer = new char [len];
+ ASSERT_EQ(len, fread(buffer, 1, len, file));
+ msg.ParseFromArray(buffer, len);
+ delete buffer;
+ }
+
+ void CheckNoAvailable() {
+ const long pos = ftell(file);
+ fseek(file, 0, SEEK_END);
+ EXPECT_EQ(pos, ftell(file)) << "check no available";
+ }
+};
+
+TEST_F(ServerFileTest, Send)
+{
+ glesv2debugger::Message msg, cmd, read;
+ msg.set_context_id(1);
+ msg.set_function(msg.glFinish);
+ msg.set_expect_response(false);
+ msg.set_type(msg.BeforeCall);
+ rewind(file);
+ android::Send(msg, cmd);
+ rewind(file);
+ Read(read);
+ EXPECT_EQ(msg.context_id(), read.context_id());
+ EXPECT_EQ(msg.function(), read.function());
+ EXPECT_EQ(msg.expect_response(), read.expect_response());
+ EXPECT_EQ(msg.type(), read.type());
+}
+
+TEST_F(ServerFileTest, CreateDbgContext)
+{
+ gl_hooks_t hooks;
+ struct Constant {
+ GLenum pname;
+ GLint param;
+ };
+ static const Constant constants [] = {
+ {GL_MAX_VERTEX_ATTRIBS, 16},
+ {GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, 32},
+ {GL_IMPLEMENTATION_COLOR_READ_FORMAT, GL_RGBA},
+ {GL_IMPLEMENTATION_COLOR_READ_TYPE, GL_UNSIGNED_BYTE},
+ };
+ struct HookMock {
+ static void GetIntegerv(GLenum pname, GLint* params) {
+ ASSERT_TRUE(params != NULL);
+ for (unsigned int i = 0; i < sizeof(constants) / sizeof(*constants); i++)
+ if (pname == constants[i].pname) {
+ *params = constants[i].param;
+ return;
+ }
+ FAIL() << "GetIntegerv unknown pname: " << pname;
+ }
+ static GLenum GetError() {
+ return GL_NO_ERROR;
+ }
+ };
+ hooks.gl.glGetError = HookMock::GetError;
+ hooks.gl.glGetIntegerv = HookMock::GetIntegerv;
+ DbgContext * const dbg = CreateDbgContext(-1, 1, &hooks);
+ ASSERT_TRUE(dbg != NULL);
+ EXPECT_TRUE(dbg->vertexAttribs != NULL);
+
+ rewind(file);
+ glesv2debugger::Message read;
+ for (unsigned int i = 0; i < 2; i++) {
+ Read(read);
+ EXPECT_EQ(reinterpret_cast<int>(dbg), read.context_id());
+ EXPECT_FALSE(read.expect_response());
+ EXPECT_EQ(read.Response, read.type());
+ EXPECT_EQ(read.SETPROP, read.function());
+ EXPECT_EQ(read.GLConstant, read.prop());
+ GLint expectedConstant = 0;
+ HookMock::GetIntegerv(read.arg0(), &expectedConstant);
+ EXPECT_EQ(expectedConstant, read.arg1());
+ }
+ CheckNoAvailable();
+ DestroyDbgContext(dbg);
+}
+
+void * glNoop()
+{
+ return 0;
+}
+
+class ServerFileContextTest : public ServerFileTest
+{
+protected:
+ tls_t tls;
+ gl_hooks_t hooks;
+
+ ServerFileContextTest() { }
+
+ virtual ~ServerFileContextTest() { }
+
+ virtual void SetUp() {
+ ServerFileTest::SetUp();
+
+ if (dbgEGLThreadLocalStorageKey == -1)
+ pthread_key_create(&dbgEGLThreadLocalStorageKey, NULL);
+ ASSERT_NE(-1, dbgEGLThreadLocalStorageKey);
+ tls.dbg = new DbgContext(1, &hooks, 32, GL_RGBA, GL_UNSIGNED_BYTE);
+ ASSERT_NE((void *)NULL, tls.dbg);
+ pthread_setspecific(dbgEGLThreadLocalStorageKey, &tls);
+ for (unsigned int i = 0; i < sizeof(hooks) / sizeof(void *); i++)
+ ((void **)&hooks)[i] = reinterpret_cast<void *>(glNoop);
+ }
+
+ virtual void TearDown() {
+ ServerFileTest::TearDown();
+ }
+};
+
+TEST_F(ServerFileContextTest, MessageLoop)
+{
+ static const int arg0 = 45;
+ static const float arg7 = -87.2331f;
+ static const int arg8 = -3;
+ static const int * ret = reinterpret_cast<int *>(870);
+
+ struct Caller : public FunctionCall {
+ const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+ msg.set_arg0(arg0);
+ msg.set_arg7((int &)arg7);
+ msg.set_arg8(arg8);
+ return ret;
+ }
+ } caller;
+ const int contextId = reinterpret_cast<int>(tls.dbg);
+ glesv2debugger::Message msg, read;
+
+ EXPECT_EQ(ret, MessageLoop(caller, msg, msg.glFinish));
+
+ rewind(file);
+ Read(read);
+ EXPECT_EQ(contextId, read.context_id());
+ EXPECT_EQ(read.glFinish, read.function());
+ EXPECT_EQ(false, read.expect_response());
+ EXPECT_EQ(read.BeforeCall, read.type());
+
+ Read(read);
+ EXPECT_EQ(contextId, read.context_id());
+ EXPECT_EQ(read.glFinish, read.function());
+ EXPECT_EQ(false, read.expect_response());
+ EXPECT_EQ(read.AfterCall, read.type());
+ EXPECT_TRUE(read.has_time());
+ EXPECT_EQ(arg0, read.arg0());
+ const int readArg7 = read.arg7();
+ EXPECT_EQ(arg7, (float &)readArg7);
+ EXPECT_EQ(arg8, read.arg8());
+
+ const long pos = ftell(file);
+ fseek(file, 0, SEEK_END);
+ EXPECT_EQ(pos, ftell(file))
+ << "should only write the BeforeCall and AfterCall messages";
+}
+
+TEST_F(ServerFileContextTest, DisableEnableVertexAttribArray)
+{
+ Debug_glEnableVertexAttribArray(tls.dbg->MAX_VERTEX_ATTRIBS + 2); // should just ignore invalid index
+
+ glesv2debugger::Message read;
+ rewind(file);
+ Read(read);
+ EXPECT_EQ(read.glEnableVertexAttribArray, read.function());
+ EXPECT_EQ(tls.dbg->MAX_VERTEX_ATTRIBS + 2, read.arg0());
+ Read(read);
+
+ rewind(file);
+ Debug_glDisableVertexAttribArray(tls.dbg->MAX_VERTEX_ATTRIBS + 4); // should just ignore invalid index
+ rewind(file);
+ Read(read);
+ Read(read);
+
+ for (unsigned int i = 0; i < tls.dbg->MAX_VERTEX_ATTRIBS; i += 5) {
+ rewind(file);
+ Debug_glEnableVertexAttribArray(i);
+ EXPECT_TRUE(tls.dbg->vertexAttribs[i].enabled);
+ rewind(file);
+ Read(read);
+ EXPECT_EQ(read.glEnableVertexAttribArray, read.function());
+ EXPECT_EQ(i, read.arg0());
+ Read(read);
+
+ rewind(file);
+ Debug_glDisableVertexAttribArray(i);
+ EXPECT_FALSE(tls.dbg->vertexAttribs[i].enabled);
+ rewind(file);
+ Read(read);
+ EXPECT_EQ(read.glDisableVertexAttribArray, read.function());
+ EXPECT_EQ(i, read.arg0());
+ Read(read);
+ }
+}
diff --git a/opengl/libs/GLES2_dbg/test/test_socket.cpp b/opengl/libs/GLES2_dbg/test/test_socket.cpp
new file mode 100644
index 0000000..617292e
--- /dev/null
+++ b/opengl/libs/GLES2_dbg/test/test_socket.cpp
@@ -0,0 +1,474 @@
+/*
+ ** Copyright 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 <sys/socket.h>
+#include <sys/ioctl.h>
+
+#include "header.h"
+#include "gtest/gtest.h"
+#include "egl_tls.h"
+#include "hooks.h"
+
+namespace android
+{
+extern int serverSock, clientSock;
+extern pthread_key_t dbgEGLThreadLocalStorageKey;
+};
+
+void * glNoop();
+
+class SocketContextTest : public ::testing::Test
+{
+protected:
+ tls_t tls;
+ gl_hooks_t hooks;
+ int sock;
+ char * buffer;
+ unsigned int bufferSize;
+
+ SocketContextTest() : sock(-1) {
+ }
+
+ virtual ~SocketContextTest() {
+ }
+
+ virtual void SetUp() {
+ if (dbgEGLThreadLocalStorageKey == -1)
+ pthread_key_create(&dbgEGLThreadLocalStorageKey, NULL);
+ ASSERT_NE(-1, dbgEGLThreadLocalStorageKey);
+ tls.dbg = new DbgContext(1, &hooks, 32, GL_RGBA, GL_UNSIGNED_BYTE);
+ ASSERT_TRUE(tls.dbg != NULL);
+ pthread_setspecific(dbgEGLThreadLocalStorageKey, &tls);
+ for (unsigned int i = 0; i < sizeof(hooks) / sizeof(void *); i++)
+ ((void **)&hooks)[i] = (void *)glNoop;
+
+ int socks[2] = {-1, -1};
+ ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, socks));
+ clientSock = socks[0];
+ sock = socks[1];
+
+ bufferSize = 128;
+ buffer = new char [128];
+ ASSERT_NE((char *)NULL, buffer);
+ }
+
+ virtual void TearDown() {
+ close(sock);
+ close(clientSock);
+ clientSock = -1;
+ delete buffer;
+ }
+
+ void Write(glesv2debugger::Message & msg) const {
+ msg.set_context_id((int)tls.dbg);
+ msg.set_type(msg.Response);
+ ASSERT_TRUE(msg.has_context_id());
+ ASSERT_TRUE(msg.has_function());
+ ASSERT_TRUE(msg.has_type());
+ ASSERT_TRUE(msg.has_expect_response());
+ static std::string str;
+ msg.SerializeToString(&str);
+ const uint32_t len = str.length();
+ ASSERT_EQ(sizeof(len), send(sock, &len, sizeof(len), 0));
+ ASSERT_EQ(str.length(), send(sock, str.data(), str.length(), 0));
+ }
+
+ void Read(glesv2debugger::Message & msg) {
+ int available = 0;
+ ASSERT_EQ(0, ioctl(sock, FIONREAD, &available));
+ ASSERT_GT(available, 0);
+ uint32_t len = 0;
+ ASSERT_EQ(sizeof(len), recv(sock, &len, sizeof(len), 0));
+ if (len > bufferSize) {
+ bufferSize = len;
+ buffer = new char[bufferSize];
+ ASSERT_TRUE(buffer != NULL);
+ }
+ ASSERT_EQ(len, recv(sock, buffer, len, 0));
+ msg.Clear();
+ msg.ParseFromArray(buffer, len);
+ ASSERT_TRUE(msg.has_context_id());
+ ASSERT_TRUE(msg.has_function());
+ ASSERT_TRUE(msg.has_type());
+ ASSERT_TRUE(msg.has_expect_response());
+ }
+
+ void CheckNoAvailable() {
+ int available = 0;
+ ASSERT_EQ(0, ioctl(sock, FIONREAD, &available));
+ ASSERT_EQ(available, 0);
+ }
+};
+
+TEST_F(SocketContextTest, MessageLoopSkip)
+{
+ static const int arg0 = 45;
+ static const float arg7 = -87.2331f;
+ static const int arg8 = -3;
+ static const int * ret = (int *)870;
+
+ struct Caller : public FunctionCall {
+ const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+ msg.set_arg0(arg0);
+ msg.set_arg7((int &)arg7);
+ msg.set_arg8(arg8);
+ return ret;
+ }
+ } caller;
+ glesv2debugger::Message msg, read, cmd;
+ tls.dbg->expectResponse.Bit(msg.glFinish, true);
+
+ cmd.set_function(cmd.SKIP);
+ cmd.set_expect_response(false);
+ Write(cmd);
+
+ EXPECT_NE(ret, MessageLoop(caller, msg, msg.glFinish));
+
+ Read(read);
+ EXPECT_EQ(read.glFinish, read.function());
+ EXPECT_EQ(read.BeforeCall, read.type());
+ EXPECT_NE(arg0, read.arg0());
+ EXPECT_NE((int &)arg7, read.arg7());
+ EXPECT_NE(arg8, read.arg8());
+
+ CheckNoAvailable();
+}
+
+TEST_F(SocketContextTest, MessageLoopContinue)
+{
+ static const int arg0 = GL_FRAGMENT_SHADER;
+ static const int ret = -342;
+ struct Caller : public FunctionCall {
+ const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+ msg.set_ret(ret);
+ return (int *)ret;
+ }
+ } caller;
+ glesv2debugger::Message msg, read, cmd;
+ tls.dbg->expectResponse.Bit(msg.glCreateShader, true);
+
+ cmd.set_function(cmd.CONTINUE);
+ cmd.set_expect_response(false); // MessageLoop should automatically skip after continue
+ Write(cmd);
+
+ msg.set_arg0(arg0);
+ EXPECT_EQ((int *)ret, MessageLoop(caller, msg, msg.glCreateShader));
+
+ Read(read);
+ EXPECT_EQ(read.glCreateShader, read.function());
+ EXPECT_EQ(read.BeforeCall, read.type());
+ EXPECT_EQ(arg0, read.arg0());
+
+ Read(read);
+ EXPECT_EQ(read.glCreateShader, read.function());
+ EXPECT_EQ(read.AfterCall, read.type());
+ EXPECT_EQ(ret, read.ret());
+
+ CheckNoAvailable();
+}
+
+TEST_F(SocketContextTest, MessageLoopGenerateCall)
+{
+ static const int ret = -342;
+ static unsigned int createShader, createProgram;
+ createShader = 0;
+ createProgram = 0;
+ struct Caller : public FunctionCall {
+ const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+ const int r = (int)_c->glCreateProgram();
+ msg.set_ret(r);
+ return (int *)r;
+ }
+ static GLuint CreateShader(const GLenum type) {
+ createShader++;
+ return type;
+ }
+ static GLuint CreateProgram() {
+ createProgram++;
+ return ret;
+ }
+ } caller;
+ glesv2debugger::Message msg, read, cmd;
+ hooks.gl.glCreateShader = caller.CreateShader;
+ hooks.gl.glCreateProgram = caller.CreateProgram;
+ tls.dbg->expectResponse.Bit(msg.glCreateProgram, true);
+
+ cmd.set_function(cmd.glCreateShader);
+ cmd.set_arg0(GL_FRAGMENT_SHADER);
+ cmd.set_expect_response(true);
+ Write(cmd);
+
+ cmd.Clear();
+ cmd.set_function(cmd.CONTINUE);
+ cmd.set_expect_response(true);
+ Write(cmd);
+
+ cmd.set_function(cmd.glCreateShader);
+ cmd.set_arg0(GL_VERTEX_SHADER);
+ cmd.set_expect_response(false); // MessageLoop should automatically skip afterwards
+ Write(cmd);
+
+ EXPECT_EQ((int *)ret, MessageLoop(caller, msg, msg.glCreateProgram));
+
+ Read(read);
+ EXPECT_EQ(read.glCreateProgram, read.function());
+ EXPECT_EQ(read.BeforeCall, read.type());
+
+ Read(read);
+ EXPECT_EQ(read.glCreateShader, read.function());
+ EXPECT_EQ(read.AfterGeneratedCall, read.type());
+ EXPECT_EQ(GL_FRAGMENT_SHADER, read.ret());
+
+ Read(read);
+ EXPECT_EQ(read.glCreateProgram, read.function());
+ EXPECT_EQ(read.AfterCall, read.type());
+ EXPECT_EQ(ret, read.ret());
+
+ Read(read);
+ EXPECT_EQ(read.glCreateShader, read.function());
+ EXPECT_EQ(read.AfterGeneratedCall, read.type());
+ EXPECT_EQ(GL_VERTEX_SHADER, read.ret());
+
+ EXPECT_EQ(2, createShader);
+ EXPECT_EQ(1, createProgram);
+
+ CheckNoAvailable();
+}
+
+TEST_F(SocketContextTest, MessageLoopSetProp)
+{
+ static const int ret = -342;
+ static unsigned int createShader, createProgram;
+ createShader = 0;
+ createProgram = 0;
+ struct Caller : public FunctionCall {
+ const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+ const int r = (int)_c->glCreateProgram();
+ msg.set_ret(r);
+ return (int *)r;
+ }
+ static GLuint CreateShader(const GLenum type) {
+ createShader++;
+ return type;
+ }
+ static GLuint CreateProgram() {
+ createProgram++;
+ return ret;
+ }
+ } caller;
+ glesv2debugger::Message msg, read, cmd;
+ hooks.gl.glCreateShader = caller.CreateShader;
+ hooks.gl.glCreateProgram = caller.CreateProgram;
+ tls.dbg->expectResponse.Bit(msg.glCreateProgram, false);
+
+ cmd.set_function(cmd.SETPROP);
+ cmd.set_prop(cmd.ExpectResponse);
+ cmd.set_arg0(cmd.glCreateProgram);
+ cmd.set_arg1(true);
+ cmd.set_expect_response(true);
+ Write(cmd);
+
+ cmd.Clear();
+ cmd.set_function(cmd.glCreateShader);
+ cmd.set_arg0(GL_FRAGMENT_SHADER);
+ cmd.set_expect_response(true);
+ Write(cmd);
+
+ cmd.set_function(cmd.SETPROP);
+ cmd.set_prop(cmd.CaptureDraw);
+ cmd.set_arg0(819);
+ cmd.set_expect_response(true);
+ Write(cmd);
+
+ cmd.Clear();
+ cmd.set_function(cmd.CONTINUE);
+ cmd.set_expect_response(true);
+ Write(cmd);
+
+ cmd.set_function(cmd.glCreateShader);
+ cmd.set_arg0(GL_VERTEX_SHADER);
+ cmd.set_expect_response(false); // MessageLoop should automatically skip afterwards
+ Write(cmd);
+
+ EXPECT_EQ((int *)ret, MessageLoop(caller, msg, msg.glCreateProgram));
+
+ EXPECT_TRUE(tls.dbg->expectResponse.Bit(msg.glCreateProgram));
+ EXPECT_EQ(819, tls.dbg->captureDraw);
+
+ Read(read);
+ EXPECT_EQ(read.glCreateProgram, read.function());
+ EXPECT_EQ(read.BeforeCall, read.type());
+
+ Read(read);
+ EXPECT_EQ(read.glCreateShader, read.function());
+ EXPECT_EQ(read.AfterGeneratedCall, read.type());
+ EXPECT_EQ(GL_FRAGMENT_SHADER, read.ret());
+
+ Read(read);
+ EXPECT_EQ(read.glCreateProgram, read.function());
+ EXPECT_EQ(read.AfterCall, read.type());
+ EXPECT_EQ(ret, read.ret());
+
+ Read(read);
+ EXPECT_EQ(read.glCreateShader, read.function());
+ EXPECT_EQ(read.AfterGeneratedCall, read.type());
+ EXPECT_EQ(GL_VERTEX_SHADER, read.ret());
+
+ EXPECT_EQ(2, createShader);
+ EXPECT_EQ(1, createProgram);
+
+ CheckNoAvailable();
+}
+
+TEST_F(SocketContextTest, TexImage2D)
+{
+ static const GLenum _target = GL_TEXTURE_2D;
+ static const GLint _level = 1, _internalformat = GL_RGBA;
+ static const GLsizei _width = 2, _height = 2;
+ static const GLint _border = 333;
+ static const GLenum _format = GL_RGB, _type = GL_UNSIGNED_SHORT_5_6_5;
+ static const short _pixels [_width * _height] = {11, 22, 33, 44};
+ static unsigned int texImage2D;
+ texImage2D = 0;
+
+ struct Caller {
+ static void TexImage2D(GLenum target, GLint level, GLint internalformat,
+ GLsizei width, GLsizei height, GLint border,
+ GLenum format, GLenum type, const GLvoid* pixels) {
+ EXPECT_EQ(_target, target);
+ EXPECT_EQ(_level, level);
+ EXPECT_EQ(_internalformat, internalformat);
+ EXPECT_EQ(_width, width);
+ EXPECT_EQ(_height, height);
+ EXPECT_EQ(_border, border);
+ EXPECT_EQ(_format, format);
+ EXPECT_EQ(_type, type);
+ EXPECT_EQ(0, memcmp(_pixels, pixels, sizeof(_pixels)));
+ texImage2D++;
+ }
+ } caller;
+ glesv2debugger::Message msg, read, cmd;
+ hooks.gl.glTexImage2D = caller.TexImage2D;
+ tls.dbg->expectResponse.Bit(msg.glTexImage2D, false);
+
+ Debug_glTexImage2D(_target, _level, _internalformat, _width, _height, _border,
+ _format, _type, _pixels);
+ EXPECT_EQ(1, texImage2D);
+
+ Read(read);
+ EXPECT_EQ(read.glTexImage2D, read.function());
+ EXPECT_EQ(read.BeforeCall, read.type());
+ EXPECT_EQ(_target, read.arg0());
+ EXPECT_EQ(_level, read.arg1());
+ EXPECT_EQ(_internalformat, read.arg2());
+ EXPECT_EQ(_width, read.arg3());
+ EXPECT_EQ(_height, read.arg4());
+ EXPECT_EQ(_border, read.arg5());
+ EXPECT_EQ(_format, read.arg6());
+ EXPECT_EQ(_type, read.arg7());
+
+ EXPECT_TRUE(read.has_data());
+ uint32_t dataLen = 0;
+ const unsigned char * data = tls.dbg->Decompress(read.data().data(),
+ read.data().length(), &dataLen);
+ EXPECT_EQ(sizeof(_pixels), dataLen);
+ if (sizeof(_pixels) == dataLen)
+ EXPECT_EQ(0, memcmp(_pixels, data, sizeof(_pixels)));
+
+ Read(read);
+ EXPECT_EQ(read.glTexImage2D, read.function());
+ EXPECT_EQ(read.AfterCall, read.type());
+
+ CheckNoAvailable();
+}
+
+TEST_F(SocketContextTest, CopyTexImage2D)
+{
+ static const GLenum _target = GL_TEXTURE_2D;
+ static const GLint _level = 1, _internalformat = GL_RGBA;
+ static const GLint _x = 9, _y = 99;
+ static const GLsizei _width = 2, _height = 3;
+ static const GLint _border = 333;
+ static const int _pixels [_width * _height] = {11, 22, 33, 44, 55, 66};
+ static unsigned int copyTexImage2D, readPixels;
+ copyTexImage2D = 0, readPixels = 0;
+
+ struct Caller {
+ static void CopyTexImage2D(GLenum target, GLint level, GLenum internalformat,
+ GLint x, GLint y, GLsizei width, GLsizei height, GLint border) {
+ EXPECT_EQ(_target, target);
+ EXPECT_EQ(_level, level);
+ EXPECT_EQ(_internalformat, internalformat);
+ EXPECT_EQ(_x, x);
+ EXPECT_EQ(_y, y);
+ EXPECT_EQ(_width, width);
+ EXPECT_EQ(_height, height);
+ EXPECT_EQ(_border, border);
+ copyTexImage2D++;
+ }
+ static void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
+ GLenum format, GLenum type, GLvoid* pixels) {
+ EXPECT_EQ(_x, x);
+ EXPECT_EQ(_y, y);
+ EXPECT_EQ(_width, width);
+ EXPECT_EQ(_height, height);
+ EXPECT_EQ(GL_RGBA, format);
+ EXPECT_EQ(GL_UNSIGNED_BYTE, type);
+ ASSERT_TRUE(pixels != NULL);
+ memcpy(pixels, _pixels, sizeof(_pixels));
+ readPixels++;
+ }
+ } caller;
+ glesv2debugger::Message msg, read, cmd;
+ hooks.gl.glCopyTexImage2D = caller.CopyTexImage2D;
+ hooks.gl.glReadPixels = caller.ReadPixels;
+ tls.dbg->expectResponse.Bit(msg.glCopyTexImage2D, false);
+
+ Debug_glCopyTexImage2D(_target, _level, _internalformat, _x, _y, _width, _height,
+ _border);
+ ASSERT_EQ(1, copyTexImage2D);
+ ASSERT_EQ(1, readPixels);
+
+ Read(read);
+ EXPECT_EQ(read.glCopyTexImage2D, read.function());
+ EXPECT_EQ(read.BeforeCall, read.type());
+ EXPECT_EQ(_target, read.arg0());
+ EXPECT_EQ(_level, read.arg1());
+ EXPECT_EQ(_internalformat, read.arg2());
+ EXPECT_EQ(_x, read.arg3());
+ EXPECT_EQ(_y, read.arg4());
+ EXPECT_EQ(_width, read.arg5());
+ EXPECT_EQ(_height, read.arg6());
+ EXPECT_EQ(_border, read.arg7());
+
+ EXPECT_TRUE(read.has_data());
+ EXPECT_EQ(read.ReferencedImage, read.data_type());
+ EXPECT_EQ(GL_RGBA, read.pixel_format());
+ EXPECT_EQ(GL_UNSIGNED_BYTE, read.pixel_type());
+ uint32_t dataLen = 0;
+ unsigned char * const data = tls.dbg->Decompress(read.data().data(),
+ read.data().length(), &dataLen);
+ ASSERT_EQ(sizeof(_pixels), dataLen);
+ for (unsigned i = 0; i < sizeof(_pixels) / sizeof(*_pixels); i++)
+ EXPECT_EQ(_pixels[i], ((const int *)data)[i]) << "xor with 0 ref is identity";
+ free(data);
+
+ Read(read);
+ EXPECT_EQ(read.glCopyTexImage2D, read.function());
+ EXPECT_EQ(read.AfterCall, read.type());
+
+ CheckNoAvailable();
+}
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
index 90865da..59b7e5a 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
@@ -38,23 +38,10 @@
#include "SurfaceFlinger.h"
// ----------------------------------------------------------------------------
-// the sim build doesn't have gettid
-
-#ifndef HAVE_GETTID
-# define gettid getpid
-#endif
-
-// ----------------------------------------------------------------------------
namespace android {
-static char const * kSleepFileName = "/sys/power/wait_for_fb_sleep";
-static char const * kWakeFileName = "/sys/power/wait_for_fb_wake";
-static char const * const kOldSleepFileName = "/sys/android_power/wait_for_fb_sleep";
-static char const * const kOldWakeFileName = "/sys/android_power/wait_for_fb_wake";
-
-// This dir exists if the framebuffer console is present, either built into
-// the kernel or loaded as a module.
-static char const * const kFbconSysDir = "/sys/class/graphics/fbcon";
+static char const * const kSleepFileName = "/sys/power/wait_for_fb_sleep";
+static char const * const kWakeFileName = "/sys/power/wait_for_fb_wake";
// ----------------------------------------------------------------------------
@@ -122,237 +109,13 @@
status_t DisplayHardwareBase::DisplayEventThread::readyToRun()
{
- if (access(kSleepFileName, R_OK) || access(kWakeFileName, R_OK)) {
- if (access(kOldSleepFileName, R_OK) || access(kOldWakeFileName, R_OK)) {
- LOGE("Couldn't open %s or %s", kSleepFileName, kWakeFileName);
- return NO_INIT;
- }
- kSleepFileName = kOldSleepFileName;
- kWakeFileName = kOldWakeFileName;
- }
return NO_ERROR;
}
status_t DisplayHardwareBase::DisplayEventThread::initCheck() const
{
- return (((access(kSleepFileName, R_OK) == 0 &&
- access(kWakeFileName, R_OK) == 0) ||
- (access(kOldSleepFileName, R_OK) == 0 &&
- access(kOldWakeFileName, R_OK) == 0)) &&
- access(kFbconSysDir, F_OK) != 0) ? NO_ERROR : NO_INIT;
-}
-
-// ----------------------------------------------------------------------------
-
-pid_t DisplayHardwareBase::ConsoleManagerThread::sSignalCatcherPid = 0;
-
-DisplayHardwareBase::ConsoleManagerThread::ConsoleManagerThread(
- const sp<SurfaceFlinger>& flinger)
- : DisplayEventThreadBase(flinger), consoleFd(-1)
-{
- sSignalCatcherPid = 0;
-
- // create a new console
- char const * const ttydev = "/dev/tty0";
- int fd = open(ttydev, O_RDWR | O_SYNC);
- if (fd<0) {
- LOGE("Can't open %s", ttydev);
- this->consoleFd = -errno;
- return;
- }
-
- // to make sure that we are in text mode
- int res = ioctl(fd, KDSETMODE, (void*) KD_TEXT);
- if (res<0) {
- LOGE("ioctl(%d, KDSETMODE, ...) failed, res %d (%s)",
- fd, res, strerror(errno));
- }
-
- // get the current console
- struct vt_stat vs;
- res = ioctl(fd, VT_GETSTATE, &vs);
- if (res<0) {
- LOGE("ioctl(%d, VT_GETSTATE, ...) failed, res %d (%s)",
- fd, res, strerror(errno));
- this->consoleFd = -errno;
- return;
- }
-
- // switch to console 7 (which is what X normaly uses)
- int vtnum = 7;
- do {
- res = ioctl(fd, VT_ACTIVATE, (void*)vtnum);
- } while(res < 0 && errno == EINTR);
- if (res<0) {
- LOGE("ioctl(%d, VT_ACTIVATE, ...) failed, %d (%s) for %d",
- fd, errno, strerror(errno), vtnum);
- this->consoleFd = -errno;
- return;
- }
-
- do {
- res = ioctl(fd, VT_WAITACTIVE, (void*)vtnum);
- } while(res < 0 && errno == EINTR);
- if (res<0) {
- LOGE("ioctl(%d, VT_WAITACTIVE, ...) failed, %d %d %s for %d",
- fd, res, errno, strerror(errno), vtnum);
- this->consoleFd = -errno;
- return;
- }
-
- // open the new console
- close(fd);
- fd = open(ttydev, O_RDWR | O_SYNC);
- if (fd<0) {
- LOGE("Can't open new console %s", ttydev);
- this->consoleFd = -errno;
- return;
- }
-
- /* disable console line buffer, echo, ... */
- struct termios ttyarg;
- ioctl(fd, TCGETS , &ttyarg);
- ttyarg.c_iflag = 0;
- ttyarg.c_lflag = 0;
- ioctl(fd, TCSETS , &ttyarg);
-
- // set up signals so we're notified when the console changes
- // we can't use SIGUSR1 because it's used by the java-vm
- vm.mode = VT_PROCESS;
- vm.waitv = 0;
- vm.relsig = SIGUSR2;
- vm.acqsig = SIGUNUSED;
- vm.frsig = 0;
-
- struct sigaction act;
- sigemptyset(&act.sa_mask);
- act.sa_handler = sigHandler;
- act.sa_flags = 0;
- sigaction(vm.relsig, &act, NULL);
-
- sigemptyset(&act.sa_mask);
- act.sa_handler = sigHandler;
- act.sa_flags = 0;
- sigaction(vm.acqsig, &act, NULL);
-
- sigset_t mask;
- sigemptyset(&mask);
- sigaddset(&mask, vm.relsig);
- sigaddset(&mask, vm.acqsig);
- sigprocmask(SIG_BLOCK, &mask, NULL);
-
- // switch to graphic mode
- res = ioctl(fd, KDSETMODE, (void*)KD_GRAPHICS);
- LOGW_IF(res<0,
- "ioctl(%d, KDSETMODE, KD_GRAPHICS) failed, res %d", fd, res);
-
- this->prev_vt_num = vs.v_active;
- this->vt_num = vtnum;
- this->consoleFd = fd;
-}
-
-DisplayHardwareBase::ConsoleManagerThread::~ConsoleManagerThread()
-{
- if (this->consoleFd >= 0) {
- int fd = this->consoleFd;
- int prev_vt_num = this->prev_vt_num;
- int res;
- ioctl(fd, KDSETMODE, (void*)KD_TEXT);
- do {
- res = ioctl(fd, VT_ACTIVATE, (void*)prev_vt_num);
- } while(res < 0 && errno == EINTR);
- do {
- res = ioctl(fd, VT_WAITACTIVE, (void*)prev_vt_num);
- } while(res < 0 && errno == EINTR);
- close(fd);
- char const * const ttydev = "/dev/tty0";
- fd = open(ttydev, O_RDWR | O_SYNC);
- ioctl(fd, VT_DISALLOCATE, 0);
- close(fd);
- }
-}
-
-status_t DisplayHardwareBase::ConsoleManagerThread::readyToRun()
-{
- if (this->consoleFd >= 0) {
- sSignalCatcherPid = gettid();
-
- sigset_t mask;
- sigemptyset(&mask);
- sigaddset(&mask, vm.relsig);
- sigaddset(&mask, vm.acqsig);
- sigprocmask(SIG_BLOCK, &mask, NULL);
-
- int res = ioctl(this->consoleFd, VT_SETMODE, &vm);
- if (res<0) {
- LOGE("ioctl(%d, VT_SETMODE, ...) failed, %d (%s)",
- this->consoleFd, errno, strerror(errno));
- }
- return NO_ERROR;
- }
- return this->consoleFd;
-}
-
-void DisplayHardwareBase::ConsoleManagerThread::requestExit()
-{
- Thread::requestExit();
- if (sSignalCatcherPid != 0) {
- // wake the thread up
- kill(sSignalCatcherPid, SIGINT);
- // wait for it...
- }
-}
-
-void DisplayHardwareBase::ConsoleManagerThread::sigHandler(int sig)
-{
- // resend the signal to our signal catcher thread
- LOGW("received signal %d in thread %d, resending to %d",
- sig, gettid(), sSignalCatcherPid);
-
- // we absolutely need the delays below because without them
- // our main thread never gets a chance to handle the signal.
- usleep(10000);
- kill(sSignalCatcherPid, sig);
- usleep(10000);
-}
-
-status_t DisplayHardwareBase::ConsoleManagerThread::releaseScreen() const
-{
- int fd = this->consoleFd;
- int err = ioctl(fd, VT_RELDISP, (void*)1);
- LOGE_IF(err<0, "ioctl(%d, VT_RELDISP, 1) failed %d (%s)",
- fd, errno, strerror(errno));
- return (err<0) ? (-errno) : status_t(NO_ERROR);
-}
-
-bool DisplayHardwareBase::ConsoleManagerThread::threadLoop()
-{
- sigset_t mask;
- sigemptyset(&mask);
- sigaddset(&mask, vm.relsig);
- sigaddset(&mask, vm.acqsig);
-
- int sig = 0;
- sigwait(&mask, &sig);
-
- if (sig == vm.relsig) {
- sp<SurfaceFlinger> flinger = mFlinger.promote();
- //LOGD("About to give-up screen, flinger = %p", flinger.get());
- if (flinger != 0)
- flinger->screenReleased(0);
- } else if (sig == vm.acqsig) {
- sp<SurfaceFlinger> flinger = mFlinger.promote();
- //LOGD("Screen about to return, flinger = %p", flinger.get());
- if (flinger != 0)
- flinger->screenAcquired(0);
- }
-
- return true;
-}
-
-status_t DisplayHardwareBase::ConsoleManagerThread::initCheck() const
-{
- return consoleFd >= 0 ? NO_ERROR : NO_INIT;
+ return ((access(kSleepFileName, R_OK) == 0 &&
+ access(kWakeFileName, R_OK) == 0)) ? NO_ERROR : NO_INIT;
}
// ----------------------------------------------------------------------------
@@ -362,10 +125,6 @@
: mCanDraw(true), mScreenAcquired(true)
{
mDisplayEventThread = new DisplayEventThread(flinger);
- if (mDisplayEventThread->initCheck() != NO_ERROR) {
- // fall-back on the console
- mDisplayEventThread = new ConsoleManagerThread(flinger);
- }
}
DisplayHardwareBase::~DisplayHardwareBase()
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
index fa6a0c4..30eb258 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
@@ -73,24 +73,6 @@
virtual status_t initCheck() const;
};
- class ConsoleManagerThread : public DisplayEventThreadBase
- {
- int consoleFd;
- int vt_num;
- int prev_vt_num;
- vt_mode vm;
- static void sigHandler(int sig);
- static pid_t sSignalCatcherPid;
- public:
- ConsoleManagerThread(const sp<SurfaceFlinger>& flinger);
- virtual ~ConsoleManagerThread();
- virtual bool threadLoop();
- virtual status_t readyToRun();
- virtual void requestExit();
- virtual status_t releaseScreen() const;
- virtual status_t initCheck() const;
- };
-
sp<DisplayEventThreadBase> mDisplayEventThread;
mutable int mCanDraw;
mutable int mScreenAcquired;