| /* |
| ** 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.util.ArrayList; |
| |
| class GLShader implements Cloneable { |
| public final int name; |
| GLServerShader context; // the context this was created in |
| public final GLEnum type; |
| public boolean delete; |
| public ArrayList<Integer> programs = new ArrayList<Integer>(); |
| public String source, originalSource; |
| |
| GLShader(final int name, final GLServerShader context, final GLEnum type) { |
| this.name = name; |
| this.context = context; |
| this.type = type; |
| } |
| |
| /** deep copy */ |
| public GLShader clone(final GLServerShader copyContext) { |
| try { |
| GLShader shader = (GLShader) super.clone(); |
| shader.programs = (ArrayList<Integer>) programs.clone(); |
| shader.context = copyContext; |
| return shader; |
| } catch (CloneNotSupportedException e) { |
| e.printStackTrace(); |
| assert false; |
| return null; |
| } |
| } |
| } |
| |
| class GLProgram implements Cloneable { |
| public final int name; |
| GLServerShader context; // the context this was created in |
| public boolean delete; |
| public int vert, frag; |
| |
| GLProgram(final int name, final GLServerShader context) { |
| this.name = name; |
| this.context = context; |
| } |
| |
| /** deep copy */ |
| public GLProgram clone(final GLServerShader copyContext) { |
| try { |
| GLProgram copy = (GLProgram) super.clone(); |
| copy.context = copyContext; |
| return copy; |
| } catch (CloneNotSupportedException e) { |
| e.printStackTrace(); |
| assert false; |
| return null; |
| } |
| } |
| } |
| |
| public class GLServerShader implements Cloneable { |
| Context context; |
| public SparseArray<GLShader> shaders = new SparseArray<GLShader>(); |
| public SparseArray<GLProgram> programs = new SparseArray<GLProgram>(); |
| public GLProgram current = null; |
| boolean uiUpdate = false; |
| |
| GLServerShader(Context context) { |
| this.context = context; |
| } |
| |
| /** deep copy */ |
| public GLServerShader clone(final Context copyContext) { |
| try { |
| GLServerShader copy = (GLServerShader) super.clone(); |
| copy.context = copyContext; |
| |
| copy.shaders = new SparseArray<GLShader>(shaders.size()); |
| for (int i = 0; i < shaders.size(); i++) |
| copy.shaders.append(shaders.keyAt(i), shaders.valueAt(i).clone(copy)); |
| |
| copy.programs = new SparseArray<GLProgram>(programs.size()); |
| for (int i = 0; i < programs.size(); i++) |
| copy.programs.append(programs.keyAt(i), programs.valueAt(i).clone(copy)); |
| |
| if (current != null) |
| copy.current = copy.programs.get(current.name); |
| return copy; |
| } catch (CloneNotSupportedException e) { |
| e.printStackTrace(); |
| assert false; |
| return null; |
| } |
| } |
| |
| /** returns true if processed */ |
| public boolean ProcessMessage(final Message msg) { |
| boolean oldUiUpdate = uiUpdate; |
| uiUpdate = true; |
| switch (msg.getFunction()) { |
| case glAttachShader: |
| glAttachShader(msg); |
| return true; |
| case glCreateProgram: |
| glCreateProgram(msg); |
| return true; |
| case glCreateShader: |
| glCreateShader(msg); |
| return true; |
| case glDeleteProgram: |
| glDeleteProgram(msg); |
| return true; |
| case glDeleteShader: |
| glDeleteShader(msg); |
| return true; |
| case glDetachShader: |
| glDetachShader(msg); |
| return true; |
| case glShaderSource: |
| glShaderSource(msg); |
| return true; |
| case glUseProgram: |
| glUseProgram(msg); |
| return true; |
| default: |
| uiUpdate = oldUiUpdate; |
| return false; |
| } |
| } |
| |
| GLShader GetShader(int name) { |
| if (name == 0) |
| return null; |
| for (Context ctx : context.shares) { |
| GLShader shader = ctx.serverShader.shaders.get(name); |
| if (shader != null) |
| return shader; |
| } |
| assert false; |
| return null; |
| } |
| |
| GLProgram GetProgram(int name) { |
| if (name == 0) |
| return null; |
| for (Context ctx : context.shares) { |
| GLProgram program = ctx.serverShader.programs.get(name); |
| if (program != null) |
| return program; |
| } |
| assert false; |
| return null; |
| } |
| |
| // void API_ENTRY(glAttachShader)(GLuint program, GLuint shader) |
| void glAttachShader(final Message msg) { |
| GLProgram program = GetProgram(msg.getArg0()); |
| GLShader shader = GetShader(msg.getArg1()); |
| if (GLEnum.GL_VERTEX_SHADER == shader.type) |
| program.vert = shader.name; |
| else |
| program.frag = shader.name; |
| shader.programs.add(program.name); |
| } |
| |
| // GLuint API_ENTRY(glCreateProgram)(void) |
| void glCreateProgram(final Message msg) { |
| programs.put(msg.getRet(), new GLProgram(msg.getRet(), this)); |
| } |
| |
| // GLuint API_ENTRY(glCreateShader)(GLenum type) |
| void glCreateShader(final Message msg) { |
| shaders.put(msg.getRet(), |
| new GLShader(msg.getRet(), this, GLEnum.valueOf(msg.getArg0()))); |
| } |
| |
| // void API_ENTRY(glDeleteProgram) |
| void glDeleteProgram(final Message msg) { |
| if (msg.getArg0() == 0) |
| return; |
| GLProgram program = GetProgram(msg.getArg0()); |
| program.delete = true; |
| for (Context ctx : context.shares) |
| if (ctx.serverShader.current == program) |
| return; |
| glDetachShader(program, GetShader(program.vert)); |
| glDetachShader(program, GetShader(program.frag)); |
| programs.remove(program.name); |
| } |
| |
| // void API_ENTRY(glDeleteShader)(GLuint shader) |
| void glDeleteShader(final Message msg) { |
| if (msg.getArg0() == 0) |
| return; |
| GLShader shader = GetShader(msg.getArg0()); |
| shader.delete = true; |
| if (shader.programs.size() == 0) |
| shaders.remove(shader.name); |
| } |
| |
| // void API_ENTRY(glDetachShader)(GLuint program, GLuint shader) |
| void glDetachShader(final Message msg) { |
| glDetachShader(GetProgram(msg.getArg0()), GetShader(msg.getArg1())); |
| } |
| |
| void glDetachShader(final GLProgram program, final GLShader shader) { |
| if (program == null) |
| return; |
| if (program.vert == shader.name) |
| program.vert = 0; |
| else if (program.frag == shader.name) |
| program.frag = 0; |
| else |
| return; |
| shader.programs.remove(program.name); |
| if (shader.delete && shader.programs.size() == 0) |
| shaders.remove(shader.name); |
| } |
| |
| // void API_ENTRY(glShaderSource)(GLuint shader, GLsizei count, const |
| // GLchar** string, const GLint* length) |
| void glShaderSource(final Message msg) { |
| if (!msg.hasData()) |
| return; // TODO: distinguish between generated calls |
| GLShader shader = GetShader(msg.getArg0()); |
| shader.source = shader.originalSource = msg.getData().toStringUtf8(); |
| } |
| |
| // void API_ENTRY(glUseProgram)(GLuint program) |
| void glUseProgram(final Message msg) { |
| GLProgram oldCurrent = current; |
| current = GetProgram(msg.getArg0()); |
| if (null != oldCurrent && oldCurrent.delete && oldCurrent != current) { |
| for (Context ctx : context.shares) |
| if (ctx.serverShader.current == oldCurrent) |
| return; |
| oldCurrent.context.programs.remove(oldCurrent.name); |
| } |
| } |
| } |