1 /* 2 ** Copyright 2011, The Android Open Source Project 3 ** 4 ** Licensed under the Apache License, Version 2.0 (the "License"); 5 ** you may not use this file except in compliance with the License. 6 ** You may obtain a copy of the License at 7 ** 8 ** http://www.apache.org/licenses/LICENSE-2.0 9 ** 10 ** Unless required by applicable law or agreed to in writing, software 11 ** distributed under the License is distributed on an "AS IS" BASIS, 12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 ** See the License for the specific language governing permissions and 14 ** limitations under the License. 15 */ 16 17 package com.android.ide.eclipse.gldebugger; 18 19 import com.android.ide.eclipse.gldebugger.DebuggerMessage.Message; 20 import com.android.sdklib.util.SparseArray; 21 22 import java.nio.ByteBuffer; 23 import java.util.ArrayList; 24 25 class GLTexture implements Cloneable { 26 public final int name; 27 public final GLEnum target; 28 public ArrayList<Message> contentChanges = new ArrayList<Message>(); 29 public GLEnum wrapS = GLEnum.GL_REPEAT, wrapT = GLEnum.GL_REPEAT; 30 public GLEnum min = GLEnum.GL_NEAREST_MIPMAP_LINEAR; 31 public GLEnum mag = GLEnum.GL_LINEAR; 32 public GLEnum format; 33 public int width, height; 34 35 GLTexture(final int name, final GLEnum target) { 36 this.name = name; 37 this.target = target; 38 } 39 40 @Override 41 public GLTexture clone() { 42 try { 43 GLTexture copy = (GLTexture) super.clone(); 44 copy.contentChanges = (ArrayList<Message>) contentChanges.clone(); 45 return copy; 46 } catch (CloneNotSupportedException e) { 47 e.printStackTrace(); 48 assert false; 49 return null; 50 } 51 } 52 53 boolean processMessage(final Message msg) { 54 switch (msg.getFunction()) { 55 case glCompressedTexImage2D: 56 case glCopyTexImage2D: 57 case glTexImage2D: 58 if (msg.getArg1() == 0) { // level 0 59 format = GLEnum.valueOf(msg.getArg2()); 60 width = msg.getArg3(); 61 height = msg.getArg4(); 62 } 63 //$FALL-THROUGH$ 64 case glCompressedTexSubImage2D: 65 case glCopyTexSubImage2D: 66 case glTexSubImage2D: 67 case glGenerateMipmap: 68 contentChanges.add(msg); 69 break; 70 default: 71 assert false; 72 } 73 return true; 74 } 75 76 @Override 77 public String toString() { 78 return String.format("%s %s %d*%d %d change(s)", target, format, width, height, 79 contentChanges.size()); 80 } 81 } 82 83 public class GLServerTexture implements Cloneable { 84 Context context; 85 86 public GLEnum activeTexture = GLEnum.GL_TEXTURE0; 87 public int[] tmu2D; 88 public int[] tmuCube; 89 public SparseArray<GLTexture> textures = new SparseArray<GLTexture>(); 90 public GLTexture tex2D = null, texCube = null; 91 92 GLServerTexture(final Context context, final int MAX_COMBINED_TEXTURE_IMAGE_UNITS) { 93 this.context = context; 94 textures.append(0, null); 95 tmu2D = new int[MAX_COMBINED_TEXTURE_IMAGE_UNITS]; 96 tmuCube = new int[MAX_COMBINED_TEXTURE_IMAGE_UNITS]; 97 } 98 99 public GLServerTexture clone(final Context copyContext) { 100 try { 101 GLServerTexture copy = (GLServerTexture) super.clone(); 102 copy.context = copyContext; 103 104 copy.tmu2D = tmu2D.clone(); 105 copy.tmuCube = tmuCube.clone(); 106 107 copy.textures = new SparseArray<GLTexture>(textures.size()); 108 for (int i = 0; i < textures.size(); i++) 109 if (textures.valueAt(i) != null) 110 copy.textures.append(textures.keyAt(i), textures.valueAt(i).clone()); 111 else 112 copy.textures.append(textures.keyAt(i), null); 113 114 if (tex2D != null) 115 copy.tex2D = copy.textures.get(tex2D.name); 116 if (texCube != null) 117 copy.texCube = copy.textures.get(texCube.name); 118 119 return copy; 120 } catch (CloneNotSupportedException e) { 121 e.printStackTrace(); 122 assert false; 123 return null; 124 } 125 } 126 127 public boolean processMessage(final Message msg) { 128 switch (msg.getFunction()) { 129 case glActiveTexture: 130 activeTexture = GLEnum.valueOf(msg.getArg0()); 131 return true; 132 case glBindTexture: 133 return bindTexture(msg.getArg0(), msg.getArg1()); 134 case glCompressedTexImage2D: 135 case glCompressedTexSubImage2D: 136 case glCopyTexImage2D: 137 case glCopyTexSubImage2D: 138 case glTexImage2D: 139 case glTexSubImage2D: 140 switch (GLEnum.valueOf(msg.getArg0())) { 141 case GL_TEXTURE_2D: 142 if (tex2D != null) 143 return tex2D.processMessage(msg); 144 return true; 145 case GL_TEXTURE_CUBE_MAP_POSITIVE_X: 146 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: 147 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: 148 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: 149 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: 150 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: 151 if (texCube != null) 152 return texCube.processMessage(msg); 153 return true; 154 default: 155 return true; 156 } 157 case glDeleteTextures: { 158 final ByteBuffer names = msg.getData().asReadOnlyByteBuffer(); 159 names.order(GLFramesView.TARGET_BYTE_ORDER); 160 for (int i = 0; i < msg.getArg0(); i++) { 161 final int name = names.getInt(); 162 if (tex2D != null && tex2D.name == name) 163 bindTexture(GLEnum.GL_TEXTURE_2D.value, 0); 164 if (texCube != null && texCube.name == name) 165 bindTexture(GLEnum.GL_TEXTURE_CUBE_MAP.value, 0); 166 if (name != 0) 167 textures.remove(name); 168 } 169 return true; 170 } 171 case glGenerateMipmap: 172 if (GLEnum.valueOf(msg.getArg0()) == GLEnum.GL_TEXTURE_2D && tex2D != null) 173 return tex2D.processMessage(msg); 174 else if (GLEnum.valueOf(msg.getArg0()) == GLEnum.GL_TEXTURE_CUBE_MAP 175 && texCube != null) 176 return texCube.processMessage(msg); 177 return true; 178 case glTexParameteri: 179 return texParameter(msg.getArg0(), msg.getArg1(), msg.getArg2()); 180 case glTexParameterf: 181 return texParameter(msg.getArg0(), msg.getArg1(), 182 (int) Float.intBitsToFloat(msg.getArg2())); 183 default: 184 return false; 185 } 186 } 187 188 boolean bindTexture(final int target, final int name) { 189 final int index = activeTexture.value - GLEnum.GL_TEXTURE0.value; 190 if (GLEnum.valueOf(target) == GLEnum.GL_TEXTURE_2D) { 191 tex2D = textures.get(name); 192 if (name != 0 && tex2D == null) 193 textures.put(name, tex2D = new GLTexture(name, 194 GLEnum.GL_TEXTURE_2D)); 195 if (index >= 0 && index < tmu2D.length) 196 tmu2D[index] = name; 197 } else if (GLEnum.valueOf(target) == GLEnum.GL_TEXTURE_CUBE_MAP) { 198 texCube = textures.get(name); 199 if (name != 0 && texCube == null) 200 textures.put(name, texCube = new GLTexture(name, 201 GLEnum.GL_TEXTURE_CUBE_MAP)); 202 if (index >= 0 && index < tmu2D.length) 203 tmu2D[index] = name; 204 } else 205 assert false; 206 return true; 207 } 208 209 boolean texParameter(final int target, final int pname, final int param) { 210 GLTexture tex = null; 211 if (GLEnum.valueOf(target) == GLEnum.GL_TEXTURE_2D) 212 tex = tex2D; 213 else if (GLEnum.valueOf(target) == GLEnum.GL_TEXTURE_CUBE_MAP) 214 tex = texCube; 215 if (tex == null) 216 return true; 217 final GLEnum p = GLEnum.valueOf(param); 218 switch (GLEnum.valueOf(pname)) { 219 case GL_TEXTURE_WRAP_S: 220 tex.wrapS = p; 221 return true; 222 case GL_TEXTURE_WRAP_T: 223 tex.wrapT = p; 224 return true; 225 case GL_TEXTURE_MIN_FILTER: 226 tex.min = p; 227 return true; 228 case GL_TEXTURE_MAG_FILTER: 229 tex.mag = p; 230 return true; 231 default: 232 return true; 233 } 234 } 235 } 236