Reputation: 139
I have texture loading routine in C that calls Java part of my game to do the job. It can load .png as well as .jpg files and create textures from them. It returns back to C the generated textureID (generated with glGenTextures). It worked perfectly until I started to use frontbuffer.
As the texture for frontbuffer is empty one I am creating it directly in C. It works ok when I run the game for the first time - the texture ID generated for front buffer is different from all other texture IDs. But when I press HOME key, then jump back into game again and I reload all textures and recreate front buffer again (to recover from context loss) the texture ID generated for frontbuffer collides with one of texture IDs generated for textures - like if there were two ID lines. The screen using the framebuffer is corrupted - displaying the texture with ID that equals to the newly assigned ID of the framebuffer.
This all happens only on real device (Samsung Galaxy Tablet in my case), not in emulator.
The C loading routine:
void Texture::construct(AssetLoader* aLoader, s32 aIdx)
{
const c8* fileName = aLoader->getFileName();
// load texture
SBC::System::Application* app = &Game::getGame().getApplication();
JNIEnv *env;
bool shouldDetach = false;
JavaVM* vm = gJavaVM;
jint rc = vm->GetEnv((void **)&env, JNI_VERSION_1_6);
if (rc != JNI_OK)
{
shouldDetach = true;
vm->AttachCurrentThread(&env, NULL);
}
jclass& activityClass = gJavaActivityClass;
jmethodID mid = env->GetStaticMethodID(activityClass, "loadTexture", "(Ljava/lang/String;I)I");
jstring mystr = env->NewStringUTF(fileName);
jint ret = env->CallStaticIntMethod(activityClass, mid, mystr, aIdx);
env->DeleteLocalRef(mystr);
// store information on ID, width and height of texture
mTextureID = ret;
LOGE("textureID = %i", mTextureID);
mid = env->GetStaticMethodID(activityClass, "getTextureWidth", "()I");
mWidth = env->CallStaticIntMethod(activityClass, mid);
mid = env->GetStaticMethodID(activityClass, "getTextureHeight", "()I");
mHeight = env->CallStaticIntMethod(activityClass, mid);
if (shouldDetach)
vm->DetachCurrentThread();
LOGI("texture ID %i, width %i, height %i", mTextureID, mWidth, mHeight);
}
Java methods
//-----------------------------------------------------
/* fname = asset file name
* id >= 0 ... position in compound file
* id < 0 ... single file (no compound)
*/
public static int loadTexture(String fname, int id)
{
// clear last texture parameters
txtID = width = height = -1;
Log.d("Helper", "Loading texture from asset file " + fname + " with id " + id);
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false; // No pre-scaling
AssetManager am = SBCEngine.getSBCEngine().getAssets();
Bitmap bitmap = null;
try
{
InputStream stream = am.open(fname);
// loading from compound file?
if (id >= 0)
{
DataInputStream input = new DataInputStream(stream);
// skip header
input.skip(3);
// skip to entry offset
input.skip(id * 4);
// read entry beginning
int dataStart = input.readInt();
// read data length
int dataLen = input.readInt() - dataStart;
// skip to start of subfile
// offsets are without header (3) bytes
// we already skipped id * 4 bytes
// we already have read 2 offset by 4 bytes = 8 in total
input.skip(dataStart - (id * 4) - 8);
// get data from correct position
byte[] data = new byte[dataLen];
input.read(data);
bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, options);
}
else // no compound
{
Log.d("Helper", "Loading from stream");
bitmap = BitmapFactory.decodeStream(stream, null, options);
}
// test returned bitmap for success
if (bitmap == null)
{
Log.e("Helper", "Failed to load texture " + fname + " with id " + id);
}
// check whether the loaded bitmap has width and height equal to power of 2
int w = bitmap.getWidth();
int h = bitmap.getHeight();
if (getNearestPOT(w) != w || getNearestPOT(h) != h)
{
Log.w("Helper", "Texture " + fname + " with id " + id +
" has not either width or height power of 2");
// new dimensions
w = getNearestPOT(w);
h = getNearestPOT(h);
// get actual bitmap config
Bitmap.Config bitmapConfig = bitmap.getConfig();
// check for null
if (bitmapConfig == null)
{
bitmapConfig = Bitmap.Config.ARGB_8888;
Log.w("Helper", "Unknown bitmap config. Setting to ARGB_8888");
}
// redraw bitmap into POT bitmap
Bitmap newBitmap = Bitmap.createBitmap(w, h, bitmapConfig);
Canvas canvas = new Canvas(newBitmap);
canvas.drawBitmap(bitmap, 0.0f, 0.0f, null);
bitmap.recycle();
canvas = null;
bitmap = newBitmap;
Log.w("Helper", "Texture " + fname + " rebuilded into texture with POT");
}
// generate textureID
int[] textures = new int[1];
GLES20.glGenTextures(1, textures, 0);
int textureID = textures[0];
// create texture
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureID);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
// destroy bitmap
bitmap.recycle();
txtID = textureID;
width = w;
height = h;
Log.d("Helper", "Loaded texture ID:" + textureID + ", width:" + w + ", height:" + h);
return textureID;
}
catch (IOException e)
{
Log.e("Helper", "Failed to load texture " + fname + " with id " + id);
return 0;
}
}
//------------------------------------------------------------------------
public static int getTextureWidth()
{
return width;
}
//------------------------------------------------------------------------
public static int getTextureHeight()
{
return height;
}
//------------------------------------------------------------------------
private static int getNearestPOT(int val)
{
int newDim = 1;
while(val > newDim) newDim *= 2;
return newDim;
}
and finally the C routine to create texture for frontbuffer
// create empty texture
void Texture::construct(u32 aTextureWidth, u32 aTextureHeight)
{
// get power of 2 dimensions
mWidth = getNearestPOT(aTextureWidth);
mHeight = getNearestPOT(aTextureHeight);
glGenTextures(1, &mTextureID);
glBindTexture(GL_TEXTURE_2D, mTextureID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, mWidth, mHeight, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, null);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
LOGE("textureID = %i", mTextureID);
}
Anyone encoutered the same problem?
Upvotes: 0
Views: 1741
Reputation: 139
I finally found the solution. When context loss happens all textures are deleted. But I was deleting them by myself before recreating with previously sotred ID. It led to mess during the process as some newly generated ID were immediately deleted when renewing next object.
Upvotes: 2