/* * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Sun designates this * particular file as subject to the "Classpath" exception as provided * by Sun in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. * */ package javax.media.j3d; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; /** * The ShaderProgramRetained object is a component object of an AppearanceRetained * object that defines the shader properties used when programmable shader is * enabled. ShaderProgramRetained object is an abstract class. All shader program * objects must be created as either a GLSLShaderProgramRetained object or a * CgShaderProgramRetained object. */ abstract class ShaderProgramRetained extends NodeComponentRetained { // Each element in the array corresponds to a unique renderer if shared // context or a unique canvas otherwise. protected ShaderProgramData shaderProgramData[]; // Flag indicating whether an UNSUPPORTED_LANGUAGE_ERROR has // already been reported for this shader program object. It is // set in verifyShaderProgram and cleared in setLive or clearLive. // TODO KCR: Add code to clear this in setLive or clearLive private boolean unsupportedErrorReported = false; // Flag indicating whether a LINK_ERROR has occurred for this shader program // object. It is set in updateNative to indicate that the linkShaderProgram // operation failed. It is cleared in setLive or clearLive. // TODO KCR: Add code to clear this in setLive or clearLive private boolean linkErrorOccurred = false; // an array of shaders used by this shader program protected ShaderRetained[] shaders; // an array of vertex attribute names protected String[] vertexAttrNames; // an array of (uniform) shader attribute names protected String[] shaderAttrNames; // Set of ShaderAttribute objects for which we have already reported an error private HashSet shaderAttrErrorSet = null; // need to synchronize access from multiple rendering threads Object resourceLock = new Object(); // Package-scope default constructor ShaderProgramRetained() { } /** * Sets the vertex attribute names array for this ShaderProgram * object. Each element in the array specifies the shader * attribute name that is bound to the corresponding numbered * vertex attribute within a GeometryArray object that uses this * shader program. Array element 0 specifies the name of * GeometryArray vertex attribute 0, array element 1 specifies the * name of GeometryArray vertex attribute 1, and so forth. * The array of names may be null or empty (0 length), but the * elements of the array must be non-null. * * @param vertexAttrNames array of vertex attribute names for this * shader program. A copy of this array is made. */ void setVertexAttrNames(String[] vertexAttrNames) { if (vertexAttrNames == null) { this.vertexAttrNames = null; } else { this.vertexAttrNames = vertexAttrNames.clone(); } } /** * Retrieves the vertex attribute names array from this * ShaderProgram object. * * @return a copy of this ShaderProgram's array of vertex attribute names. */ String[] getVertexAttrNames() { if (vertexAttrNames == null) { return null; } return vertexAttrNames.clone(); } /** * Sets the shader attribute names array for this ShaderProgram * object. Each element in the array specifies a shader * attribute name that may be set via a ShaderAttribute object. * Only those attributes whose names that appear in the shader * attribute names array can be set for a given shader program. * The array of names may be null or empty (0 length), but the * elements of the array must be non-null. * * @param shaderAttrNames array of shader attribute names for this * shader program. A copy of this array is made. */ void setShaderAttrNames(String[] shaderAttrNames) { if (shaderAttrNames == null) { this.shaderAttrNames = null; } else { this.shaderAttrNames = shaderAttrNames.clone(); } } /** * Retrieves the shader attribute names array from this * ShaderProgram object. * * @return a copy of this ShaderProgram's array of shader attribute names. */ String[] getShaderAttrNames() { if (shaderAttrNames == null) { return null; } return shaderAttrNames.clone(); } /** * Copies the specified array of shaders into this shader * program. This method makes a shallow copy of the array. The * array of shaders may be null or empty (0 length), but the * elements of the array must be non-null. The shading * language of each shader in the array must match the * subclass. Subclasses may impose additional restrictions. * * @param shaders array of Shader objects to be copied into this * ShaderProgram * * @exception CapabilityNotSetException if appropriate capability is * not set and this object is part of live or compiled scene graph * * @exception IllegalArgumentException if the shading language of * any shader in the shaders array doesn't match the type of the * subclass. */ void setShaders(Shader[] shaders) { if (shaders == null) { this.shaders = null; return; } this.shaders = new ShaderRetained[shaders.length]; // Copy vertex and fragment shader for (int i = 0; i < shaders.length; i++) { this.shaders[i] = (ShaderRetained)shaders[i].retained; } } /** * Retrieves the array of shaders from this shader program. A * shallow copy of the array is returned. The return value may * be null. * * @return a copy of this ShaderProgram's array of Shader objects * */ Shader[] getShaders() { if (shaders == null) { return null; } else { Shader shads[] = new Shader[shaders.length]; for (int i = 0; i < shaders.length; i++) { if (shaders[i] != null) { shads[i] = (Shader) shaders[i].source; } else { shads[i] = null; } } return shads; } } /** * Method to create the native shader. */ abstract ShaderError createShader(Context ctx, ShaderRetained shader, ShaderId[] shaderIdArr); /** * Method to destroy the native shader. */ abstract ShaderError destroyShader(Context ctx, ShaderId shaderId); /** * Method to compile the native shader. */ abstract ShaderError compileShader(Context ctx, ShaderId shaderId, String source); /** * Method to create the native shader program. */ abstract ShaderError createShaderProgram(Context ctx, ShaderProgramId[] shaderProgramIdArr); /** * Method to destroy the native shader program. */ abstract ShaderError destroyShaderProgram(Context ctx, ShaderProgramId shaderProgramId); /** * Method to link the native shader program. */ abstract ShaderError linkShaderProgram(Context ctx, ShaderProgramId shaderProgramId, ShaderId[] shaderIds); /** * Method to bind a vertex attribute name to the specified index. */ abstract ShaderError bindVertexAttrName(Context ctx, ShaderProgramId shaderProgramId, String attrName, int attrIndex); /** * Method to lookup a list of (uniform) shader attribute names and return * information about the attributes. */ abstract void lookupShaderAttrNames(Context ctx, ShaderProgramId shaderProgramId, String[] attrNames, AttrNameInfo[] attrNameInfoArr); /* * Method to lookup a list of vertex attribute names. */ abstract void lookupVertexAttrNames(Context ctx, ShaderProgramId shaderProgramId, String[] attrNames, boolean[] errArr); /** * Method to use the native shader program. */ abstract ShaderError enableShaderProgram(Context ctx, ShaderProgramId shaderProgramId); /** * Method to disable the native shader program. */ abstract ShaderError disableShaderProgram(Context ctx); // ShaderAttributeValue methods abstract ShaderError setUniform1i(Context ctx, ShaderProgramId shaderProgramId, ShaderAttrLoc uniformLocation, int value); abstract ShaderError setUniform1f(Context ctx, ShaderProgramId shaderProgramId, ShaderAttrLoc uniformLocation, float value); abstract ShaderError setUniform2i(Context ctx, ShaderProgramId shaderProgramId, ShaderAttrLoc uniformLocation, int[] value); abstract ShaderError setUniform2f(Context ctx, ShaderProgramId shaderProgramId, ShaderAttrLoc uniformLocation, float[] value); abstract ShaderError setUniform3i(Context ctx, ShaderProgramId shaderProgramId, ShaderAttrLoc uniformLocation, int[] value); abstract ShaderError setUniform3f(Context ctx, ShaderProgramId shaderProgramId, ShaderAttrLoc uniformLocation, float[] value); abstract ShaderError setUniform4i(Context ctx, ShaderProgramId shaderProgramId, ShaderAttrLoc uniformLocation, int[] value); abstract ShaderError setUniform4f(Context ctx, ShaderProgramId shaderProgramId, ShaderAttrLoc uniformLocation, float[] value); abstract ShaderError setUniformMatrix3f(Context ctx, ShaderProgramId shaderProgramId, ShaderAttrLoc uniformLocation, float[] value); abstract ShaderError setUniformMatrix4f(Context ctx, ShaderProgramId shaderProgramId, ShaderAttrLoc uniformLocation, float[] value); // ShaderAttributeArray methods abstract ShaderError setUniform1iArray(Context ctx, ShaderProgramId shaderProgramId, ShaderAttrLoc uniformLocation, int numElements, int[] value); abstract ShaderError setUniform1fArray(Context ctx, ShaderProgramId shaderProgramId, ShaderAttrLoc uniformLocation, int numElements, float[] value); abstract ShaderError setUniform2iArray(Context ctx, ShaderProgramId shaderProgramId, ShaderAttrLoc uniformLocation, int numElements, int[] value); abstract ShaderError setUniform2fArray(Context ctx, ShaderProgramId shaderProgramId, ShaderAttrLoc uniformLocation, int numElements, float[] value); abstract ShaderError setUniform3iArray(Context ctx, ShaderProgramId shaderProgramId, ShaderAttrLoc uniformLocation, int numElements, int[] value); abstract ShaderError setUniform3fArray(Context ctx, ShaderProgramId shaderProgramId, ShaderAttrLoc uniformLocation, int numElements, float[] value); abstract ShaderError setUniform4iArray(Context ctx, ShaderProgramId shaderProgramId, ShaderAttrLoc uniformLocation, int numElements, int[] value); abstract ShaderError setUniform4fArray(Context ctx, ShaderProgramId shaderProgramId, ShaderAttrLoc uniformLocation, int numElements, float[] value); abstract ShaderError setUniformMatrix3fArray(Context ctx, ShaderProgramId shaderProgramId, ShaderAttrLoc uniformLocation, int numElements, float[] value); abstract ShaderError setUniformMatrix4fArray(Context ctx, ShaderProgramId shaderProgramId, ShaderAttrLoc uniformLocation, int numElements, float[] value); /** * Method to return a flag indicating whether this * ShaderProgram is supported on the specified Canvas. */ abstract boolean isSupported(Canvas3D cv); @Override void setLive(boolean backgroundGroup, int refCount) { // System.err.println("ShaderProgramRetained.setLive()"); if (shaders != null) { for (int i = 0; i < shaders.length; i++){ shaders[i].setLive(backgroundGroup, refCount); } } super.doSetLive(backgroundGroup, refCount); super.markAsLive(); } @Override void clearLive(int refCount) { // System.err.println("ShaderProgramRetained.clearLive()"); super.clearLive(refCount); if (shaders != null) { for (int i = 0; i < shaders.length; i++) { shaders[i].clearLive(refCount); } } } /** * Method to enable the native shader program. */ private ShaderError enableShaderProgram(Canvas3D cv, int cvRdrIndex) { assert(cvRdrIndex >= 0); synchronized(resourceLock) { return enableShaderProgram(cv.ctx, shaderProgramData[cvRdrIndex].getShaderProgramId()); } } /** * Method to disable the native shader program. */ private ShaderError disableShaderProgram(Canvas3D cv) { return disableShaderProgram(cv.ctx); } /** * Initializes a mirror object. */ @Override synchronized void initMirrorObject() { // Create mirror copy of shaders if (this.shaders == null) { ((ShaderProgramRetained)mirror).shaders = null; } else { ((ShaderProgramRetained)mirror).shaders = new ShaderRetained[this.shaders.length]; // Copy vertex and fragment shader for (int i = 0; i < this.shaders.length; i++) { ((ShaderProgramRetained)mirror).shaders[i] = (ShaderRetained)this.shaders[i].mirror; } } ((ShaderProgramRetained)mirror).shaderProgramData = null; // Create mirror copy of vertex attribute names if (this.vertexAttrNames == null) { ((ShaderProgramRetained)mirror).vertexAttrNames = null; } else { ((ShaderProgramRetained)mirror).vertexAttrNames = this.vertexAttrNames.clone(); } // Create mirror copy of shader attribute names if (this.shaderAttrNames == null) { ((ShaderProgramRetained)mirror).shaderAttrNames = null; } else { ((ShaderProgramRetained)mirror).shaderAttrNames = this.shaderAttrNames.clone(); } // Clear shader attribute error set ((ShaderProgramRetained)mirror).shaderAttrErrorSet = null; } /** * Update the "component" field of the mirror object with the given "value" */ @Override synchronized void updateMirrorObject(int component, Object value) { // ShaderProgram can't be modified once it is live. assert(false); System.err.println("ShaderProgramRetained : updateMirrorObject NOT IMPLEMENTED YET"); } /** * Method to create a ShaderProgramData object for the specified * canvas/renderer if it doesn't already exist. * * Issue 378 : reset the ShaderProgramData object if the context * has been recreated for the particular canvas / renderer. */ private void createShaderProgramData(int cvRdrIndex, long ctxTimeStamp) { // Create shaderProgram resources if it has not been done. synchronized(resourceLock) { if(shaderProgramData == null) { // We rely on Java to initial the array elements to null. shaderProgramData = new ShaderProgramData[cvRdrIndex+1]; } else if(shaderProgramData.length <= cvRdrIndex) { // We rely on Java to initial the array elements to null. ShaderProgramData[] tempSPData = new ShaderProgramData[cvRdrIndex+1]; System.arraycopy(shaderProgramData, 0, tempSPData, 0, shaderProgramData.length); shaderProgramData = tempSPData; } if(shaderProgramData[cvRdrIndex] == null) { shaderProgramData[cvRdrIndex] = new ShaderProgramData(); } else if (shaderProgramData[cvRdrIndex].getCtxTimeStamp() != ctxTimeStamp) { // Issue 378 - reset the shader program data for this canvas / renderer // if the context has been recreated shaderProgramData[cvRdrIndex].reset(); } shaderProgramData[cvRdrIndex].setCtxTimeStamp(ctxTimeStamp); } } /** * Method to create the native shader program. We must already have * called createShaderProgramData for this cvRdrIndex. */ private ShaderError createShaderProgram(Canvas3D cv, int cvRdrIndex) { // Create shaderProgram resources if it has not been done. synchronized(resourceLock) { assert shaderProgramData[cvRdrIndex].getShaderProgramId() == null; ShaderProgramId[] spIdArr = new ShaderProgramId[1]; ShaderError err = createShaderProgram(cv.ctx, spIdArr); if(err != null) { return err; } shaderProgramData[cvRdrIndex].setShaderProgramId(spIdArr[0]); } return null; } /** * Method to link the native shader program. */ private ShaderError linkShaderProgram(Canvas3D cv, int cvRdrIndex, ShaderRetained[] shaders) { synchronized(resourceLock) { ShaderId[] shaderIds = new ShaderId[shaders.length]; for(int i=0; i cvRdrIndex && shaderProgramData[cvRdrIndex] != null); // // Check whether an entry in the shaderProgramData array has been allocated // if (shaderProgramData == null || // shaderProgramData.length <= cvRdrIndex || // shaderProgramData[cvRdrIndex] == null) { // return; // } ShaderProgramId shaderProgramId = shaderProgramData[cvRdrIndex].getShaderProgramId(); // Nothing to do if the shaderProgramId is null if (shaderProgramId == null) { return; } // Destroy the native resource, set the ID to null for this canvas/renderer, // and clear the bit in the resourceCreationMask // Ignore any possible shader error, because there is no meaningful way to report it destroyShaderProgram(cv.ctx, shaderProgramId); // Reset this ShaderProgramData object. shaderProgramData[cvRdrIndex].reset(); } } /** * updateNative is called while traversing the RenderBin to * update the shader program state */ void updateNative(Canvas3D cv, boolean enable) { // System.err.println("ShaderProgramRetained.updateNative : "); final boolean useSharedCtx = cv.useSharedCtx && cv.screen.renderer.sharedCtx != null; int cvRdrIndex; long ctxTimeStamp; if (useSharedCtx) { cvRdrIndex = cv.screen.renderer.rendererId; ctxTimeStamp = cv.screen.renderer.sharedCtxTimeStamp; } else { cvRdrIndex = cv.canvasId; ctxTimeStamp = cv.ctxTimeStamp; } // Create ShaderProgramData object for this canvas/renderer if it doesn't already exist createShaderProgramData(cvRdrIndex, ctxTimeStamp); // Check whether this shader program type is supported for this canvas if (!verifyShaderProgramSupported(cv)) { return; } // Just disable shader program and return if enable parameter is set to false if (!enable) { // Given the current design, disableShaderProgram cannot return a non-null value, // so no need to check it disableShaderProgram(cv); return; } // Just disable shader program and return if array of shaders is empty, // or if a previous attempt to link resulted in an error if (shaders == null || shaders.length == 0 || linkErrorOccurred) { disableShaderProgram(cv); return; } boolean loadShaderProgram = false; // flag indicating whether to reload all shaderProgram states if (getShaderProgramData(cvRdrIndex).getShaderProgramId() == null) { loadShaderProgram = true; } //System.err.println(".... loadShaderProgram = " + loadShaderProgram); //System.err.println(".... resourceCreationMask= " + resourceCreationMask); ShaderError err = null; boolean errorOccurred = false; if (loadShaderProgram) { if (useSharedCtx) { // TODO : Need to test useSharedCtx case. ** Untested case ** cv.makeCtxCurrent(cv.screen.renderer.sharedCtx); } // Create shader resources if not already done for(int i=0; i < shaders.length; i++) { // Create ShaderProgramData object for this canvas/renderer if it doesn't already exist shaders[i].createShaderData(cvRdrIndex, ctxTimeStamp); if (shaders[i].compileErrorOccurred) { errorOccurred = true; } else { err = createShader(cv, cvRdrIndex, shaders[i]); if (err != null) { err.setShaderProgram((ShaderProgram)this.source); err.setShader((Shader)shaders[i].source); err.setCanvas3D(cv); notifyErrorListeners(cv, err); errorOccurred = true; } else { err = compileShader(cv, cvRdrIndex, shaders[i]); if (err != null) { err.setShaderProgram((ShaderProgram)this.source); err.setShader((Shader)shaders[i].source); err.setCanvas3D(cv); notifyErrorListeners(cv, err); destroyShader(cv, cvRdrIndex, shaders[i]); shaders[i].compileErrorOccurred = true; errorOccurred = true; } } } } // Create shader program if (!errorOccurred) { err = createShaderProgram(cv, cvRdrIndex); if (err != null) { err.setShaderProgram((ShaderProgram)this.source); err.setCanvas3D(cv); notifyErrorListeners(cv, err); errorOccurred = true; } } boolean linked = getShaderProgramData(cvRdrIndex).isLinked(); if (!linked) { // Bind vertex attribute names if (!errorOccurred) { if (vertexAttrNames != null) { // System.err.println("vertexAttrNames.length = " + vertexAttrNames.length); for (int i = 0; i < vertexAttrNames.length; i++) { err = bindVertexAttrName(cv, cvRdrIndex, vertexAttrNames[i], i); // Report non-fatal error, if one was detected if (err != null) { err.setShaderProgram((ShaderProgram)this.source); err.setCanvas3D(cv); notifyErrorListeners(cv, err); } } } } // Link shader program if (!errorOccurred) { err = linkShaderProgram(cv, cvRdrIndex, shaders); if (err != null) { err.setShaderProgram((ShaderProgram)this.source); err.setCanvas3D(cv); notifyErrorListeners(cv, err); destroyShaderProgram(cv, cvRdrIndex); linkErrorOccurred = true; errorOccurred = true; } } // lookup vertex attribute names if (!errorOccurred) { if (vertexAttrNames != null) { lookupVertexAttrNames(cv, cvRdrIndex, vertexAttrNames); } } // Lookup shader attribute names if (!errorOccurred) { if (shaderAttrNames != null) { // System.err.println("shaderAttrNames.length = " + shaderAttrNames.length); lookupShaderAttrNames(cv, cvRdrIndex, shaderAttrNames); } } } // Restore current context if we changed it to the shareCtx if (useSharedCtx) { cv.makeCtxCurrent(cv.ctx); } // If compilation or link error occured, disable shader program and return if (errorOccurred) { disableShaderProgram(cv); return; } } // Now we can enable the shader program enableShaderProgram(cv, cvRdrIndex); } /** * Update native value for ShaderAttributeValue class */ ShaderError setUniformAttrValue(Context ctx, ShaderProgramId shaderProgramId, ShaderAttrLoc loc, ShaderAttributeValueRetained sav) { switch (sav.getClassType()) { case ShaderAttributeObjectRetained.TYPE_INTEGER: return setUniform1i(ctx, shaderProgramId, loc, ((int[])sav.attrWrapper.getRef())[0]); case ShaderAttributeObjectRetained.TYPE_FLOAT: return setUniform1f(ctx, shaderProgramId, loc, ((float[])sav.attrWrapper.getRef())[0]); case ShaderAttributeObjectRetained.TYPE_TUPLE2I: return setUniform2i(ctx, shaderProgramId, loc, (int[])sav.attrWrapper.getRef()); case ShaderAttributeObjectRetained.TYPE_TUPLE2F: return setUniform2f(ctx, shaderProgramId, loc, (float[])sav.attrWrapper.getRef()); case ShaderAttributeObjectRetained.TYPE_TUPLE3I: return setUniform3i(ctx, shaderProgramId, loc, (int[])sav.attrWrapper.getRef()); case ShaderAttributeObjectRetained.TYPE_TUPLE3F: return setUniform3f(ctx, shaderProgramId, loc, (float[])sav.attrWrapper.getRef()); case ShaderAttributeObjectRetained.TYPE_TUPLE4I: return setUniform4i(ctx, shaderProgramId, loc, (int[])sav.attrWrapper.getRef()); case ShaderAttributeObjectRetained.TYPE_TUPLE4F: return setUniform4f(ctx, shaderProgramId, loc, (float[])sav.attrWrapper.getRef()); case ShaderAttributeObjectRetained.TYPE_MATRIX3F: return setUniformMatrix3f(ctx, shaderProgramId, loc, (float[])sav.attrWrapper.getRef()); case ShaderAttributeObjectRetained.TYPE_MATRIX4F: return setUniformMatrix4f(ctx, shaderProgramId, loc, (float[])sav.attrWrapper.getRef()); default: // Should never get here assert false : "Unrecognized ShaderAttributeValue classType"; return null; } } /** * Update native value for ShaderAttributeArray class */ ShaderError setUniformAttrArray(Context ctx, ShaderProgramId shaderProgramId, ShaderAttrLoc loc, ShaderAttributeArrayRetained saa) { switch (saa.getClassType()) { case ShaderAttributeObjectRetained.TYPE_INTEGER: return setUniform1iArray(ctx, shaderProgramId, loc, saa.length(), ((int[])saa.attrWrapper.getRef())); case ShaderAttributeObjectRetained.TYPE_FLOAT: return setUniform1fArray(ctx, shaderProgramId, loc, saa.length(), ((float[])saa.attrWrapper.getRef())); case ShaderAttributeObjectRetained.TYPE_TUPLE2I: return setUniform2iArray(ctx, shaderProgramId, loc, saa.length(), (int[])saa.attrWrapper.getRef()); case ShaderAttributeObjectRetained.TYPE_TUPLE2F: return setUniform2fArray(ctx, shaderProgramId, loc, saa.length(), (float[])saa.attrWrapper.getRef()); case ShaderAttributeObjectRetained.TYPE_TUPLE3I: return setUniform3iArray(ctx, shaderProgramId, loc, saa.length(), (int[])saa.attrWrapper.getRef()); case ShaderAttributeObjectRetained.TYPE_TUPLE3F: return setUniform3fArray(ctx, shaderProgramId, loc, saa.length(), (float[])saa.attrWrapper.getRef()); case ShaderAttributeObjectRetained.TYPE_TUPLE4I: return setUniform4iArray(ctx, shaderProgramId, loc, saa.length(), (int[])saa.attrWrapper.getRef()); case ShaderAttributeObjectRetained.TYPE_TUPLE4F: return setUniform4fArray(ctx, shaderProgramId, loc, saa.length(), (float[])saa.attrWrapper.getRef()); case ShaderAttributeObjectRetained.TYPE_MATRIX3F: return setUniformMatrix3fArray(ctx, shaderProgramId, loc, saa.length(), (float[])saa.attrWrapper.getRef()); case ShaderAttributeObjectRetained.TYPE_MATRIX4F: return setUniformMatrix4fArray(ctx, shaderProgramId, loc, saa.length(), (float[])saa.attrWrapper.getRef()); default: // Should never get here assert false : "Unrecognized ShaderAttributeArray classType"; return null; } } void setShaderAttributes(Canvas3D cv, ShaderAttributeSetRetained attributeSet) { final boolean useSharedCtx = cv.useSharedCtx && cv.screen.renderer.sharedCtx != null; final int cvRdrIndex = useSharedCtx ? cv.screen.renderer.rendererId : cv.canvasId; ShaderProgramData spData = getShaderProgramData(cvRdrIndex); // Just return if shader program wasn't linked successfully if (!spData.isLinked()) { return; } ShaderProgramId shaderProgramId = spData.getShaderProgramId(); Iterator attrs = attributeSet.getAttrs().values().iterator(); while (attrs.hasNext()) { ShaderError err = null; ShaderAttributeRetained saRetained = attrs.next(); // Lookup attribute info for the specified attrName; null means // that the name does not appear in the ShaderProgram, so we will // report an error. AttrNameInfo attrNameInfo = spData.getAttrNameInfo(saRetained.getAttributeName()); if(attrNameInfo == null) { // System.err.println("ShaderProgramRetained : attrLocation (" + saRetained.getAttributeName() + ") is null."); String errMsg = "Attribute name not set in ShaderProgram: " + saRetained.getAttributeName(); // TODO: I18N err = new ShaderError(ShaderError.SHADER_ATTRIBUTE_NAME_NOT_SET_ERROR, errMsg); } else { ShaderAttrLoc loc = attrNameInfo.getLocation(); if (loc != null) { if (saRetained instanceof ShaderAttributeValueRetained) { ShaderAttributeValueRetained savRetained = (ShaderAttributeValueRetained)saRetained; if (attrNameInfo.isArray() || (savRetained.getClassType() != attrNameInfo.getType())) { String errMsg = "Attribute type mismatch: " + savRetained.getAttributeName(); // TODO: I18N err = new ShaderError(ShaderError.SHADER_ATTRIBUTE_TYPE_ERROR, errMsg); } else { err = setUniformAttrValue(cv.ctx, shaderProgramId, loc, savRetained); } } else if (saRetained instanceof ShaderAttributeArrayRetained) { ShaderAttributeArrayRetained saaRetained = (ShaderAttributeArrayRetained)saRetained; if (!attrNameInfo.isArray() || (saaRetained.getClassType() != attrNameInfo.getType())) { String errMsg = "Attribute type mismatch: " + saaRetained.getAttributeName(); // TODO: I18N err = new ShaderError(ShaderError.SHADER_ATTRIBUTE_TYPE_ERROR, errMsg); } else { err = setUniformAttrArray(cv.ctx, shaderProgramId, loc, saaRetained); } } else if (saRetained instanceof ShaderAttributeBindingRetained) { assert false; throw new RuntimeException("not implemented"); } else { assert false; } } } if (err != null) { // Before reporting the ShaderAttribute error, check // whether it has already been reported for this ShaderProgram if (shaderAttrErrorSet == null) { shaderAttrErrorSet = new HashSet(); } if (shaderAttrErrorSet.add((ShaderAttribute) saRetained.source)) { err.setShaderProgram((ShaderProgram)this.source); err.setShaderAttributeSet((ShaderAttributeSet)attributeSet.source); err.setShaderAttribute((ShaderAttribute)saRetained.source); err.setCanvas3D(cv); notifyErrorListeners(cv, err); } } } } class ShaderProgramData extends Object { // issue 378 - time stamp of context creation for this Canvas private long ctxTimeStamp; // shaderProgramId use by native code. private ShaderProgramId shaderProgramId = null; // linked flag for native. private boolean linked = false; // A map of locations for ShaderAttributes. private HashMap attrNameInfoMap = new HashMap(); /** ShaderProgramData Constructor */ ShaderProgramData() { } void reset() { ctxTimeStamp = 0L; shaderProgramId = null; linked = false; attrNameInfoMap.clear(); } long getCtxTimeStamp() { return ctxTimeStamp; } void setCtxTimeStamp(long ctxTimeStamp) { this.ctxTimeStamp = ctxTimeStamp; } void setShaderProgramId(ShaderProgramId shaderProgramId) { this.shaderProgramId = shaderProgramId; } ShaderProgramId getShaderProgramId() { return this.shaderProgramId; } void setLinked(boolean linked) { this.linked = linked; } boolean isLinked() { return linked; } void setAttrNameInfo(String shaderAttribute, AttrNameInfo attrNameInfo) { assert (shaderAttribute != null); attrNameInfoMap.put(shaderAttribute, attrNameInfo); } AttrNameInfo getAttrNameInfo(String shaderAttribute) { return attrNameInfoMap.get(shaderAttribute); } } // Data associated with an attribute name class AttrNameInfo { void setLocation(ShaderAttrLoc loc) { this.loc = loc; } ShaderAttrLoc getLocation() { return loc; } void setType(int type) { this.type = type; } int getType() { return type; } boolean isArray() { return isArray; } void setArray(boolean isArray) { this.isArray = isArray; } // Location of attribute name in linked shader program private ShaderAttrLoc loc; // boolean indicating whether the attribute is an array private boolean isArray; // type of shader attribute private int type; } }