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.glesv2debugger; 18 19 import com.android.glesv2debugger.DebuggerMessage.Message; 20 import com.android.sdklib.util.SparseArray; 21 22 import java.util.ArrayList; 23 24 class GLShader implements Cloneable { 25 public final int name; 26 GLServerShader context; // the context this was created in 27 public final GLEnum type; 28 public boolean delete; 29 public ArrayList<Integer> programs = new ArrayList<Integer>(); 30 public String source, originalSource; 31 GLShader(final int name, final GLServerShader context, final GLEnum type)32 GLShader(final int name, final GLServerShader context, final GLEnum type) { 33 this.name = name; 34 this.context = context; 35 this.type = type; 36 } 37 38 /** deep copy */ clone(final GLServerShader copyContext)39 public GLShader clone(final GLServerShader copyContext) { 40 try { 41 GLShader shader = (GLShader) super.clone(); 42 shader.programs = (ArrayList<Integer>) programs.clone(); 43 shader.context = copyContext; 44 return shader; 45 } catch (CloneNotSupportedException e) { 46 e.printStackTrace(); 47 assert false; 48 return null; 49 } 50 } 51 } 52 53 class GLProgram implements Cloneable { 54 public final int name; 55 GLServerShader context; // the context this was created in 56 public boolean delete; 57 public int vert, frag; 58 GLProgram(final int name, final GLServerShader context)59 GLProgram(final int name, final GLServerShader context) { 60 this.name = name; 61 this.context = context; 62 } 63 64 /** deep copy */ clone(final GLServerShader copyContext)65 public GLProgram clone(final GLServerShader copyContext) { 66 try { 67 GLProgram copy = (GLProgram) super.clone(); 68 copy.context = copyContext; 69 return copy; 70 } catch (CloneNotSupportedException e) { 71 e.printStackTrace(); 72 assert false; 73 return null; 74 } 75 } 76 } 77 78 public class GLServerShader implements Cloneable { 79 Context context; 80 public SparseArray<GLShader> shaders = new SparseArray<GLShader>(); 81 public SparseArray<GLProgram> programs = new SparseArray<GLProgram>(); 82 public GLProgram current = null; 83 boolean uiUpdate = false; 84 GLServerShader(Context context)85 GLServerShader(Context context) { 86 this.context = context; 87 } 88 89 /** deep copy */ clone(final Context copyContext)90 public GLServerShader clone(final Context copyContext) { 91 try { 92 GLServerShader copy = (GLServerShader) super.clone(); 93 copy.context = copyContext; 94 95 copy.shaders = new SparseArray<GLShader>(shaders.size()); 96 for (int i = 0; i < shaders.size(); i++) 97 copy.shaders.append(shaders.keyAt(i), shaders.valueAt(i).clone(copy)); 98 99 copy.programs = new SparseArray<GLProgram>(programs.size()); 100 for (int i = 0; i < programs.size(); i++) 101 copy.programs.append(programs.keyAt(i), programs.valueAt(i).clone(copy)); 102 103 if (current != null) 104 copy.current = copy.programs.get(current.name); 105 return copy; 106 } catch (CloneNotSupportedException e) { 107 e.printStackTrace(); 108 assert false; 109 return null; 110 } 111 } 112 113 /** returns true if processed */ processMessage(final Message msg)114 public boolean processMessage(final Message msg) { 115 boolean oldUiUpdate = uiUpdate; 116 uiUpdate = true; 117 switch (msg.getFunction()) { 118 case glAttachShader: 119 glAttachShader(msg); 120 return true; 121 case glCreateProgram: 122 glCreateProgram(msg); 123 return true; 124 case glCreateShader: 125 glCreateShader(msg); 126 return true; 127 case glDeleteProgram: 128 glDeleteProgram(msg); 129 return true; 130 case glDeleteShader: 131 glDeleteShader(msg); 132 return true; 133 case glDetachShader: 134 glDetachShader(msg); 135 return true; 136 case glShaderSource: 137 glShaderSource(msg); 138 return true; 139 case glUseProgram: 140 glUseProgram(msg); 141 return true; 142 default: 143 uiUpdate = oldUiUpdate; 144 return false; 145 } 146 } 147 getShader(int name)148 GLShader getShader(int name) { 149 if (name == 0) 150 return null; 151 for (Context ctx : context.shares) { 152 GLShader shader = ctx.serverShader.shaders.get(name); 153 if (shader != null) 154 return shader; 155 } 156 assert false; 157 return null; 158 } 159 getProgram(int name)160 GLProgram getProgram(int name) { 161 if (name == 0) 162 return null; 163 for (Context ctx : context.shares) { 164 GLProgram program = ctx.serverShader.programs.get(name); 165 if (program != null) 166 return program; 167 } 168 assert false; 169 return null; 170 } 171 172 // void API_ENTRY(glAttachShader)(GLuint program, GLuint shader) glAttachShader(final Message msg)173 void glAttachShader(final Message msg) { 174 GLProgram program = getProgram(msg.getArg0()); 175 assert program != null; 176 GLShader shader = getShader(msg.getArg1()); 177 assert program != null; 178 if (GLEnum.GL_VERTEX_SHADER == shader.type) 179 program.vert = shader.name; 180 else 181 program.frag = shader.name; 182 shader.programs.add(program.name); 183 } 184 185 // GLuint API_ENTRY(glCreateProgram)(void) glCreateProgram(final Message msg)186 void glCreateProgram(final Message msg) { 187 programs.put(msg.getRet(), new GLProgram(msg.getRet(), this)); 188 } 189 190 // GLuint API_ENTRY(glCreateShader)(GLenum type) glCreateShader(final Message msg)191 void glCreateShader(final Message msg) { 192 shaders.put(msg.getRet(), 193 new GLShader(msg.getRet(), this, GLEnum.valueOf(msg.getArg0()))); 194 } 195 196 // void API_ENTRY(glDeleteProgram) glDeleteProgram(final Message msg)197 void glDeleteProgram(final Message msg) { 198 if (msg.getArg0() == 0) 199 return; 200 GLProgram program = getProgram(msg.getArg0()); 201 program.delete = true; 202 for (Context ctx : context.shares) 203 if (ctx.serverShader.current == program) 204 return; 205 glDetachShader(program, getShader(program.vert)); 206 glDetachShader(program, getShader(program.frag)); 207 programs.remove(program.name); 208 } 209 210 // void API_ENTRY(glDeleteShader)(GLuint shader) glDeleteShader(final Message msg)211 void glDeleteShader(final Message msg) { 212 if (msg.getArg0() == 0) 213 return; 214 GLShader shader = getShader(msg.getArg0()); 215 shader.delete = true; 216 if (shader.programs.size() == 0) 217 shaders.remove(shader.name); 218 } 219 220 // void API_ENTRY(glDetachShader)(GLuint program, GLuint shader) glDetachShader(final Message msg)221 void glDetachShader(final Message msg) { 222 glDetachShader(getProgram(msg.getArg0()), getShader(msg.getArg1())); 223 } 224 glDetachShader(final GLProgram program, final GLShader shader)225 void glDetachShader(final GLProgram program, final GLShader shader) { 226 if (program == null) 227 return; 228 if (program.vert == shader.name) 229 program.vert = 0; 230 else if (program.frag == shader.name) 231 program.frag = 0; 232 else 233 return; 234 shader.programs.remove(new Integer(program.name)); 235 if (shader.delete && shader.programs.size() == 0) 236 shaders.remove(shader.name); 237 } 238 239 // void API_ENTRY(glShaderSource)(GLuint shader, GLsizei count, const 240 // GLchar** string, const GLint* length) glShaderSource(final Message msg)241 void glShaderSource(final Message msg) { 242 if (!msg.hasData()) 243 return; // TODO: distinguish between generated calls 244 GLShader shader = getShader(msg.getArg0()); 245 shader.source = shader.originalSource = msg.getData().toStringUtf8(); 246 } 247 248 // void API_ENTRY(glUseProgram)(GLuint program) glUseProgram(final Message msg)249 void glUseProgram(final Message msg) { 250 GLProgram oldCurrent = current; 251 current = getProgram(msg.getArg0()); 252 if (null != oldCurrent && oldCurrent.delete && oldCurrent != current) { 253 for (Context ctx : context.shares) 254 if (ctx.serverShader.current == oldCurrent) 255 return; 256 oldCurrent.context.programs.remove(new Integer(oldCurrent.name)); 257 } 258 } 259 } 260