/* ** 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. */ package com.android.glesv2debugger; import com.android.glesv2debugger.DebuggerMessage.Message; import com.android.sdklib.util.SparseArray; import java.nio.ByteBuffer; import java.util.ArrayList; class GLTexture implements Cloneable { public final int name; public final GLEnum target; public ArrayList<Message> contentChanges = new ArrayList<Message>(); public GLEnum wrapS = GLEnum.GL_REPEAT, wrapT = GLEnum.GL_REPEAT; public GLEnum min = GLEnum.GL_NEAREST_MIPMAP_LINEAR; public GLEnum mag = GLEnum.GL_LINEAR; public GLEnum format; public int width, height; GLTexture(final int name, final GLEnum target) { this.name = name; this.target = target; } @Override public GLTexture clone() { try { GLTexture copy = (GLTexture) super.clone(); copy.contentChanges = (ArrayList<Message>) contentChanges.clone(); return copy; } catch (CloneNotSupportedException e) { e.printStackTrace(); assert false; return null; } } boolean processMessage(final Message msg) { switch (msg.getFunction()) { case glCompressedTexImage2D: case glCopyTexImage2D: case glTexImage2D: if (msg.getArg1() == 0) { // level 0 format = GLEnum.valueOf(msg.getArg2()); width = msg.getArg3(); height = msg.getArg4(); } //$FALL-THROUGH$ case glCompressedTexSubImage2D: case glCopyTexSubImage2D: case glTexSubImage2D: case glGenerateMipmap: contentChanges.add(msg); break; default: assert false; } return true; } @Override public String toString() { return String.format("%s %s %d*%d %d change(s)", target, format, width, height, contentChanges.size()); } } public class GLServerTexture implements Cloneable { Context context; public GLEnum activeTexture = GLEnum.GL_TEXTURE0; public int[] tmu2D; public int[] tmuCube; public SparseArray<GLTexture> textures = new SparseArray<GLTexture>(); public GLTexture tex2D = null, texCube = null; GLServerTexture(final Context context, final int MAX_COMBINED_TEXTURE_IMAGE_UNITS) { this.context = context; textures.append(0, null); tmu2D = new int[MAX_COMBINED_TEXTURE_IMAGE_UNITS]; tmuCube = new int[MAX_COMBINED_TEXTURE_IMAGE_UNITS]; } public GLServerTexture clone(final Context copyContext) { try { GLServerTexture copy = (GLServerTexture) super.clone(); copy.context = copyContext; copy.tmu2D = tmu2D.clone(); copy.tmuCube = tmuCube.clone(); copy.textures = new SparseArray<GLTexture>(textures.size()); for (int i = 0; i < textures.size(); i++) if (textures.valueAt(i) != null) copy.textures.append(textures.keyAt(i), textures.valueAt(i).clone()); else copy.textures.append(textures.keyAt(i), null); if (tex2D != null) copy.tex2D = copy.textures.get(tex2D.name); if (texCube != null) copy.texCube = copy.textures.get(texCube.name); return copy; } catch (CloneNotSupportedException e) { e.printStackTrace(); assert false; return null; } } public boolean processMessage(final Message msg) { switch (msg.getFunction()) { case glActiveTexture: activeTexture = GLEnum.valueOf(msg.getArg0()); return true; case glBindTexture: return bindTexture(msg.getArg0(), msg.getArg1()); case glCompressedTexImage2D: case glCompressedTexSubImage2D: case glCopyTexImage2D: case glCopyTexSubImage2D: case glTexImage2D: case glTexSubImage2D: switch (GLEnum.valueOf(msg.getArg0())) { case GL_TEXTURE_2D: if (tex2D != null) return tex2D.processMessage(msg); return true; case GL_TEXTURE_CUBE_MAP_POSITIVE_X: case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: if (texCube != null) return texCube.processMessage(msg); return true; default: return true; } case glDeleteTextures: { final ByteBuffer names = msg.getData().asReadOnlyByteBuffer(); names.order(SampleView.targetByteOrder); for (int i = 0; i < msg.getArg0(); i++) { final int name = names.getInt(); if (tex2D != null && tex2D.name == name) bindTexture(GLEnum.GL_TEXTURE_2D.value, 0); if (texCube != null && texCube.name == name) bindTexture(GLEnum.GL_TEXTURE_CUBE_MAP.value, 0); if (name != 0) textures.remove(name); } return true; } case glGenerateMipmap: if (GLEnum.valueOf(msg.getArg0()) == GLEnum.GL_TEXTURE_2D && tex2D != null) return tex2D.processMessage(msg); else if (GLEnum.valueOf(msg.getArg0()) == GLEnum.GL_TEXTURE_CUBE_MAP && texCube != null) return texCube.processMessage(msg); return true; case glTexParameteri: return texParameter(msg.getArg0(), msg.getArg1(), msg.getArg2()); case glTexParameterf: return texParameter(msg.getArg0(), msg.getArg1(), (int) Float.intBitsToFloat(msg.getArg2())); default: return false; } } boolean bindTexture(final int target, final int name) { final int index = activeTexture.value - GLEnum.GL_TEXTURE0.value; if (GLEnum.valueOf(target) == GLEnum.GL_TEXTURE_2D) { tex2D = textures.get(name); if (name != 0 && tex2D == null) textures.put(name, tex2D = new GLTexture(name, GLEnum.GL_TEXTURE_2D)); if (index >= 0 && index < tmu2D.length) tmu2D[index] = name; } else if (GLEnum.valueOf(target) == GLEnum.GL_TEXTURE_CUBE_MAP) { texCube = textures.get(name); if (name != 0 && texCube == null) textures.put(name, texCube = new GLTexture(name, GLEnum.GL_TEXTURE_CUBE_MAP)); if (index >= 0 && index < tmu2D.length) tmu2D[index] = name; } else assert false; return true; } boolean texParameter(final int target, final int pname, final int param) { GLTexture tex = null; if (GLEnum.valueOf(target) == GLEnum.GL_TEXTURE_2D) tex = tex2D; else if (GLEnum.valueOf(target) == GLEnum.GL_TEXTURE_CUBE_MAP) tex = texCube; if (tex == null) return true; final GLEnum p = GLEnum.valueOf(param); switch (GLEnum.valueOf(pname)) { case GL_TEXTURE_WRAP_S: tex.wrapS = p; return true; case GL_TEXTURE_WRAP_T: tex.wrapT = p; return true; case GL_TEXTURE_MIN_FILTER: tex.min = p; return true; case GL_TEXTURE_MAG_FILTER: tex.mag = p; return true; default: return true; } } }