301 lines
9.9 KiB
C++
301 lines
9.9 KiB
C++
/*
|
|
** 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"
|
|
|
|
static inline void GetFormatAndBytesPerPixel(const GLenum format, unsigned & bytesPerPixel)
|
|
{
|
|
switch (format) {
|
|
case GL_ALPHA:
|
|
bytesPerPixel = 1;
|
|
break;
|
|
case GL_LUMINANCE:
|
|
bytesPerPixel = 1;
|
|
break;
|
|
case GL_LUMINANCE_ALPHA:
|
|
bytesPerPixel = 2;
|
|
break;
|
|
case GL_RGB:
|
|
bytesPerPixel = 3;
|
|
break;
|
|
case GL_RGBA:
|
|
bytesPerPixel = 4;
|
|
break;
|
|
|
|
// internal formats to avoid conversion
|
|
case GL_UNSIGNED_SHORT_5_6_5:
|
|
bytesPerPixel = 2;
|
|
break;
|
|
case GL_UNSIGNED_SHORT_4_4_4_4:
|
|
bytesPerPixel = 2;
|
|
break;
|
|
case GL_UNSIGNED_SHORT_5_5_5_1:
|
|
bytesPerPixel = 2;
|
|
break;
|
|
default:
|
|
assert(0);
|
|
return;
|
|
}
|
|
}
|
|
|
|
#define USE_RLE 0
|
|
#if USE_RLE
|
|
template<typename T>
|
|
void * RLEEncode(const void * pixels, unsigned count, unsigned * encodedSize)
|
|
{
|
|
// first is a byte indicating data size [1,2,4] bytes
|
|
// then an unsigned indicating decompressed size
|
|
// then a byte of header: MSB == 1 indicates run, else literal
|
|
// LSB7 is run or literal length (actual length - 1)
|
|
|
|
const T * data = (T *)pixels;
|
|
unsigned bufferSize = sizeof(T) * count / 2 + 8;
|
|
unsigned char * buffer = (unsigned char *)malloc(bufferSize);
|
|
buffer[0] = sizeof(T);
|
|
unsigned bufferWritten = 1; // number of bytes written
|
|
*(unsigned *)(buffer + bufferWritten) = count;
|
|
bufferWritten += sizeof(count);
|
|
while (count) {
|
|
unsigned char run = 1;
|
|
bool repeat = true;
|
|
for (run = 1; run < count; run++)
|
|
if (data[0] != data[run]) {
|
|
repeat = false;
|
|
break;
|
|
} else if (run > 127)
|
|
break;
|
|
if (!repeat) {
|
|
// find literal length
|
|
for (run = 1; run < count; run++)
|
|
if (data[run - 1] == data[run])
|
|
break;
|
|
else if (run > 127)
|
|
break;
|
|
unsigned bytesToWrite = 1 + sizeof(T) * run;
|
|
if (bufferWritten + bytesToWrite > bufferSize) {
|
|
bufferSize += sizeof(T) * run + 256;
|
|
buffer = (unsigned char *)realloc(buffer, bufferSize);
|
|
}
|
|
buffer[bufferWritten++] = run - 1;
|
|
for (unsigned i = 0; i < run; i++) {
|
|
*(T *)(buffer + bufferWritten) = *data;
|
|
bufferWritten += sizeof(T);
|
|
data++;
|
|
}
|
|
count -= run;
|
|
} else {
|
|
unsigned bytesToWrite = 1 + sizeof(T);
|
|
if (bufferWritten + bytesToWrite > bufferSize) {
|
|
bufferSize += 256;
|
|
buffer = (unsigned char *)realloc(buffer, bufferSize);
|
|
}
|
|
buffer[bufferWritten++] = (run - 1) | 0x80;
|
|
*(T *)(buffer + bufferWritten) = data[0];
|
|
bufferWritten += sizeof(T);
|
|
data += run;
|
|
count -= run;
|
|
}
|
|
}
|
|
if (encodedSize)
|
|
*encodedSize = bufferWritten;
|
|
return buffer;
|
|
}
|
|
|
|
void * RLEEncode(const void * pixels, const unsigned bytesPerPixel, const unsigned count, unsigned * encodedSize)
|
|
{
|
|
switch (bytesPerPixel) {
|
|
case 4:
|
|
return RLEEncode<int>(pixels, count, encodedSize);
|
|
case 2:
|
|
return RLEEncode<short>(pixels, count, encodedSize);
|
|
case 1:
|
|
return RLEEncode<char>(pixels, count, encodedSize);
|
|
default:
|
|
assert(0);
|
|
return NULL;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void API_ENTRY(glTexImage2D)(GLenum target, GLint level, GLint internalformat, GLsizei width,
|
|
GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid * pixels)
|
|
{
|
|
// LOGD("\n*\n* GLESv2_dbg: %s \n*", "glTexImage2D");
|
|
gl_hooks_t::gl_t const * const _c = &getGLTraceThreadSpecific()->gl;
|
|
|
|
GLESv2Debugger::Message msg, cmd;
|
|
msg.set_context_id(0);
|
|
msg.set_has_next_message(true);
|
|
const bool expectResponse = false;
|
|
msg.set_expect_response(expectResponse);
|
|
msg.set_function(GLESv2Debugger::Message_Function_glTexImage2D);
|
|
|
|
msg.set_arg0(target);
|
|
msg.set_arg1(level);
|
|
msg.set_arg2(internalformat);
|
|
msg.set_arg3(width);
|
|
msg.set_arg4(height);
|
|
msg.set_arg5(border);
|
|
msg.set_arg6(format);
|
|
msg.set_arg7(type);
|
|
|
|
if (pixels) {
|
|
assert(internalformat == format);
|
|
assert(0 == border);
|
|
|
|
GLenum newFormat = internalformat;
|
|
switch (type) {
|
|
case GL_UNSIGNED_BYTE:
|
|
break;
|
|
case GL_UNSIGNED_SHORT_5_6_5:
|
|
case GL_UNSIGNED_SHORT_4_4_4_4:
|
|
case GL_UNSIGNED_SHORT_5_5_5_1:
|
|
newFormat = type;
|
|
break;
|
|
default:
|
|
LOGD("GLESv2_dbg: glTexImage2D type=0x%.4X", type);
|
|
assert(0);
|
|
}
|
|
unsigned bytesPerPixel = 0;
|
|
GetFormatAndBytesPerPixel(newFormat, bytesPerPixel);
|
|
assert(0 < bytesPerPixel);
|
|
|
|
// LOGD("GLESv2_dbg: glTexImage2D width=%d height=%d level=%d bytesPerPixel=%d",
|
|
// width, height, level, bytesPerPixel);
|
|
#if USE_RLE
|
|
unsigned encodedSize = 0;
|
|
void * data = RLEEncode(pixels, bytesPerPixel, width * height, &encodedSize);
|
|
msg.set_data(data, encodedSize);
|
|
free(data);
|
|
if (encodedSize > bytesPerPixel * width * height)
|
|
LOGD("GLESv2_dbg: glTexImage2D sending data encodedSize=%d size=%d", encodedSize, bytesPerPixel * width * height);
|
|
#else
|
|
msg.set_data(pixels, bytesPerPixel * width * height);
|
|
#endif
|
|
}
|
|
assert(msg.has_arg3());
|
|
Send(msg, cmd);
|
|
if (!expectResponse)
|
|
cmd.set_function(GLESv2Debugger::Message_Function_CONTINUE);
|
|
|
|
while (true) {
|
|
msg.Clear();
|
|
clock_t c0 = clock();
|
|
switch (cmd.function()) {
|
|
case GLESv2Debugger::Message_Function_CONTINUE:
|
|
_c->glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels);
|
|
msg.set_time((float(clock()) - c0) / CLOCKS_PER_SEC);
|
|
msg.set_context_id(0);
|
|
msg.set_function(GLESv2Debugger::Message_Function_glTexImage2D);
|
|
msg.set_has_next_message(false);
|
|
msg.set_expect_response(expectResponse);
|
|
assert(!msg.has_arg3());
|
|
Send(msg, cmd);
|
|
if (!expectResponse)
|
|
cmd.set_function(GLESv2Debugger::Message_Function_SKIP);
|
|
break;
|
|
case GLESv2Debugger::Message_Function_SKIP:
|
|
return;
|
|
default:
|
|
ASSERT(0); //GenerateCall(msg, cmd);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void API_ENTRY(glTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset,
|
|
GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels)
|
|
{
|
|
// LOGD("\n*\n* GLESv2_dbg: %s \n*", "glTexSubImage2D");
|
|
gl_hooks_t::gl_t const * const _c = &getGLTraceThreadSpecific()->gl;
|
|
|
|
GLESv2Debugger::Message msg, cmd;
|
|
msg.set_context_id(0);
|
|
msg.set_has_next_message(true);
|
|
const bool expectResponse = false;
|
|
msg.set_expect_response(expectResponse);
|
|
msg.set_function(GLESv2Debugger::Message_Function_glTexSubImage2D);
|
|
|
|
msg.set_arg0(target);
|
|
msg.set_arg1(level);
|
|
msg.set_arg2(xoffset);
|
|
msg.set_arg3(yoffset);
|
|
msg.set_arg4(width);
|
|
msg.set_arg5(height);
|
|
msg.set_arg6(format);
|
|
msg.set_arg7(type);
|
|
|
|
assert(pixels);
|
|
if (pixels) {
|
|
GLenum newFormat = format;
|
|
switch (type) {
|
|
case GL_UNSIGNED_BYTE:
|
|
break;
|
|
case GL_UNSIGNED_SHORT_5_6_5:
|
|
case GL_UNSIGNED_SHORT_4_4_4_4:
|
|
case GL_UNSIGNED_SHORT_5_5_5_1:
|
|
newFormat = type;
|
|
break;
|
|
default:
|
|
assert(0);
|
|
}
|
|
unsigned bytesPerPixel = 0;
|
|
GetFormatAndBytesPerPixel(newFormat, bytesPerPixel);
|
|
assert(0 < bytesPerPixel);
|
|
|
|
// LOGD("GLESv2_dbg: glTexSubImage2D width=%d height=%d level=%d bytesPerPixel=%d",
|
|
// width, height, level, bytesPerPixel);
|
|
|
|
#if USE_RLE
|
|
unsigned encodedSize = 0;
|
|
void * data = RLEEncode(pixels, bytesPerPixel, width * height, &encodedSize);
|
|
msg.set_data(data, encodedSize);
|
|
free(data);
|
|
if (encodedSize > bytesPerPixel * width * height)
|
|
LOGD("GLESv2_dbg: glTexImage2D sending data encodedSize=%d size=%d", encodedSize, bytesPerPixel * width * height);
|
|
#else
|
|
msg.set_data(pixels, bytesPerPixel * width * height);
|
|
#endif
|
|
}
|
|
|
|
Send(msg, cmd);
|
|
if (!expectResponse)
|
|
cmd.set_function(GLESv2Debugger::Message_Function_CONTINUE);
|
|
|
|
while (true) {
|
|
msg.Clear();
|
|
clock_t c0 = clock();
|
|
switch (cmd.function()) {
|
|
case GLESv2Debugger::Message_Function_CONTINUE:
|
|
_c->glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
|
|
msg.set_time((float(clock()) - c0) / CLOCKS_PER_SEC);
|
|
msg.set_function(GLESv2Debugger::Message_Function_glTexImage2D);
|
|
msg.set_context_id(0);
|
|
msg.set_has_next_message(false);
|
|
msg.set_expect_response(expectResponse);
|
|
Send(msg, cmd);
|
|
if (!expectResponse)
|
|
cmd.set_function(GLESv2Debugger::Message_Function_SKIP);
|
|
break;
|
|
case GLESv2Debugger::Message_Function_SKIP:
|
|
return;
|
|
default:
|
|
ASSERT(0); //GenerateCall(msg, cmd);
|
|
break;
|
|
}
|
|
}
|
|
}
|