From 7a2e20caac9db6f789a7b3fab344b9758af45335 Mon Sep 17 00:00:00 2001 From: Harvey Harrison Date: Sun, 19 Apr 2015 21:02:06 -0700 Subject: j3dcore: flatten the directory structure a bit Signed-off-by: Harvey Harrison --- src/javax/media/j3d/Renderer.java | 1751 +++++++++++++++++++++++++++++++++++++ 1 file changed, 1751 insertions(+) create mode 100644 src/javax/media/j3d/Renderer.java (limited to 'src/javax/media/j3d/Renderer.java') diff --git a/src/javax/media/j3d/Renderer.java b/src/javax/media/j3d/Renderer.java new file mode 100644 index 0000000..6362672 --- /dev/null +++ b/src/javax/media/j3d/Renderer.java @@ -0,0 +1,1751 @@ +/* + * Copyright 1997-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. + * + */ + +/* + * Portions of this code were derived from work done by the Blackdown + * group (www.blackdown.org), who did the initial Linux implementation + * of the Java 3D API. + */ + +package javax.media.j3d; + +import java.awt.GraphicsConfiguration; +import java.awt.Point; +import java.awt.image.BufferedImage; +import java.awt.image.ImageObserver; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.logging.Level; + + +class Renderer extends J3dThread { + + // This action causes this thread to wait + static final int WAIT = 0; + + // This action causes this thread to notify the view, and then wait. + static final int NOTIFY_AND_WAIT = 1; + + // This action causes this thread to be notified + static final int NOTIFY = 2; + + // The following are DecalGroup rendering states + static final int DECAL_NONE = 0; + static final int DECAL_1ST_CHILD = 1; + static final int DECAL_NTH_CHILD = 2; + + // stuff for scene antialiasing + static final int NUM_ACCUMULATION_SAMPLES = 8; + + static final float ACCUM_SAMPLES_X[] = + { -0.54818f, 0.56438f, 0.39462f, -0.54498f, + -0.83790f, -0.39263f, 0.32254f, 0.84216f}; + + static final float ACCUM_SAMPLES_Y[] = + { 0.55331f, -0.53495f, 0.41540f, -0.52829f, + 0.82102f, -0.27383f, 0.09133f, -0.84399f}; + + static final float accumValue = 1.0f / NUM_ACCUMULATION_SAMPLES; + + // The following are Render arguments + static final int RENDER = 0; + static final int SWAP = 1; + static final int REQUESTRENDER = 2; + static final int REQUESTCLEANUP = 3; + + // Renderer Structure used for the messaging to the renderer + RendererStructure rendererStructure = new RendererStructure(); + + + // vworldtoVpc matrix for background geometry + Transform3D bgVworldToVpc = new Transform3D(); + + private static int numInstances = 0; + private int instanceNum = -1; + + // Local copy of sharedStereZBuffer flag + boolean sharedStereoZBuffer; + + // This is the id for the underlying sharable graphics context + Context sharedCtx = null; + + // since the sharedCtx id can be the same as the previous one, + // we need to keep a time stamp to differentiate the contexts with the + // same id + long sharedCtxTimeStamp = 0; + + // display and drawable, used to free shared context + private Drawable sharedCtxDrawable = null; + + /** + * This is the id of the current rendering context + */ + Context currentCtx = null; + + /** + * This is the id of the current rendering drawable + */ + Drawable currentDrawable = null; + + // an unique bit to identify this renderer + int rendererBit = 0; + // an unique number to identify this renderer : ( rendererBit = 1 << rendererId) + int rendererId = 0; + +// List of renderMolecules that are dirty due to additions +// or removal of renderAtoms from their display list set +// of renderAtoms +ArrayList dirtyRenderMoleculeList = new ArrayList(); + +// List of individual dlists that need to be rebuilt +ArrayList dirtyRenderAtomList = new ArrayList(); + +// List of (Rm, rInfo) pair of individual dlists that need to be rebuilt +ArrayList dirtyDlistPerRinfoList = new ArrayList(); + +// Texture and display list that should be freed +ArrayList textureIdResourceFreeList = new ArrayList(); +ArrayList displayListResourceFreeList = new ArrayList(); + +// Texture that should be reload +ArrayList textureReloadList = new ArrayList(); + + J3dMessage[] renderMessage; + + // The screen for this Renderer. Note that this renderer may share + // by both on screen and off screen. When view unregister, we need + // to set both reference to null. + Screen3D onScreen; + Screen3D offScreen; + + // full screen anti-aliasing projection matrices + Transform3D accumLeftProj = new Transform3D(); + Transform3D accumRightProj = new Transform3D(); + Transform3D accumInfLeftProj = new Transform3D(); + Transform3D accumInfRightProj = new Transform3D(); + + // rendering messages + J3dMessage m[]; + int nmesg = 0; + + // List of contexts created + ArrayList listOfCtxs = new ArrayList(); + + // Parallel list of canvases + ArrayList listOfCanvases = new ArrayList(); + + boolean needToRebuildDisplayList = false; + + // True when either one of dirtyRenderMoleculeList, + // dirtyDlistPerRinfoList, dirtyRenderAtomList size > 0 + boolean dirtyDisplayList = false; + +// Remember OGL context resources to free +// before context is destroy. +// It is used when sharedCtx = true; +ArrayList textureIDResourceTable = new ArrayList(5); + + // Instrumentation of Java 3D renderer + private long lastSwapTime = System.nanoTime(); + + private synchronized int newInstanceNum() { + return (++numInstances); + } + + @Override + int getInstanceNum() { + if (instanceNum == -1) + instanceNum = newInstanceNum(); + return instanceNum; + } + + /** + * Constructs a new Renderer + */ + Renderer(ThreadGroup t) { + super(t); + setName("J3D-Renderer-" + getInstanceNum()); + + type = J3dThread.RENDER_THREAD; + rendererId = VirtualUniverse.mc.getRendererId(); + rendererBit = (1 << rendererId); + renderMessage = new J3dMessage[1]; + } + + + /** + * The main loop for the renderer. + */ + @Override + void doWork(long referenceTime) { + RenderBin renderBin = null; + Canvas3D cv, canvas=null; + Object firstArg; + View view = null; + int stereo_mode; + int num_stereo_passes, num_accum_passes = 1; + int pass, apass, i, j; + boolean doAccum = false; + double accumDx = 0.0f, accumDy = 0.0f; + double accumDxFactor = 1.0f, accumDyFactor = 1.0f; + + double accumLeftX = 0.0, accumLeftY = 0.0, + accumRightX = 0.0, accumRightY = 0.0, + accumInfLeftX = 0.0, accumInfLeftY = 0.0, + accumInfRightX = 0.0, accumInfRightY = 0.0; + int opArg; + Transform3D t3d = null; + + opArg = ((Integer)args[0]).intValue(); + + try { + if (opArg == SWAP) { + + Object [] swapArray = (Object[])args[2]; + + view = (View)args[3]; + + for (i=0; i 0; + + c.userStencilAvailable = + (userOwnsStencil && (c.actualStencilSize > 0)); + c.systemStencilAvailable = + (!userOwnsStencil && (c.actualStencilSize > 0)); + + c.sceneAntialiasingMultiSamplesAvailable = + c.hasSceneAntialiasingMultisample(); + + if (c.sceneAntialiasingMultiSamplesAvailable) { + c.sceneAntialiasingAvailable = true; + } else { + c.sceneAntialiasingAvailable = + c.hasSceneAntialiasingAccum(); + } + } catch (RuntimeException ex) { + ex.printStackTrace(); + + // Issue 260 : indicate fatal error and notify error listeners + c.setFatalError(); + RenderingError err = + new RenderingError(RenderingError.GRAPHICS_CONFIG_ERROR, + J3dI18N.getString("Renderer1")); + err.setCanvas3D(c); + err.setGraphicsDevice(c.graphicsConfiguration.getDevice()); + notifyErrorListeners(err); + } + GraphicsConfigTemplate3D.runMonitor(J3dThread.NOTIFY); + } else if (reqType == MasterControl.SET_QUERYPROPERTIES){ + try { + c.createQueryContext(); + } catch (RuntimeException ex) { + ex.printStackTrace(); + + // Issue 260 : indicate fatal error and notify error listeners + c.setFatalError(); + RenderingError err = + new RenderingError(RenderingError.CONTEXT_CREATION_ERROR, + J3dI18N.getString("Renderer2")); + err.setCanvas3D(c); + err.setGraphicsDevice(c.graphicsConfiguration.getDevice()); + notifyErrorListeners(err); + } + // currentCtx change after we create a new context + GraphicsConfigTemplate3D.runMonitor(J3dThread.NOTIFY); + currentCtx = null; + currentDrawable = null; + } + } else if (secondArg instanceof Integer) { + // Issue 121 - This was formerly used as a message from + // the now-nonexistant TextureRetained finalize() method + // to free the texture id + throw new AssertionError(); + } else if (secondArg instanceof GeometryArrayRetained) { + // message from GeometryArrayRetained + // clearLive() to free D3D array + //((GeometryArrayRetained) secondArg).freeD3DArray(false); + } else if (secondArg instanceof GraphicsConfigTemplate3D) { + GraphicsConfigTemplate3D gct = + (GraphicsConfigTemplate3D) secondArg; + Integer reqType = (Integer) m[nmesg].args[2]; + if (reqType == MasterControl.GETBESTCONFIG) { + GraphicsConfiguration gcfg = null; + GraphicsConfiguration [] gcList = (GraphicsConfiguration []) gct.testCfg; + try { + gcfg = Pipeline.getPipeline().getBestConfiguration(gct, gcList); + } catch (NullPointerException npe) { + npe.printStackTrace(); + } catch (RuntimeException ex) { + ex.printStackTrace(); + + // Issue 260 : notify error listeners + RenderingError err = + new RenderingError(RenderingError.GRAPHICS_CONFIG_ERROR, + J3dI18N.getString("Renderer3")); + err.setGraphicsDevice(gcList[0].getDevice()); + notifyErrorListeners(err); + } + + gct.testCfg = gcfg; + } else if (reqType == MasterControl.ISCONFIGSUPPORT) { + boolean rval = false; + GraphicsConfiguration gc = (GraphicsConfiguration) gct.testCfg; + try { + if (Pipeline.getPipeline().isGraphicsConfigSupported(gct, gc)) { + rval = true; + } + } catch (NullPointerException npe) { + npe.printStackTrace(); + } catch (RuntimeException ex) { + ex.printStackTrace(); + + // Issue 260 : notify error listeners + RenderingError err = + new RenderingError(RenderingError.GRAPHICS_CONFIG_ERROR, + J3dI18N.getString("Renderer4")); + err.setGraphicsDevice(gc.getDevice()); + notifyErrorListeners(err); + } + + gct.testCfg = Boolean.valueOf(rval); + } + GraphicsConfigTemplate3D.runMonitor(J3dThread.NOTIFY); + } + + m[nmesg++].decRefcount(); + continue; + } + + canvas = (Canvas3D) firstArg; + + renderType = m[nmesg].type; + + if (renderType == J3dMessage.CREATE_OFFSCREENBUFFER) { + // Fix for issue 18. + // Fix for issue 20. + + canvas.drawable = null; + try { + // Issue 396. Pass in a null ctx for 2 reasons : + // 1) We should not use ctx field directly without buffering in a msg. + // 2) canvas.ctx should be null. + canvas.drawable = + canvas.createOffScreenBuffer(null, + canvas.offScreenCanvasSize.width, + canvas.offScreenCanvasSize.height); + } catch (RuntimeException ex) { + ex.printStackTrace(); + } + + if (canvas.drawable == null) { + // Issue 260 : indicate fatal error and notify error listeners + canvas.setFatalError(); + RenderingError err = + new RenderingError(RenderingError.OFF_SCREEN_BUFFER_ERROR, + J3dI18N.getString("Renderer5")); + err.setCanvas3D(canvas); + err.setGraphicsDevice(canvas.graphicsConfiguration.getDevice()); + notifyErrorListeners(err); + } + + canvas.offScreenBufferPending = false; + m[nmesg++].decRefcount(); + continue; + } + else if (renderType == J3dMessage.DESTROY_CTX_AND_OFFSCREENBUFFER) { + Object[] obj = m[nmesg].args; + + // Fix for issue 175: destroy ctx & off-screen buffer + // Fix for issue 340: get display, drawable & ctx from msg + removeCtx(canvas, + (Drawable) obj[2], + (Context) obj[3], + false, !canvas.offScreen, true); + + canvas.offScreenBufferPending = false; + m[nmesg++].decRefcount(); + continue; + } else if (renderType == J3dMessage.ALLOCATE_CANVASID) { + canvas.allocateCanvasId(); + } else if (renderType == J3dMessage.FREE_CANVASID) { + canvas.freeCanvasId(); + } + + if ((canvas.view == null) || !canvas.firstPaintCalled) { + // This happen when the canvas just remove from the View + if (renderType == J3dMessage.RENDER_OFFSCREEN) { + canvas.offScreenRendering = false; + } + m[nmesg++].decRefcount(); + continue; + } + + if (!canvas.validCanvas && + (renderType != J3dMessage.RENDER_OFFSCREEN)) { + m[nmesg++].decRefcount(); + continue; + } + + if (renderType == J3dMessage.RESIZE_CANVAS) { + // render the image again after resize + VirtualUniverse.mc.sendRunMessage(canvas.view, J3dThread.RENDER_THREAD); + m[nmesg++].decRefcount(); + } else if (renderType == J3dMessage.TOGGLE_CANVAS) { + VirtualUniverse.mc.sendRunMessage(canvas.view, J3dThread.RENDER_THREAD); + m[nmesg++].decRefcount(); + } else if (renderType == J3dMessage.RENDER_IMMEDIATE) { + int command = ((Integer)m[nmesg].args[1]).intValue(); + //System.err.println("command= " + command); + if (canvas.isFatalError()) { + continue; + } + + try { + + switch (command) { + case GraphicsContext3D.CLEAR: + canvas.graphicsContext3D.doClear(); + break; + case GraphicsContext3D.DRAW: + canvas.graphicsContext3D.doDraw( + (Geometry)m[nmesg].args[2]); + break; + case GraphicsContext3D.SWAP: + canvas.doSwap(); + break; + case GraphicsContext3D.READ_RASTER: + canvas.graphicsContext3D.doReadRaster( + (Raster)m[nmesg].args[2]); + break; + case GraphicsContext3D.SET_APPEARANCE: + canvas.graphicsContext3D.doSetAppearance( + (Appearance)m[nmesg].args[2]); + break; + case GraphicsContext3D.SET_BACKGROUND: + canvas.graphicsContext3D.doSetBackground( + (Background)m[nmesg].args[2]); + break; + case GraphicsContext3D.SET_FOG: + canvas.graphicsContext3D.doSetFog( + (Fog)m[nmesg].args[2]); + break; + case GraphicsContext3D.SET_LIGHT: + canvas.graphicsContext3D.doSetLight( + (Light)m[nmesg].args[2], + ((Integer)m[nmesg].args[3]).intValue()); + break; + case GraphicsContext3D.INSERT_LIGHT: + canvas.graphicsContext3D.doInsertLight( + (Light)m[nmesg].args[2], + ((Integer)m[nmesg].args[3]).intValue()); + break; + case GraphicsContext3D.REMOVE_LIGHT: + canvas.graphicsContext3D.doRemoveLight( + ((Integer)m[nmesg].args[2]).intValue()); + break; + case GraphicsContext3D.ADD_LIGHT: + canvas.graphicsContext3D.doAddLight( + (Light)m[nmesg].args[2]); + break; + case GraphicsContext3D.SET_HI_RES: + canvas.graphicsContext3D.doSetHiRes( + (HiResCoord)m[nmesg].args[2]); + break; + case GraphicsContext3D.SET_MODEL_TRANSFORM: + t3d = (Transform3D)m[nmesg].args[2]; + canvas.graphicsContext3D.doSetModelTransform(t3d); + break; + case GraphicsContext3D.MULTIPLY_MODEL_TRANSFORM: + t3d = (Transform3D)m[nmesg].args[2]; + canvas.graphicsContext3D.doMultiplyModelTransform(t3d); + break; + case GraphicsContext3D.SET_SOUND: + canvas.graphicsContext3D.doSetSound( + (Sound)m[nmesg].args[2], + ((Integer)m[nmesg].args[3]).intValue()); + break; + case GraphicsContext3D.INSERT_SOUND: + canvas.graphicsContext3D.doInsertSound( + (Sound)m[nmesg].args[2], + ((Integer)m[nmesg].args[3]).intValue()); + break; + case GraphicsContext3D.REMOVE_SOUND: + canvas.graphicsContext3D.doRemoveSound( + ((Integer)m[nmesg].args[2]).intValue()); + break; + case GraphicsContext3D.ADD_SOUND: + canvas.graphicsContext3D.doAddSound( + (Sound)m[nmesg].args[2]); + break; + case GraphicsContext3D.SET_AURAL_ATTRIBUTES: + canvas.graphicsContext3D.doSetAuralAttributes( + (AuralAttributes)m[nmesg].args[2]); + break; + case GraphicsContext3D.SET_BUFFER_OVERRIDE: + canvas.graphicsContext3D.doSetBufferOverride( + ((Boolean)m[nmesg].args[2]).booleanValue()); + break; + case GraphicsContext3D.SET_FRONT_BUFFER_RENDERING: + canvas.graphicsContext3D.doSetFrontBufferRendering( + ((Boolean)m[nmesg].args[2]).booleanValue()); + break; + case GraphicsContext3D.SET_STEREO_MODE: + canvas.graphicsContext3D.doSetStereoMode( + ((Integer)m[nmesg].args[2]).intValue()); + break; + case GraphicsContext3D.FLUSH: + canvas.graphicsContext3D.doFlush( + ((Boolean)m[nmesg].args[2]).booleanValue()); + break; + case GraphicsContext3D.FLUSH2D: + canvas.graphics2D.doFlush(); + break; + case GraphicsContext3D.DRAWANDFLUSH2D: + Object ar[] = m[nmesg].args; + canvas.graphics2D.doDrawAndFlushImage( + (BufferedImage) ar[2], + ((Point) ar[3]).x, + ((Point) ar[3]).y, + (ImageObserver) ar[4]); + break; + case GraphicsContext3D.DISPOSE2D: + // Issue 583 - the graphics2D field may be null here + if (canvas.graphics2D != null) { + canvas.graphics2D.doDispose(); + } + break; + case GraphicsContext3D.SET_MODELCLIP: + canvas.graphicsContext3D.doSetModelClip( + (ModelClip)m[nmesg].args[2]); + break; + default: + break; + } + + } catch (RuntimeException ex) { + ex.printStackTrace(); + + // Issue 260 : indicate fatal error and notify error listeners + canvas.setFatalError(); + RenderingError err = + new RenderingError(RenderingError.CONTEXT_CREATION_ERROR, + J3dI18N.getString("Renderer6")); + err.setCanvas3D(canvas); + err.setGraphicsDevice(canvas.graphicsConfiguration.getDevice()); + notifyErrorListeners(err); + } + + m[nmesg++].decRefcount(); + } else { // retained mode rendering + long startRenderTime = 0L; + if (MasterControl.isStatsLoggable(Level.INFO)) { + // Instrumentation of Java 3D renderer + startRenderTime = System.nanoTime(); + } + + m[nmesg++].decRefcount(); + + if (canvas.isFatalError()) { + continue; + } + + ImageComponent2DRetained offBufRetained = null; + + if (renderType == J3dMessage.RENDER_OFFSCREEN) { + // Issue 131: set offScreenRendering flag here, since it + // otherwise won't be set for auto-off-screen rendering + // (which doesn't use renderOffScreenBuffer) + canvas.offScreenRendering = true; + if (canvas.drawable == null || !canvas.active) { + canvas.offScreenRendering = false; + continue; + } else { + offBufRetained = (ImageComponent2DRetained) + canvas.offScreenBuffer.retained; + + if (offBufRetained.isByReference()) { + offBufRetained.geomLock.getLock(); + } + + offBufRetained.evaluateExtensions(canvas); + + } + + } else if (!canvas.active) { + continue; + } + + // Issue 78 - need to get the drawingSurface info every + // frame; this is necessary since the HDC (window ID) + // on Windows can become invalidated without our + // being notified! + if (!canvas.offScreen) { + canvas.drawingSurfaceObject.getDrawingSurfaceObjectInfo(); + } + + renderBin = canvas.view.renderBin; + + // setup rendering context + + // We need to catch NullPointerException when the dsi + // gets yanked from us during a remove. + + if (canvas.useSharedCtx) { + + if (sharedCtx == null) { + sharedCtxDrawable = canvas.drawable; + + // Always lock for context create + if (!canvas.drawingSurfaceObject.renderLock()) { + if ((offBufRetained != null) && + offBufRetained.isByReference()) { + offBufRetained.geomLock.unLock(); + } + canvas.offScreenRendering = false; + break doneRender; + } + + synchronized (VirtualUniverse.mc.contextCreationLock) { + sharedCtx = null; + try { + sharedCtx = canvas.createNewContext(null, true); + } catch (RuntimeException ex) { + ex.printStackTrace(); + } + + if (sharedCtx == null) { + canvas.drawingSurfaceObject.unLock(); + if ((offBufRetained != null) && + offBufRetained.isByReference()) { + offBufRetained.geomLock.unLock(); + } + canvas.offScreenRendering = false; + + // Issue 260 : indicate fatal error and notify error listeners + canvas.setFatalError(); + RenderingError err = + new RenderingError(RenderingError.CONTEXT_CREATION_ERROR, + J3dI18N.getString("Renderer7")); + err.setCanvas3D(canvas); + err.setGraphicsDevice(canvas.graphicsConfiguration.getDevice()); + notifyErrorListeners(err); + + break doneRender; + } + sharedCtxTimeStamp = + VirtualUniverse.mc.getContextTimeStamp(); + + needToRebuildDisplayList = true; + } + + canvas.drawingSurfaceObject.unLock(); + } + } + + if (canvas.ctx == null) { + + // Always lock for context create + if (!canvas.drawingSurfaceObject.renderLock()) { + if ((offBufRetained != null) && + offBufRetained.isByReference()) { + offBufRetained.geomLock.unLock(); + } + canvas.offScreenRendering = false; + break doneRender; + } + + synchronized (VirtualUniverse.mc.contextCreationLock) { + canvas.ctx = null; + try { + canvas.ctx = canvas.createNewContext(sharedCtx, false); + } catch (RuntimeException ex) { + ex.printStackTrace(); + } + + if (canvas.ctx == null) { + canvas.drawingSurfaceObject.unLock(); + if ((offBufRetained != null) && + offBufRetained.isByReference()) { + offBufRetained.geomLock.unLock(); + } + canvas.offScreenRendering = false; + + // Issue 260 : indicate fatal error and notify error listeners + canvas.setFatalError(); + RenderingError err = + new RenderingError(RenderingError.CONTEXT_CREATION_ERROR, + J3dI18N.getString("Renderer7")); + err.setCanvas3D(canvas); + err.setGraphicsDevice(canvas.graphicsConfiguration.getDevice()); + notifyErrorListeners(err); + + break doneRender; + } + + if (canvas.graphics2D != null) { + canvas.graphics2D.init(); + } + + canvas.ctxTimeStamp = + VirtualUniverse.mc.getContextTimeStamp(); + listOfCtxs.add(canvas.ctx); + listOfCanvases.add(canvas); + + if (renderBin.nodeComponentList.size() > 0) { + for (i = 0; i < renderBin.nodeComponentList.size(); i++) { + NodeComponentRetained nc = (NodeComponentRetained)renderBin.nodeComponentList.get(i); + if(nc instanceof ImageComponentRetained) { + ((ImageComponentRetained)nc).evaluateExtensions(canvas); + } + } + } + + // enable separate specular color + canvas.enableSeparateSpecularColor(); + } + + // create the cache texture state in canvas + // for state download checking purpose + if (canvas.texUnitState == null) { + canvas.createTexUnitState(); + } + + canvas.resetImmediateRendering(); + canvas.drawingSurfaceObject.contextValidated(); + + if (!canvas.useSharedCtx) { + canvas.needToRebuildDisplayList = true; + } + canvas.drawingSurfaceObject.unLock(); + } else { + + if (canvas.isRunning) { + canvas.makeCtxCurrent(); + } + } + + + if (renderBin != null) { + if ((VirtualUniverse.mc.doDsiRenderLock) && + (!canvas.drawingSurfaceObject.renderLock())) { + if ((offBufRetained != null) && + offBufRetained.isByReference()) { + offBufRetained.geomLock.unLock(); + } + canvas.offScreenRendering = false; + break doneRender; + } + + // handle free resource + if (canvas.useSharedCtx) { + freeResourcesInFreeList(canvas); + } else { + canvas.freeResourcesInFreeList(canvas.ctx); + } + + if (VirtualUniverse.mc.doDsiRenderLock) { + canvas.drawingSurfaceObject.unLock(); + } + + // Issue 109 : removed copyOfCvCache now that we have + // a separate canvasViewCache for computing view frustum + CanvasViewCache cvCache = canvas.canvasViewCache; + + // Deadlock if we include updateViewCache in + // drawingSurfaceObject sync. + canvas.updateViewCache(false, null, null, + renderBin.geometryBackground != null); + + if ((VirtualUniverse.mc.doDsiRenderLock) && + (!canvas.drawingSurfaceObject.renderLock())) { + if ((offBufRetained != null) && + offBufRetained.isByReference()) { + offBufRetained.geomLock.unLock(); + } + canvas.offScreenRendering = false; + break doneRender; + } + + int cvWidth = cvCache.getCanvasWidth(); + int cvHeight = cvCache.getCanvasHeight(); + // setup viewport + canvas.setViewport(canvas.ctx, 0, 0, cvWidth, cvHeight); + + // rebuild the display list of all dirty renderMolecules. + if (canvas.useSharedCtx) { + if (needToRebuildDisplayList) { + renderBin.updateAllRenderMolecule( + this, canvas); + needToRebuildDisplayList = false; + } + + if (dirtyDisplayList) { + renderBin.updateDirtyDisplayLists(canvas, + dirtyRenderMoleculeList, + dirtyDlistPerRinfoList, + dirtyRenderAtomList,true); + dirtyDisplayList = false; + } + + // for shared context, download textures upfront + // to minimize the context switching overhead + int sz = textureReloadList.size(); + + if (sz > 0) { + for (j = sz-1; j>=0; j--) { + textureReloadList.get(j).reloadTextureSharedContext(canvas); + } + textureReloadList.clear(); + } + + } else { + // update each canvas + if (canvas.needToRebuildDisplayList) { + renderBin.updateAllRenderMolecule(canvas); + canvas.needToRebuildDisplayList = false; + } + if (canvas.dirtyDisplayList) { + renderBin.updateDirtyDisplayLists(canvas, + canvas.dirtyRenderMoleculeList, + canvas.dirtyDlistPerRinfoList, + canvas.dirtyRenderAtomList, false); + canvas.dirtyDisplayList = false; + } + } + + // lighting setup + if (canvas.view.localEyeLightingEnable != + canvas.ctxEyeLightingEnable) { + canvas.ctxUpdateEyeLightingEnable(canvas.ctx, + canvas.view.localEyeLightingEnable); + canvas.ctxEyeLightingEnable = + canvas.view.localEyeLightingEnable; + } + + + // stereo setup + boolean useStereo = cvCache.getUseStereo(); + if (useStereo) { + num_stereo_passes = 2; + stereo_mode = Canvas3D.FIELD_LEFT; + + sharedStereoZBuffer = + VirtualUniverse.mc.sharedStereoZBuffer; + } else { + num_stereo_passes = 1; + stereo_mode = Canvas3D.FIELD_ALL; + + // just in case user set flag - + // disable since we are not in stereo + sharedStereoZBuffer = false; + } + + // full screen anti-aliasing setup + if (canvas.view.getSceneAntialiasingEnable() && + canvas.sceneAntialiasingAvailable) { + + if (((canvas.extensionsSupported & Canvas3D.MULTISAMPLE) == 0) || + !canvas.sceneAntialiasingMultiSamplesAvailable) { + doAccum = true; + num_accum_passes = NUM_ACCUMULATION_SAMPLES; + + System.arraycopy( + cvCache.getLeftProjection().mat, + 0, accumLeftProj.mat, 0, 16); + + + accumDxFactor = ( + canvas.canvasViewCache.getPhysicalWindowWidth() / + canvas.canvasViewCache.getCanvasWidth())*canvas.view.fieldOfView; + + accumDyFactor = ( + canvas.canvasViewCache.getPhysicalWindowHeight() / + canvas.canvasViewCache.getCanvasHeight())*canvas.view.fieldOfView; + + + accumLeftX = accumLeftProj.mat[3]; + accumLeftY = accumLeftProj.mat[7]; + + if (useStereo) { + System.arraycopy( + cvCache.getRightProjection().mat, + 0, accumRightProj.mat, 0, 16); + accumRightX = accumRightProj.mat[3]; + accumRightY = accumRightProj.mat[7]; + } + + if (renderBin.geometryBackground != null) { + System.arraycopy( + cvCache.getInfLeftProjection().mat, + 0, accumInfLeftProj.mat, 0, 16); + accumInfLeftX = accumInfLeftProj.mat[3]; + accumInfLeftY = accumInfLeftProj.mat[7]; + if (useStereo) { + System.arraycopy( + cvCache.getInfRightProjection().mat, + 0, accumInfRightProj.mat, 0, 16); + accumInfRightX = accumInfRightProj.mat[3]; + accumInfRightY = accumInfRightProj.mat[7]; + } + } + } else { + + if (!canvas.isAntialiasingSet()) { + // System.err.println("Renderer : Enable FullSceneAntialiasing"); + + canvas.setFullSceneAntialiasing(canvas.ctx, true); + } + } + } else { + + if (canvas.isAntialiasingSet()) { + // System.err.println("Renderer : Disable SceneAntialiasing"); + canvas.setFullSceneAntialiasing(canvas.ctx, false); + } + } + + // background geometry setup + if (renderBin.geometryBackground != null) { + renderBin.updateInfVworldToVpc(); + } + + // setup default render mode - render to both eyes + canvas.setRenderMode(canvas.ctx, + Canvas3D.FIELD_ALL, + canvas.useDoubleBuffer); + + // clear background if not full screen antialiasing + // and not in stereo mode + if (!doAccum && !sharedStereoZBuffer) { + BackgroundRetained bg = renderBin.background; + + canvas.clear(bg, cvWidth, cvHeight); + + } + + // handle preRender callback + if (VirtualUniverse.mc.doDsiRenderLock) { + canvas.drawingSurfaceObject.unLock(); + } + canvas.view.inCanvasCallback = true; + + try { + canvas.preRender(); + } catch (RuntimeException e) { + System.err.println("Exception occurred during Canvas3D callback:"); + e.printStackTrace(); + } catch (Error e) { + // Issue 264 - catch Error so Renderer doesn't die + System.err.println("Error occurred during Canvas3D callback:"); + e.printStackTrace(); + } + canvas.view.inCanvasCallback = false; + + if ((VirtualUniverse.mc.doDsiRenderLock) && + (!canvas.drawingSurfaceObject.renderLock())) { + if ((offBufRetained != null) && + offBufRetained.isByReference()) { + offBufRetained.geomLock.unLock(); + } + canvas.offScreenRendering = false; + break doneRender; + } + + // render loop + for (pass = 0; pass < num_stereo_passes; pass++) { + if (doAccum) { + canvas.clearAccum(canvas.ctx); + } + canvas.setRenderMode(canvas.ctx, stereo_mode, + canvas.useDoubleBuffer); + + + + for (apass = 0; apass < num_accum_passes; apass++) { + + // jitter projection matrix and clear background + // for full screen anti-aliasing rendering + if (doAccum) { + accumDx = ACCUM_SAMPLES_X[apass] * + accumDxFactor; + accumDy = ACCUM_SAMPLES_Y[apass] * + accumDyFactor; + + accumLeftProj.mat[3] = accumLeftX + + accumLeftProj.mat[0] * accumDx + + accumLeftProj.mat[1] * accumDy; + + accumLeftProj.mat[7] = accumLeftY + + accumLeftProj.mat[4] * accumDx + + accumLeftProj.mat[5] * accumDy; + + if (useStereo) { + accumRightProj.mat[3] = accumRightX + + accumRightProj.mat[0] * accumDx + + accumRightProj.mat[1] * accumDy; + + accumRightProj.mat[7] = accumRightY + + accumRightProj.mat[4] * accumDx + + accumRightProj.mat[5] * accumDy; + } + + if (renderBin.geometryBackground != null) { + accumInfLeftProj.mat[3] = accumInfLeftX + + accumInfLeftProj.mat[0] * accumDx + + accumInfLeftProj.mat[1] * accumDy; + + accumInfLeftProj.mat[7] = accumInfLeftY + + accumInfLeftProj.mat[4] * accumDx + + accumInfLeftProj.mat[5] * accumDy; + + if (useStereo) { + accumInfRightProj.mat[3] = + accumInfRightX + + accumInfRightProj.mat[0] * accumDx + + accumInfRightProj.mat[1] * accumDy; + + accumInfRightProj.mat[7] = + accumInfRightY + + accumInfRightProj.mat[4] * accumDx + + accumInfRightProj.mat[5] * accumDy; + } + } + } + + // clear background for stereo and + // accumulation buffer cases + if (doAccum || sharedStereoZBuffer) { + BackgroundRetained bg = renderBin.background; + + canvas.clear(bg, cvWidth, cvHeight); + + } + + // render background geometry + if (renderBin.geometryBackground != null) { + + // setup rendering matrices + if (pass == 0) { + canvas.vpcToEc = + cvCache.getInfLeftVpcToEc(); + if (doAccum) { + canvas.setProjectionMatrix( + canvas.ctx, accumInfLeftProj); + } else { + canvas.setProjectionMatrix( + canvas.ctx, + cvCache.getInfLeftProjection()); + } + } else { + canvas.vpcToEc = + cvCache.getInfRightVpcToEc(); + if (doAccum) { + canvas.setProjectionMatrix( + canvas.ctx, accumInfRightProj); + } else { + canvas.setProjectionMatrix( + canvas.ctx, + cvCache.getInfRightProjection()); + } + } + canvas.vworldToEc.mul(canvas.vpcToEc, + cvCache.getInfVworldToVpc()); + + // render background geometry + renderBin.renderBackground(canvas); + } + + // setup rendering matrices + if (pass == 0) { + canvas.vpcToEc = cvCache.getLeftVpcToEc(); + if (doAccum) { + canvas.setProjectionMatrix(canvas.ctx, accumLeftProj); + } else { + canvas.setProjectionMatrix(canvas.ctx, + cvCache.getLeftProjection()); + } + } else { + canvas.vpcToEc = cvCache.getRightVpcToEc(); + if (doAccum) { + canvas.setProjectionMatrix( + canvas.ctx, accumRightProj); + } else { + canvas.setProjectionMatrix(canvas.ctx, + cvCache.getRightProjection()); + } + } + canvas.vworldToEc.mul(canvas.vpcToEc, + cvCache.getVworldToVpc()); + + + synchronized (cvCache) { + if (pass == 0) { + canvas.setFrustumPlanes(cvCache.getLeftFrustumPlanesInVworld()); + } else { + canvas.setFrustumPlanes(cvCache.getRightFrustumPlanesInVworld()); + } + } + + // Force view matrix dirty for each eye. + if (useStereo) { + canvas.canvasDirty |= Canvas3D.VIEW_MATRIX_DIRTY; + } + + // render opaque geometry + renderBin.renderOpaque(canvas); + + // render ordered geometry + renderBin.renderOrdered(canvas); + + // handle renderField callback + if (VirtualUniverse.mc.doDsiRenderLock) { + canvas.drawingSurfaceObject.unLock(); + } + canvas.view.inCanvasCallback = true; + try { + canvas.renderField(stereo_mode); + } catch (RuntimeException e) { + System.err.println("Exception occurred during Canvas3D callback:"); + e.printStackTrace(); + } catch (Error e) { + // Issue 264 - catch Error so Renderer doesn't die + System.err.println("Error occurred during Canvas3D callback:"); + e.printStackTrace(); + } + canvas.view.inCanvasCallback = false; + if ((VirtualUniverse.mc.doDsiRenderLock) && + (!canvas.drawingSurfaceObject.renderLock())) { + if ((offBufRetained != null) && + offBufRetained.isByReference()) { + offBufRetained.geomLock.unLock(); + } + canvas.offScreenRendering = false; + break doneRender; + } + + // render transparent geometry + renderBin.renderTransparent(canvas); + + if (doAccum) + canvas.accum(canvas.ctx, accumValue); + } + + if (doAccum) + canvas.accumReturn(canvas.ctx); + if (useStereo) { + stereo_mode = Canvas3D.FIELD_RIGHT; + canvas.rightStereoPass = true; + } + } + canvas.imageReady = true; + canvas.rightStereoPass = false; + + // reset renderMode + canvas.setRenderMode(canvas.ctx, + Canvas3D.FIELD_ALL, + canvas.useDoubleBuffer); + + // handle postRender callback + if (VirtualUniverse.mc.doDsiRenderLock) { + canvas.drawingSurfaceObject.unLock(); + } + canvas.view.inCanvasCallback = true; + + try { + canvas.postRender(); + } catch (RuntimeException e) { + System.err.println("Exception occurred during Canvas3D callback:"); + e.printStackTrace(); + } catch (Error e) { + // Issue 264 - catch Error so Renderer doesn't die + System.err.println("Error occurred during Canvas3D callback:"); + e.printStackTrace(); + } + canvas.view.inCanvasCallback = false; + + // end offscreen rendering + if (canvas.offScreenRendering) { + + canvas.syncRender(canvas.ctx, true); + canvas.endOffScreenRendering(); + canvas.offScreenRendering = false; + + // Issue 489 - don't call postSwap here for auto-offscreen, + // since it will be called later by the SWAP operation + if (canvas.manualRendering) { + // do the postSwap for offscreen here + canvas.view.inCanvasCallback = true; + try { + canvas.postSwap(); + } catch (RuntimeException e) { + System.err.println("Exception occurred during Canvas 3D callback:"); + e.printStackTrace(); + } catch (Error e) { + // Issue 264 - catch Error so Renderer doesn't die + System.err.println("Error occurred during Canvas3D callback:"); + e.printStackTrace(); + } + + if (offBufRetained.isByReference()) { + offBufRetained.geomLock.unLock(); + } + + canvas.view.inCanvasCallback = false; + + canvas.releaseCtx(); + } + } + + if (MasterControl.isStatsLoggable(Level.INFO)) { + // Instrumentation of Java 3D renderer + long deltaTime = System.nanoTime() - startRenderTime; + VirtualUniverse.mc.recordTime(MasterControl.TimeType.RENDER, deltaTime); + } + + } else { // if (renderBin != null) + if ((offBufRetained != null) && + offBufRetained.isByReference()) { + offBufRetained.geomLock.unLock(); + } + } + } + } + + // clear array to prevent memory leaks + if (opArg == RENDER) { + m[0] = null; + } else { + Arrays.fill(m, 0, totalMessages, null); + } + } + } catch (NullPointerException ne) { + // Print NPE, but otherwise ignore it + ne.printStackTrace(); + if (canvas != null) { + // drawingSurfaceObject will safely ignore + // this request if this is not lock before + canvas.drawingSurfaceObject.unLock(); + + } + } catch (RuntimeException ex) { + ex.printStackTrace(); + + if (canvas != null) { + // drawingSurfaceObject will safely ignore + // this request if this is not lock before + canvas.drawingSurfaceObject.unLock(); + } + + // Issue 260 : indicate fatal error and notify error listeners + canvas.setFatalError(); + RenderingError err = + new RenderingError(RenderingError.UNEXPECTED_RENDERING_ERROR, + J3dI18N.getString("Renderer8")); + err.setCanvas3D(canvas); + err.setGraphicsDevice(canvas.graphicsConfiguration.getDevice()); + notifyErrorListeners(err); + } + } + +// resource clean up +@Override +void shutdown() { + removeAllCtxs(); +} + + @Override + void cleanup() { + super.cleanup(); + renderMessage = new J3dMessage[1]; + rendererStructure = new RendererStructure(); + bgVworldToVpc = new Transform3D(); + sharedCtx = null; + sharedCtxTimeStamp = 0; + sharedCtxDrawable = null; + dirtyRenderMoleculeList.clear(); + dirtyRenderAtomList.clear(); + dirtyDlistPerRinfoList.clear(); + textureIdResourceFreeList.clear(); + displayListResourceFreeList.clear(); + onScreen = null; + offScreen = null; + m = null; + nmesg = 0; + } + + + // This is only invoked from removeCtx()/removeAllCtxs() + // with drawingSurface already lock + final void makeCtxCurrent(Context sharedCtx, Drawable drawable) { + if (sharedCtx != currentCtx || drawable != currentDrawable) { + Canvas3D.useCtx(sharedCtx, drawable); + /* + if(!Canvas3D.useCtx(sharedCtx, display, drawable)) { + Thread.dumpStack(); + System.err.println("useCtx Fail"); + } + */ + currentCtx = sharedCtx; + currentDrawable = drawable; + } + } + + // No need to free graphics2d and background if it is from + // Canvas3D postRequest() offScreen rendering since the + // user thread will not wait for it. Also we can just + // reuse it as Canvas3D did not destroy. + private void removeCtx(Canvas3D cv, Drawable drawable, Context ctx, + boolean resetCtx, boolean freeBackground, + boolean destroyOffScreenBuffer) { + + synchronized (VirtualUniverse.mc.contextCreationLock) { + if (ctx != null) { + int idx = listOfCtxs.indexOf(ctx); + if (idx >= 0) { + listOfCtxs.remove(idx); + listOfCanvases.remove(idx); + // Issue 326 : don't check display variable here + if ((drawable != null) && cv.added) { + // cv.ctx may reset to -1 here so we + // always use the ctx pass in. + if (cv.drawingSurfaceObject.renderLock()) { + // if it is the last one, free shared resources + if (sharedCtx != null) { + if (listOfCtxs.isEmpty()) { + makeCtxCurrent(sharedCtx, sharedCtxDrawable); + freeResourcesInFreeList(null); + freeContextResources(); + Canvas3D.destroyContext(sharedCtxDrawable, sharedCtx); + currentCtx = null; + currentDrawable = null; + } else { + freeResourcesInFreeList(cv); + } + cv.makeCtxCurrent(ctx, drawable); + } else { + cv.makeCtxCurrent(ctx, drawable); + cv.freeResourcesInFreeList(ctx); + } + cv.freeContextResources(this, freeBackground, ctx); + Canvas3D.destroyContext(drawable, ctx); + currentCtx = null; + currentDrawable = null; + cv.drawingSurfaceObject.unLock(); + } + } + } + + if (resetCtx) { + cv.ctx = null; + } + + if ((sharedCtx != null) && listOfCtxs.isEmpty()) { + sharedCtx = null; + sharedCtxTimeStamp = 0; + } + cv.ctxTimeStamp = 0; + } + + // Fix for issue 18. + // Since we are now the renderer thread, + // we can safely execute destroyOffScreenBuffer. + if(destroyOffScreenBuffer) { + cv.destroyOffScreenBuffer(ctx, drawable); + cv.offScreenBufferPending = false; + } + } + } + + void removeAllCtxs() { + Canvas3D cv; + + synchronized (VirtualUniverse.mc.contextCreationLock) { + + for (int i=listOfCanvases.size()-1; i >=0; i--) { + cv = listOfCanvases.get(i); + + if ((cv.screen != null) && (cv.ctx != null)) { + // Issue 326 : don't check display variable here + if ((cv.drawable != null) && cv.added) { + if (cv.drawingSurfaceObject.renderLock()) { + // We need to free sharedCtx resource + // first before last non-sharedCtx to + // workaround Nvidia driver bug under Linux + // that crash on freeTexture ID:4685156 + if ((i == 0) && (sharedCtx != null)) { + makeCtxCurrent(sharedCtx, sharedCtxDrawable); + freeResourcesInFreeList(null); + freeContextResources(); + Canvas3D.destroyContext(sharedCtxDrawable, sharedCtx); + currentCtx = null; + currentDrawable = null; + } + cv.makeCtxCurrent(); + cv.freeResourcesInFreeList(cv.ctx); + cv.freeContextResources(this, true, cv.ctx); + Canvas3D.destroyContext(cv.drawable, cv.ctx); + currentCtx = null; + currentDrawable = null; + cv.drawingSurfaceObject.unLock(); + } + } + } + + cv.ctx = null; + cv.ctxTimeStamp = 0; + } + + if (sharedCtx != null) { + sharedCtx = null; + sharedCtxTimeStamp = 0; + } + listOfCanvases.clear(); + listOfCtxs.clear(); + } + } + + // handle free resource in the FreeList + void freeResourcesInFreeList(Canvas3D cv) { + Iterator it; + boolean isFreeTex = (textureIdResourceFreeList.size() > 0); + boolean isFreeDL = (displayListResourceFreeList.size() > 0); + int val; + + if (isFreeTex || isFreeDL) { + if (cv != null) { + cv.makeCtxCurrent(sharedCtx); + } + + if (isFreeDL) { + for (it = displayListResourceFreeList.iterator(); it.hasNext();) { + val = it.next().intValue(); + if (val <= 0) { + continue; + } + Canvas3D.freeDisplayList(sharedCtx, val); + } + displayListResourceFreeList.clear(); + } + if (isFreeTex) { + for (it = textureIdResourceFreeList.iterator(); it.hasNext();) { + val = it.next().intValue(); + if (val <= 0) { + continue; + } + if (val >= textureIDResourceTable.size()) { + MasterControl.getCoreLogger().severe( + "Error in freeResourcesInFreeList : ResourceIDTableSize = " + + textureIDResourceTable.size() + + " val = " + val); + } else { + TextureRetained tex = textureIDResourceTable.get(val); + if (tex != null) { + synchronized (tex.resourceLock) { + tex.resourceCreationMask &= ~rendererBit; + if (tex.resourceCreationMask == 0) { + tex.freeTextureId(val); + } + } + } + + textureIDResourceTable.set(val, null); + } + Canvas3D.freeTexture(sharedCtx, val); + } + textureIdResourceFreeList.clear(); + } + if (cv != null) { + cv.makeCtxCurrent(cv.ctx); + } + } + } + +final void addTextureResource(int id, TextureRetained obj) { + if (textureIDResourceTable.size() <= id) { + for (int i=textureIDResourceTable.size(); + i < id; i++) { + textureIDResourceTable.add(null); + } + textureIDResourceTable.add(obj); + } else { + textureIDResourceTable.set(id, obj); + } + } + + void freeContextResources() { + TextureRetained tex; + + for (int id = textureIDResourceTable.size()-1; id >= 0; id--) { + tex = textureIDResourceTable.get(id); + if (tex == null) { + continue; + } + Canvas3D.freeTexture(sharedCtx, id); + synchronized (tex.resourceLock) { + tex.resourceCreationMask &= ~rendererBit; + if (tex.resourceCreationMask == 0) { + tex.freeTextureId(id); + } + } + } + textureIDResourceTable.clear(); + + // displayList is free in Canvas.freeContextResources() + } + + /** + * Send a message to the notification thread, which will call the + * shader error listeners. + */ + static void notifyErrorListeners(RenderingError err) { + J3dNotification notification = new J3dNotification(); + notification.type = J3dNotification.RENDERING_ERROR; + notification.universe = null;//cv.view.universe; + notification.args[0] = err; + VirtualUniverse.mc.sendNotification(notification); + } + + + // Default rendering error listener class + private static RenderingErrorListener defaultErrorListener = null; + + synchronized static RenderingErrorListener getDefaultErrorListener() { + if (defaultErrorListener == null) { + defaultErrorListener = new DefaultErrorListener(); + } + + return defaultErrorListener; + } + + static class DefaultErrorListener implements RenderingErrorListener { + @Override + public void errorOccurred(RenderingError error) { + System.err.println(); + System.err.println("DefaultRenderingErrorListener.errorOccurred:"); + error.printVerbose(); + System.exit(1); + } + } + +} -- cgit v1.2.3