/* ** 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(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(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(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(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); } }