replicant-frameworks_native/opengl/libs/GLES2_dbg/src/texture.cpp

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;
}
}
}