blob: 617292e280e0b32171f878de909e795f6e483ab7 [file] [log] [blame]
/*
** 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();
}