0001: /*
0002: * $RCSfile: Renderer.java,v $
0003: *
0004: * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
0005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0006: *
0007: * This code is free software; you can redistribute it and/or modify it
0008: * under the terms of the GNU General Public License version 2 only, as
0009: * published by the Free Software Foundation. Sun designates this
0010: * particular file as subject to the "Classpath" exception as provided
0011: * by Sun in the LICENSE file that accompanied this code.
0012: *
0013: * This code is distributed in the hope that it will be useful, but WITHOUT
0014: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0015: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0016: * version 2 for more details (a copy is included in the LICENSE file that
0017: * accompanied this code).
0018: *
0019: * You should have received a copy of the GNU General Public License version
0020: * 2 along with this work; if not, write to the Free Software Foundation,
0021: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0022: *
0023: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0024: * CA 95054 USA or visit www.sun.com if you need additional information or
0025: * have any questions.
0026: *
0027: * $Revision: 1.24 $
0028: * $Date: 2008/02/28 20:17:28 $
0029: * $State: Exp $
0030: */
0031:
0032: /*
0033: * Portions of this code were derived from work done by the Blackdown
0034: * group (www.blackdown.org), who did the initial Linux implementation
0035: * of the Java 3D API.
0036: */
0037:
0038: package javax.media.j3d;
0039:
0040: import java.util.logging.Level;
0041: import javax.vecmath.*;
0042: import java.awt.*;
0043: import java.awt.image.*;
0044: import java.util.*;
0045:
0046: class Renderer extends J3dThread {
0047:
0048: // This action causes this thread to wait
0049: static final int WAIT = 0;
0050:
0051: // This action causes this thread to notify the view, and then wait.
0052: static final int NOTIFY_AND_WAIT = 1;
0053:
0054: // This action causes this thread to be notified
0055: static final int NOTIFY = 2;
0056:
0057: // The following are DecalGroup rendering states
0058: static final int DECAL_NONE = 0;
0059: static final int DECAL_1ST_CHILD = 1;
0060: static final int DECAL_NTH_CHILD = 2;
0061:
0062: // stuff for scene antialiasing
0063: static final int NUM_ACCUMULATION_SAMPLES = 8;
0064:
0065: static final float ACCUM_SAMPLES_X[] = { -0.54818f, 0.56438f,
0066: 0.39462f, -0.54498f, -0.83790f, -0.39263f, 0.32254f,
0067: 0.84216f };
0068:
0069: static final float ACCUM_SAMPLES_Y[] = { 0.55331f, -0.53495f,
0070: 0.41540f, -0.52829f, 0.82102f, -0.27383f, 0.09133f,
0071: -0.84399f };
0072:
0073: static final float accumValue = 1.0f / NUM_ACCUMULATION_SAMPLES;
0074:
0075: // The following are Render arguments
0076: static final int RENDER = 0;
0077: static final int SWAP = 1;
0078: static final int REQUESTRENDER = 2;
0079: static final int REQUESTCLEANUP = 3;
0080:
0081: // Renderer Structure used for the messaging to the renderer
0082: RendererStructure rendererStructure = new RendererStructure();
0083:
0084: // vworldtoVpc matrix for background geometry
0085: Transform3D bgVworldToVpc = new Transform3D();
0086:
0087: private static int numInstances = 0;
0088: private int instanceNum = -1;
0089:
0090: // Local copy of sharedStereZBuffer flag
0091: boolean sharedStereoZBuffer;
0092:
0093: // This is the id for the underlying sharable graphics context
0094: Context sharedCtx = null;
0095:
0096: // since the sharedCtx id can be the same as the previous one,
0097: // we need to keep a time stamp to differentiate the contexts with the
0098: // same id
0099: long sharedCtxTimeStamp = 0;
0100:
0101: // display and drawable, used to free shared context
0102: private long sharedCtxDisplay = 0;
0103: private Drawable sharedCtxDrawable = null;
0104:
0105: /**
0106: * This is the id of the current rendering context
0107: */
0108: Context currentCtx = null;
0109:
0110: /**
0111: * This is the id of the current rendering drawable
0112: */
0113: Drawable currentDrawable = null;
0114:
0115: // an unique bit to identify this renderer
0116: int rendererBit = 0;
0117: // an unique number to identify this renderer : ( rendererBit = 1 << rendererId)
0118: int rendererId = 0;
0119:
0120: // List of renderMolecules that are dirty due to additions
0121: // or removal of renderAtoms from their display list set
0122: // of renderAtoms
0123: ArrayList dirtyRenderMoleculeList = new ArrayList();
0124:
0125: // List of individual dlists that need to be rebuilt
0126: ArrayList dirtyRenderAtomList = new ArrayList();
0127:
0128: // List of (Rm, rInfo) pair of individual dlists that need to be rebuilt
0129: ArrayList dirtyDlistPerRinfoList = new ArrayList();
0130:
0131: // Texture and display list that should be freed
0132: ArrayList textureIdResourceFreeList = new ArrayList();
0133: ArrayList displayListResourceFreeList = new ArrayList();
0134:
0135: // Texture that should be reload
0136: ArrayList textureReloadList = new ArrayList();
0137:
0138: J3dMessage[] renderMessage;
0139:
0140: // The screen for this Renderer. Note that this renderer may share
0141: // by both on screen and off screen. When view unregister, we need
0142: // to set both reference to null.
0143: Screen3D onScreen;
0144: Screen3D offScreen;
0145:
0146: // full screen anti-aliasing projection matrices
0147: Transform3D accumLeftProj = new Transform3D();
0148: Transform3D accumRightProj = new Transform3D();
0149: Transform3D accumInfLeftProj = new Transform3D();
0150: Transform3D accumInfRightProj = new Transform3D();
0151:
0152: // rendering messages
0153: J3dMessage m[];
0154: int nmesg = 0;
0155:
0156: // List of contexts created
0157: ArrayList<Context> listOfCtxs = new ArrayList<Context>();
0158:
0159: // Parallel list of canvases
0160: ArrayList<Canvas3D> listOfCanvases = new ArrayList<Canvas3D>();
0161:
0162: boolean needToRebuildDisplayList = false;
0163: boolean needToResendTextureDown = false;
0164:
0165: // True when either one of dirtyRenderMoleculeList,
0166: // dirtyDlistPerRinfoList, dirtyRenderAtomList size > 0
0167: boolean dirtyDisplayList = false;
0168:
0169: // Remember OGL context resources to free
0170: // before context is destroy.
0171: // It is used when sharedCtx = true;
0172: ArrayList textureIDResourceTable = new ArrayList(5);
0173:
0174: // Instrumentation of Java 3D renderer
0175: private long lastSwapTime = System.nanoTime();
0176:
0177: private synchronized int newInstanceNum() {
0178: return (++numInstances);
0179: }
0180:
0181: int getInstanceNum() {
0182: if (instanceNum == -1)
0183: instanceNum = newInstanceNum();
0184: return instanceNum;
0185: }
0186:
0187: /**
0188: * Constructs a new Renderer
0189: */
0190: Renderer(ThreadGroup t) {
0191: super (t);
0192: setName("J3D-Renderer-" + getInstanceNum());
0193:
0194: type = J3dThread.RENDER_THREAD;
0195: rendererId = VirtualUniverse.mc.getRendererId();
0196: rendererBit = (1 << rendererId);
0197: renderMessage = new J3dMessage[1];
0198: }
0199:
0200: /**
0201: * The main loop for the renderer.
0202: */
0203: void doWork(long referenceTime) {
0204: RenderAtom ra;
0205: RenderBin renderBin = null;
0206: Canvas3D cv, canvas = null;
0207: Object firstArg;
0208: View view = null;
0209: Color3f col;
0210: int stereo_mode;
0211: int num_stereo_passes, num_render_passes, num_accum_passes = 1;
0212: int pass, apass, i, j, k;
0213: boolean doAccum = false;
0214: double accumDx = 0.0f, accumDy = 0.0f;
0215: double accumDxFactor = 1.0f, accumDyFactor = 1.0f;
0216:
0217: 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;
0218: int opArg, status;
0219: boolean done = false;
0220: Transform3D t3d = null;
0221:
0222: opArg = ((Integer) args[0]).intValue();
0223:
0224: try {
0225: if (opArg == SWAP) {
0226:
0227: Object[] swapArray = (Object[]) args[2];
0228:
0229: view = (View) args[3];
0230:
0231: for (i = 0; i < swapArray.length; i++) {
0232: cv = (Canvas3D) swapArray[i];
0233: if (!cv.isRunning) {
0234: continue;
0235: }
0236:
0237: doneSwap: try {
0238:
0239: if (!cv.validCanvas) {
0240: continue;
0241: }
0242:
0243: if (cv.active && (cv.ctx != null)
0244: && (cv.view != null) && (cv.imageReady)) {
0245: if (cv.useDoubleBuffer) {
0246: synchronized (cv.drawingSurfaceObject) {
0247: if (cv.validCtx) {
0248: if (VirtualUniverse.mc.doDsiRenderLock) {
0249: // Set doDsiLock flag for rendering based on system
0250: // property, If we force DSI lock for swap
0251: // buffer, we lose most of the parallelism that having
0252: // multiple renderers gives us.
0253:
0254: if (!cv.drawingSurfaceObject
0255: .renderLock()) {
0256: break doneSwap;
0257: }
0258: cv.makeCtxCurrent();
0259: cv.syncRender(cv.ctx, true);
0260: status = cv.swapBuffers(
0261: cv.ctx,
0262: cv.screen.display,
0263: cv.drawable);
0264: if (status != Canvas3D.NOCHANGE) {
0265: cv
0266: .resetRendering(status);
0267: }
0268: cv.drawingSurfaceObject
0269: .unLock();
0270: } else {
0271: cv.makeCtxCurrent();
0272:
0273: cv.syncRender(cv.ctx, true);
0274: status = cv.swapBuffers(
0275: cv.ctx,
0276: cv.screen.display,
0277: cv.drawable);
0278: if (status != Canvas3D.NOCHANGE) {
0279: cv
0280: .resetRendering(status);
0281: }
0282:
0283: }
0284: }
0285: }
0286: }
0287: cv.view.inCanvasCallback = true;
0288: try {
0289: cv.postSwap();
0290: } catch (RuntimeException e) {
0291: System.err
0292: .println("Exception occurred during Canvas3D callback:");
0293: e.printStackTrace();
0294: } catch (Error e) {
0295: // Issue 264 - catch Error so Renderer doesn't die
0296: System.err
0297: .println("Error occurred during Canvas3D callback:");
0298: e.printStackTrace();
0299: }
0300: // reset flag
0301: cv.imageReady = false;
0302: cv.view.inCanvasCallback = false;
0303: // Clear canvasDirty bit ONLY when postSwap() success
0304:
0305: if (MasterControl
0306: .isStatsLoggable(Level.INFO)) {
0307: // Instrumentation of Java 3D renderer
0308: long currSwapTime = System.nanoTime();
0309: long deltaTime = currSwapTime
0310: - lastSwapTime;
0311: lastSwapTime = currSwapTime;
0312: VirtualUniverse.mc
0313: .recordTime(
0314: MasterControl.TimeType.TOTAL_FRAME,
0315: deltaTime);
0316: }
0317:
0318: // Set all dirty bits except environment set and lightbin
0319: // they are only set dirty if the last used light bin or
0320: // environment set values for this canvas change between
0321: // one frame and other
0322:
0323: if (!cv.ctxChanged) {
0324: cv.canvasDirty = (0xffff & ~(Canvas3D.LIGHTBIN_DIRTY
0325: | Canvas3D.LIGHTENABLES_DIRTY
0326: | Canvas3D.AMBIENTLIGHT_DIRTY
0327: | Canvas3D.MODELCLIP_DIRTY
0328: | Canvas3D.VIEW_MATRIX_DIRTY | Canvas3D.FOG_DIRTY));
0329: // Force reload of transform next frame
0330: cv.modelMatrix = null;
0331:
0332: // Force the cached renderAtom to null
0333: cv.ra = null;
0334: } else {
0335: cv.ctxChanged = false;
0336: }
0337: }
0338: } catch (NullPointerException ne) {
0339: // Ignore NPE
0340: if (VirtualUniverse.mc.doDsiRenderLock) {
0341: cv.drawingSurfaceObject.unLock();
0342: }
0343: } catch (RuntimeException ex) {
0344: ex.printStackTrace();
0345:
0346: if (VirtualUniverse.mc.doDsiRenderLock) {
0347: cv.drawingSurfaceObject.unLock();
0348: }
0349:
0350: // Issue 260 : indicate fatal error and notify error listeners
0351: cv.setFatalError();
0352: RenderingError err = new RenderingError(
0353: RenderingError.UNEXPECTED_RENDERING_ERROR,
0354: J3dI18N.getString("Renderer0"));
0355: err.setCanvas3D(cv);
0356: err.setGraphicsDevice(cv.graphicsConfiguration
0357: .getDevice());
0358: notifyErrorListeners(err);
0359: }
0360:
0361: cv.releaseCtx();
0362: }
0363:
0364: if (view != null) { // STOP_TIMER
0365: // incElapsedFrames() is delay until MC:updateMirroObject
0366: if (view.viewCache.getDoHeadTracking()) {
0367: VirtualUniverse.mc.sendRunMessage(view,
0368: J3dThread.RENDER_THREAD);
0369: }
0370: }
0371:
0372: } else if (opArg == REQUESTCLEANUP) {
0373: Integer mtype = (Integer) args[2];
0374:
0375: if (mtype == MasterControl.REMOVEALLCTXS_CLEANUP) {
0376: // from MasterControl when View is last views
0377: removeAllCtxs();
0378: } else if (mtype == MasterControl.FREECONTEXT_CLEANUP) {
0379: // from MasterControl freeContext(View v)
0380: cv = (Canvas3D) args[1];
0381: removeCtx(cv, cv.screen.display, cv.drawable,
0382: cv.ctx, true, true, false);
0383: } else if (mtype == MasterControl.RESETCANVAS_CLEANUP) {
0384: // from MasterControl RESET_CANVAS postRequest
0385: cv = (Canvas3D) args[1];
0386: if (cv.ctx != null) {
0387: cv.makeCtxCurrent();
0388: }
0389: cv.freeContextResources(cv.screen.renderer, true,
0390: cv.ctx);
0391: } else if (mtype == MasterControl.REMOVECTX_CLEANUP) {
0392: // from Canvas3D removeCtx() postRequest
0393: Object[] obj = (Object[]) args[1];
0394: Canvas3D c = (Canvas3D) obj[0];
0395: removeCtx(c, ((Long) obj[1]).longValue(),
0396: (Drawable) obj[2], (Context) obj[3], false,
0397: !c.offScreen, false);
0398: }
0399: return;
0400: } else { // RENDER || REQUESTRENDER
0401:
0402: int renderType;
0403: nmesg = 0;
0404: int totalMessages = 0;
0405: if (opArg == RENDER) {
0406: m = renderMessage;
0407: m[0] = new J3dMessage();
0408: // Issue 131: Set appropriate message type
0409: if (((Canvas3D) args[1]).offScreen) {
0410: m[0].type = J3dMessage.RENDER_OFFSCREEN;
0411: } else {
0412: m[0].type = J3dMessage.RENDER_RETAINED;
0413: }
0414: m[0].incRefcount();
0415: m[0].args[0] = args[1];
0416: totalMessages = 1;
0417: } else { // REQUESTRENDER
0418: m = rendererStructure.getMessages();
0419: totalMessages = rendererStructure.getNumMessage();
0420: if (totalMessages <= 0) {
0421: return;
0422: }
0423: }
0424:
0425: doneRender: while (nmesg < totalMessages) {
0426:
0427: firstArg = m[nmesg].args[0];
0428:
0429: if (firstArg == null) {
0430: Object secondArg = m[nmesg].args[1];
0431: if (secondArg instanceof Canvas3D) {
0432: // message from Canvas3Ds to destroy Context
0433: Integer reqType = (Integer) m[nmesg].args[2];
0434: Canvas3D c = (Canvas3D) secondArg;
0435: if (reqType == MasterControl.SET_GRAPHICSCONFIG_FEATURES) {
0436: try {
0437: if (c.offScreen) {
0438: // offScreen canvas neither supports
0439: // double buffering nor stereo
0440: c.doubleBufferAvailable = false;
0441: c.stereoAvailable = false;
0442: } else {
0443: c.doubleBufferAvailable = c
0444: .hasDoubleBuffer();
0445: c.stereoAvailable = c
0446: .hasStereo();
0447: }
0448:
0449: // Setup stencil related variables.
0450: c.actualStencilSize = c
0451: .getStencilSize();
0452: boolean userOwnsStencil = c.requestedStencilSize > 0;
0453:
0454: c.userStencilAvailable = (userOwnsStencil && (c.actualStencilSize > 0));
0455: c.systemStencilAvailable = (!userOwnsStencil && (c.actualStencilSize > 0));
0456:
0457: c.sceneAntialiasingMultiSamplesAvailable = c
0458: .hasSceneAntialiasingMultisample();
0459:
0460: if (c.sceneAntialiasingMultiSamplesAvailable) {
0461: c.sceneAntialiasingAvailable = true;
0462: } else {
0463: c.sceneAntialiasingAvailable = c
0464: .hasSceneAntialiasingAccum();
0465: }
0466: } catch (RuntimeException ex) {
0467: ex.printStackTrace();
0468:
0469: // Issue 260 : indicate fatal error and notify error listeners
0470: c.setFatalError();
0471: RenderingError err = new RenderingError(
0472: RenderingError.GRAPHICS_CONFIG_ERROR,
0473: J3dI18N
0474: .getString("Renderer1"));
0475: err.setCanvas3D(c);
0476: err
0477: .setGraphicsDevice(c.graphicsConfiguration
0478: .getDevice());
0479: notifyErrorListeners(err);
0480: }
0481: GraphicsConfigTemplate3D
0482: .runMonitor(J3dThread.NOTIFY);
0483: } else if (reqType == MasterControl.SET_QUERYPROPERTIES) {
0484: try {
0485: c.createQueryContext();
0486: } catch (RuntimeException ex) {
0487: ex.printStackTrace();
0488:
0489: // Issue 260 : indicate fatal error and notify error listeners
0490: c.setFatalError();
0491: RenderingError err = new RenderingError(
0492: RenderingError.CONTEXT_CREATION_ERROR,
0493: J3dI18N
0494: .getString("Renderer2"));
0495: err.setCanvas3D(c);
0496: err
0497: .setGraphicsDevice(c.graphicsConfiguration
0498: .getDevice());
0499: notifyErrorListeners(err);
0500: }
0501: // currentCtx change after we create a new context
0502: GraphicsConfigTemplate3D
0503: .runMonitor(J3dThread.NOTIFY);
0504: currentCtx = null;
0505: currentDrawable = null;
0506: }
0507: } else if (secondArg instanceof Integer) {
0508: // Issue 121 - This was formerly used as a message from
0509: // the now-nonexistant TextureRetained finalize() method
0510: // to free the texture id
0511: throw new AssertionError();
0512: } else if (secondArg instanceof GeometryArrayRetained) {
0513: // message from GeometryArrayRetained
0514: // clearLive() to free D3D array
0515: ((GeometryArrayRetained) secondArg)
0516: .freeD3DArray(false);
0517: } else if (secondArg instanceof GraphicsConfigTemplate3D) {
0518: GraphicsConfigTemplate3D gct = (GraphicsConfigTemplate3D) secondArg;
0519: Integer reqType = (Integer) m[nmesg].args[2];
0520: if (reqType == MasterControl.GETBESTCONFIG) {
0521: GraphicsConfiguration gcfg = null;
0522: GraphicsConfiguration[] gcList = (GraphicsConfiguration[]) gct.testCfg;
0523: try {
0524: gcfg = Pipeline.getPipeline()
0525: .getBestConfiguration(gct,
0526: gcList);
0527: } catch (NullPointerException npe) {
0528: npe.printStackTrace();
0529: } catch (RuntimeException ex) {
0530: ex.printStackTrace();
0531:
0532: // Issue 260 : notify error listeners
0533: RenderingError err = new RenderingError(
0534: RenderingError.GRAPHICS_CONFIG_ERROR,
0535: J3dI18N
0536: .getString("Renderer3"));
0537: err.setGraphicsDevice(gcList[0]
0538: .getDevice());
0539: notifyErrorListeners(err);
0540: }
0541:
0542: gct.testCfg = gcfg;
0543: } else if (reqType == MasterControl.ISCONFIGSUPPORT) {
0544: boolean rval = false;
0545: GraphicsConfiguration gc = (GraphicsConfiguration) gct.testCfg;
0546: try {
0547: if (Pipeline.getPipeline()
0548: .isGraphicsConfigSupported(
0549: gct, gc)) {
0550: rval = true;
0551: }
0552: } catch (NullPointerException npe) {
0553: npe.printStackTrace();
0554: } catch (RuntimeException ex) {
0555: ex.printStackTrace();
0556:
0557: // Issue 260 : notify error listeners
0558: RenderingError err = new RenderingError(
0559: RenderingError.GRAPHICS_CONFIG_ERROR,
0560: J3dI18N
0561: .getString("Renderer4"));
0562: err.setGraphicsDevice(gc
0563: .getDevice());
0564: notifyErrorListeners(err);
0565: }
0566:
0567: gct.testCfg = Boolean.valueOf(rval);
0568: }
0569: gct.runMonitor(J3dThread.NOTIFY);
0570: }
0571:
0572: m[nmesg++].decRefcount();
0573: continue;
0574: }
0575:
0576: canvas = (Canvas3D) firstArg;
0577:
0578: renderType = m[nmesg].type;
0579:
0580: if (renderType == J3dMessage.CREATE_OFFSCREENBUFFER) {
0581: // Fix for issue 18.
0582: // Fix for issue 20.
0583:
0584: canvas.drawable = null;
0585: try {
0586: // Issue 396. Pass in a null ctx for 2 reasons :
0587: // 1) We should not use ctx field directly without buffering in a msg.
0588: // 2) canvas.ctx should be null.
0589: canvas.drawable = canvas
0590: .createOffScreenBuffer(
0591: null,
0592: canvas.screen.display,
0593: canvas.fbConfig,
0594: canvas.offScreenCanvasSize.width,
0595: canvas.offScreenCanvasSize.height);
0596: } catch (RuntimeException ex) {
0597: ex.printStackTrace();
0598: }
0599:
0600: if (canvas.drawable == null) {
0601: // Issue 260 : indicate fatal error and notify error listeners
0602: canvas.setFatalError();
0603: RenderingError err = new RenderingError(
0604: RenderingError.OFF_SCREEN_BUFFER_ERROR,
0605: J3dI18N.getString("Renderer5"));
0606: err.setCanvas3D(canvas);
0607: err
0608: .setGraphicsDevice(canvas.graphicsConfiguration
0609: .getDevice());
0610: notifyErrorListeners(err);
0611: }
0612:
0613: canvas.offScreenBufferPending = false;
0614: m[nmesg++].decRefcount();
0615: continue;
0616: } else if (renderType == J3dMessage.DESTROY_CTX_AND_OFFSCREENBUFFER) {
0617: Object[] obj = m[nmesg].args;
0618:
0619: // Fix for issue 175: destroy ctx & off-screen buffer
0620: // Fix for issue 340: get display, drawable & ctx from msg
0621: removeCtx(canvas, ((Long) obj[1]).longValue(),
0622: (Drawable) obj[2], (Context) obj[3],
0623: false, !canvas.offScreen, true);
0624:
0625: canvas.offScreenBufferPending = false;
0626: m[nmesg++].decRefcount();
0627: continue;
0628: } else if (renderType == J3dMessage.ALLOCATE_CANVASID) {
0629: canvas.allocateCanvasId();
0630: } else if (renderType == J3dMessage.FREE_CANVASID) {
0631: canvas.freeCanvasId();
0632: }
0633:
0634: if ((canvas.view == null)
0635: || !canvas.firstPaintCalled) {
0636: // This happen when the canvas just remove from the View
0637: if (renderType == J3dMessage.RENDER_OFFSCREEN) {
0638: canvas.offScreenRendering = false;
0639: }
0640: m[nmesg++].decRefcount();
0641: continue;
0642: }
0643:
0644: if (!canvas.validCanvas
0645: && (renderType != J3dMessage.RENDER_OFFSCREEN)) {
0646: m[nmesg++].decRefcount();
0647: continue;
0648: }
0649:
0650: if (renderType == J3dMessage.RESIZE_CANVAS) {
0651: canvas.d3dResize();
0652: // render the image again after resize
0653: VirtualUniverse.mc.sendRunMessage(canvas.view,
0654: J3dThread.RENDER_THREAD);
0655: m[nmesg++].decRefcount();
0656: } else if (renderType == J3dMessage.TOGGLE_CANVAS) {
0657: canvas.d3dToggle();
0658: VirtualUniverse.mc.sendRunMessage(canvas.view,
0659: J3dThread.RENDER_THREAD);
0660: m[nmesg++].decRefcount();
0661: } else if (renderType == J3dMessage.RENDER_IMMEDIATE) {
0662: int command = ((Integer) m[nmesg].args[1])
0663: .intValue();
0664: //System.err.println("command= " + command);
0665: if (needToResendTextureDown) {
0666: VirtualUniverse.mc.resendTexTimestamp++;
0667: needToResendTextureDown = false;
0668: }
0669:
0670: if (canvas.isFatalError()) {
0671: continue;
0672: }
0673:
0674: try {
0675: if (canvas.ctx != null) {
0676: // ctx may not construct until doClear();
0677: canvas.beginScene();
0678: }
0679:
0680: switch (command) {
0681: case GraphicsContext3D.CLEAR:
0682: canvas.graphicsContext3D.doClear();
0683: break;
0684: case GraphicsContext3D.DRAW:
0685: canvas.graphicsContext3D
0686: .doDraw((Geometry) m[nmesg].args[2]);
0687: break;
0688: case GraphicsContext3D.SWAP:
0689: canvas.doSwap();
0690: break;
0691: case GraphicsContext3D.READ_RASTER:
0692: canvas.graphicsContext3D
0693: .doReadRaster((Raster) m[nmesg].args[2]);
0694: break;
0695: case GraphicsContext3D.SET_APPEARANCE:
0696: canvas.graphicsContext3D
0697: .doSetAppearance((Appearance) m[nmesg].args[2]);
0698: break;
0699: case GraphicsContext3D.SET_BACKGROUND:
0700: canvas.graphicsContext3D
0701: .doSetBackground((Background) m[nmesg].args[2]);
0702: break;
0703: case GraphicsContext3D.SET_FOG:
0704: canvas.graphicsContext3D
0705: .doSetFog((Fog) m[nmesg].args[2]);
0706: break;
0707: case GraphicsContext3D.SET_LIGHT:
0708: canvas.graphicsContext3D.doSetLight(
0709: (Light) m[nmesg].args[2],
0710: ((Integer) m[nmesg].args[3])
0711: .intValue());
0712: break;
0713: case GraphicsContext3D.INSERT_LIGHT:
0714: canvas.graphicsContext3D.doInsertLight(
0715: (Light) m[nmesg].args[2],
0716: ((Integer) m[nmesg].args[3])
0717: .intValue());
0718: break;
0719: case GraphicsContext3D.REMOVE_LIGHT:
0720: canvas.graphicsContext3D
0721: .doRemoveLight(((Integer) m[nmesg].args[2])
0722: .intValue());
0723: break;
0724: case GraphicsContext3D.ADD_LIGHT:
0725: canvas.graphicsContext3D
0726: .doAddLight((Light) m[nmesg].args[2]);
0727: break;
0728: case GraphicsContext3D.SET_HI_RES:
0729: canvas.graphicsContext3D
0730: .doSetHiRes((HiResCoord) m[nmesg].args[2]);
0731: break;
0732: case GraphicsContext3D.SET_MODEL_TRANSFORM:
0733: t3d = (Transform3D) m[nmesg].args[2];
0734: canvas.graphicsContext3D
0735: .doSetModelTransform(t3d);
0736: break;
0737: case GraphicsContext3D.MULTIPLY_MODEL_TRANSFORM:
0738: t3d = (Transform3D) m[nmesg].args[2];
0739: canvas.graphicsContext3D
0740: .doMultiplyModelTransform(t3d);
0741: break;
0742: case GraphicsContext3D.SET_SOUND:
0743: canvas.graphicsContext3D.doSetSound(
0744: (Sound) m[nmesg].args[2],
0745: ((Integer) m[nmesg].args[3])
0746: .intValue());
0747: break;
0748: case GraphicsContext3D.INSERT_SOUND:
0749: canvas.graphicsContext3D.doInsertSound(
0750: (Sound) m[nmesg].args[2],
0751: ((Integer) m[nmesg].args[3])
0752: .intValue());
0753: break;
0754: case GraphicsContext3D.REMOVE_SOUND:
0755: canvas.graphicsContext3D
0756: .doRemoveSound(((Integer) m[nmesg].args[2])
0757: .intValue());
0758: break;
0759: case GraphicsContext3D.ADD_SOUND:
0760: canvas.graphicsContext3D
0761: .doAddSound((Sound) m[nmesg].args[2]);
0762: break;
0763: case GraphicsContext3D.SET_AURAL_ATTRIBUTES:
0764: canvas.graphicsContext3D
0765: .doSetAuralAttributes((AuralAttributes) m[nmesg].args[2]);
0766: break;
0767: case GraphicsContext3D.SET_BUFFER_OVERRIDE:
0768: canvas.graphicsContext3D
0769: .doSetBufferOverride(((Boolean) m[nmesg].args[2])
0770: .booleanValue());
0771: break;
0772: case GraphicsContext3D.SET_FRONT_BUFFER_RENDERING:
0773: canvas.graphicsContext3D
0774: .doSetFrontBufferRendering(((Boolean) m[nmesg].args[2])
0775: .booleanValue());
0776: break;
0777: case GraphicsContext3D.SET_STEREO_MODE:
0778: canvas.graphicsContext3D
0779: .doSetStereoMode(((Integer) m[nmesg].args[2])
0780: .intValue());
0781: break;
0782: case GraphicsContext3D.FLUSH:
0783: canvas.graphicsContext3D
0784: .doFlush(((Boolean) m[nmesg].args[2])
0785: .booleanValue());
0786: break;
0787: case GraphicsContext3D.FLUSH2D:
0788: canvas.graphics2D.doFlush();
0789: break;
0790: case GraphicsContext3D.DRAWANDFLUSH2D:
0791: Object ar[] = m[nmesg].args;
0792: canvas.graphics2D.doDrawAndFlushImage(
0793: (BufferedImage) ar[2],
0794: ((Point) ar[3]).x,
0795: ((Point) ar[3]).y,
0796: (ImageObserver) ar[4]);
0797: break;
0798: case GraphicsContext3D.DISPOSE2D:
0799: canvas.graphics2D.doDispose();
0800: break;
0801: case GraphicsContext3D.SET_MODELCLIP:
0802: canvas.graphicsContext3D
0803: .doSetModelClip((ModelClip) m[nmesg].args[2]);
0804: break;
0805: default:
0806: break;
0807: }
0808:
0809: if (canvas.ctx != null) {
0810: canvas.endScene();
0811: }
0812: } catch (RuntimeException ex) {
0813: ex.printStackTrace();
0814:
0815: // Issue 260 : indicate fatal error and notify error listeners
0816: canvas.setFatalError();
0817: RenderingError err = new RenderingError(
0818: RenderingError.CONTEXT_CREATION_ERROR,
0819: J3dI18N.getString("Renderer6"));
0820: err.setCanvas3D(canvas);
0821: err
0822: .setGraphicsDevice(canvas.graphicsConfiguration
0823: .getDevice());
0824: notifyErrorListeners(err);
0825: }
0826:
0827: m[nmesg++].decRefcount();
0828: } else { // retained mode rendering
0829: long startRenderTime = 0L;
0830: if (MasterControl.isStatsLoggable(Level.INFO)) {
0831: // Instrumentation of Java 3D renderer
0832: startRenderTime = System.nanoTime();
0833: }
0834:
0835: m[nmesg++].decRefcount();
0836:
0837: if (canvas.isFatalError()) {
0838: continue;
0839: }
0840:
0841: ImageComponent2DRetained offBufRetained = null;
0842:
0843: if (renderType == J3dMessage.RENDER_OFFSCREEN) {
0844: // Issue 131: set offScreenRendering flag here, since it
0845: // otherwise won't be set for auto-off-screen rendering
0846: // (which doesn't use renderOffScreenBuffer)
0847: canvas.offScreenRendering = true;
0848: if (canvas.drawable == null
0849: || !canvas.active) {
0850: canvas.offScreenRendering = false;
0851: continue;
0852: } else {
0853: offBufRetained = (ImageComponent2DRetained) canvas.offScreenBuffer.retained;
0854:
0855: if (offBufRetained.isByReference()) {
0856: offBufRetained.geomLock.getLock();
0857: }
0858:
0859: offBufRetained
0860: .evaluateExtensions(canvas);
0861:
0862: }
0863:
0864: } else if (!canvas.active) {
0865: continue;
0866: }
0867:
0868: // Issue 78 - need to get the drawingSurface info every
0869: // frame; this is necessary since the HDC (window ID)
0870: // on Windows can become invalidated without our
0871: // being notified!
0872: if (!canvas.offScreen) {
0873: canvas.drawingSurfaceObject
0874: .getDrawingSurfaceObjectInfo();
0875: }
0876:
0877: renderBin = canvas.view.renderBin;
0878:
0879: // setup rendering context
0880:
0881: // We need to catch NullPointerException when the dsi
0882: // gets yanked from us during a remove.
0883:
0884: if (canvas.useSharedCtx) {
0885:
0886: if (sharedCtx == null) {
0887: sharedCtxDisplay = canvas.screen.display;
0888: sharedCtxDrawable = canvas.drawable;
0889:
0890: // Always lock for context create
0891: if (!canvas.drawingSurfaceObject
0892: .renderLock()) {
0893: if ((offBufRetained != null)
0894: && offBufRetained
0895: .isByReference()) {
0896: offBufRetained.geomLock
0897: .unLock();
0898: }
0899: canvas.offScreenRendering = false;
0900: break doneRender;
0901: }
0902:
0903: synchronized (VirtualUniverse.mc.contextCreationLock) {
0904: sharedCtx = null;
0905: try {
0906: sharedCtx = canvas
0907: .createNewContext(null,
0908: true);
0909: } catch (RuntimeException ex) {
0910: ex.printStackTrace();
0911: }
0912:
0913: if (sharedCtx == null) {
0914: canvas.drawingSurfaceObject
0915: .unLock();
0916: if ((offBufRetained != null)
0917: && offBufRetained
0918: .isByReference()) {
0919: offBufRetained.geomLock
0920: .unLock();
0921: }
0922: canvas.offScreenRendering = false;
0923:
0924: // Issue 260 : indicate fatal error and notify error listeners
0925: canvas.setFatalError();
0926: RenderingError err = new RenderingError(
0927: RenderingError.CONTEXT_CREATION_ERROR,
0928: J3dI18N
0929: .getString("Renderer7"));
0930: err.setCanvas3D(canvas);
0931: err
0932: .setGraphicsDevice(canvas.graphicsConfiguration
0933: .getDevice());
0934: notifyErrorListeners(err);
0935:
0936: break doneRender;
0937: }
0938: sharedCtxTimeStamp = VirtualUniverse.mc
0939: .getContextTimeStamp();
0940:
0941: needToRebuildDisplayList = true;
0942: }
0943:
0944: canvas.drawingSurfaceObject.unLock();
0945: }
0946: }
0947:
0948: if (canvas.ctx == null) {
0949:
0950: // Always lock for context create
0951: if (!canvas.drawingSurfaceObject
0952: .renderLock()) {
0953: if ((offBufRetained != null)
0954: && offBufRetained
0955: .isByReference()) {
0956: offBufRetained.geomLock.unLock();
0957: }
0958: canvas.offScreenRendering = false;
0959: break doneRender;
0960: }
0961:
0962: synchronized (VirtualUniverse.mc.contextCreationLock) {
0963: canvas.ctx = null;
0964: try {
0965: canvas.ctx = canvas
0966: .createNewContext(
0967: sharedCtx, false);
0968: } catch (RuntimeException ex) {
0969: ex.printStackTrace();
0970: }
0971:
0972: if (canvas.ctx == null) {
0973: canvas.drawingSurfaceObject
0974: .unLock();
0975: if ((offBufRetained != null)
0976: && offBufRetained
0977: .isByReference()) {
0978: offBufRetained.geomLock
0979: .unLock();
0980: }
0981: canvas.offScreenRendering = false;
0982:
0983: // Issue 260 : indicate fatal error and notify error listeners
0984: canvas.setFatalError();
0985: RenderingError err = new RenderingError(
0986: RenderingError.CONTEXT_CREATION_ERROR,
0987: J3dI18N
0988: .getString("Renderer7"));
0989: err.setCanvas3D(canvas);
0990: err
0991: .setGraphicsDevice(canvas.graphicsConfiguration
0992: .getDevice());
0993: notifyErrorListeners(err);
0994:
0995: break doneRender;
0996: }
0997:
0998: if (canvas.graphics2D != null) {
0999: canvas.graphics2D.init();
1000: }
1001:
1002: canvas.ctxTimeStamp = VirtualUniverse.mc
1003: .getContextTimeStamp();
1004: listOfCtxs.add(canvas.ctx);
1005: listOfCanvases.add(canvas);
1006:
1007: if (renderBin.nodeComponentList.size() > 0) {
1008: for (i = 0; i < renderBin.nodeComponentList
1009: .size(); i++) {
1010: NodeComponentRetained nc = (NodeComponentRetained) renderBin.nodeComponentList
1011: .get(i);
1012: if (nc instanceof ImageComponentRetained) {
1013: ((ImageComponentRetained) nc)
1014: .evaluateExtensions(canvas);
1015: }
1016: }
1017: }
1018:
1019: // enable separate specular color
1020: canvas.enableSeparateSpecularColor();
1021: }
1022:
1023: // create the cache texture state in canvas
1024: // for state download checking purpose
1025: if (canvas.texUnitState == null) {
1026: canvas.createTexUnitState();
1027: }
1028:
1029: canvas
1030: .resetImmediateRendering(Canvas3D.NOCHANGE);
1031: canvas.drawingSurfaceObject
1032: .contextValidated();
1033:
1034: if (!canvas.useSharedCtx) {
1035: canvas.needToRebuildDisplayList = true;
1036: }
1037: canvas.drawingSurfaceObject.unLock();
1038: } else {
1039:
1040: if (canvas.isRunning) {
1041: canvas.makeCtxCurrent();
1042: }
1043: }
1044:
1045: if (renderBin != null) {
1046: if ((VirtualUniverse.mc.doDsiRenderLock)
1047: && (!canvas.drawingSurfaceObject
1048: .renderLock())) {
1049: if ((offBufRetained != null)
1050: && offBufRetained
1051: .isByReference()) {
1052: offBufRetained.geomLock.unLock();
1053: }
1054: canvas.offScreenRendering = false;
1055: break doneRender;
1056: }
1057:
1058: if (needToResendTextureDown) {
1059: VirtualUniverse.mc.resendTexTimestamp++;
1060: needToResendTextureDown = false;
1061: }
1062: // handle free resource
1063: if (canvas.useSharedCtx) {
1064: freeResourcesInFreeList(canvas);
1065: } else {
1066: canvas
1067: .freeResourcesInFreeList(canvas.ctx);
1068: }
1069:
1070: if (VirtualUniverse.mc.doDsiRenderLock) {
1071: canvas.drawingSurfaceObject.unLock();
1072: }
1073:
1074: // Issue 109 : removed copyOfCvCache now that we have
1075: // a separate canvasViewCache for computing view frustum
1076: CanvasViewCache cvCache = canvas.canvasViewCache;
1077:
1078: // Deadlock if we include updateViewCache in
1079: // drawingSurfaceObject sync.
1080: canvas
1081: .updateViewCache(
1082: false,
1083: null,
1084: null,
1085: renderBin.geometryBackground != null);
1086:
1087: if ((VirtualUniverse.mc.doDsiRenderLock)
1088: && (!canvas.drawingSurfaceObject
1089: .renderLock())) {
1090: if ((offBufRetained != null)
1091: && offBufRetained
1092: .isByReference()) {
1093: offBufRetained.geomLock.unLock();
1094: }
1095: canvas.offScreenRendering = false;
1096: break doneRender;
1097: }
1098:
1099: // setup viewport
1100: canvas.setViewport(canvas.ctx, 0, 0,
1101: cvCache.getCanvasWidth(), cvCache
1102: .getCanvasHeight());
1103:
1104: // rebuild the display list of all dirty renderMolecules.
1105: if (canvas.useSharedCtx) {
1106: if (needToRebuildDisplayList) {
1107: renderBin.updateAllRenderMolecule(
1108: this , canvas);
1109: needToRebuildDisplayList = false;
1110: }
1111:
1112: if (dirtyDisplayList) {
1113: renderBin.updateDirtyDisplayLists(
1114: canvas,
1115: dirtyRenderMoleculeList,
1116: dirtyDlistPerRinfoList,
1117: dirtyRenderAtomList, true);
1118: dirtyDisplayList = false;
1119: }
1120:
1121: // for shared context, download textures upfront
1122: // to minimize the context switching overhead
1123: int sz = textureReloadList.size();
1124:
1125: if (sz > 0) {
1126: for (j = sz - 1; j >= 0; j--) {
1127: ((TextureRetained) textureReloadList
1128: .get(j))
1129: .reloadTextureSharedContext(canvas);
1130: }
1131: textureReloadList.clear();
1132: }
1133:
1134: } else {
1135: // update each canvas
1136: if (canvas.needToRebuildDisplayList) {
1137: renderBin
1138: .updateAllRenderMolecule(canvas);
1139: canvas.needToRebuildDisplayList = false;
1140: }
1141: if (canvas.dirtyDisplayList) {
1142: renderBin
1143: .updateDirtyDisplayLists(
1144: canvas,
1145: canvas.dirtyRenderMoleculeList,
1146: canvas.dirtyDlistPerRinfoList,
1147: canvas.dirtyRenderAtomList,
1148: false);
1149: canvas.dirtyDisplayList = false;
1150: }
1151: }
1152:
1153: // lighting setup
1154: if (canvas.view.localEyeLightingEnable != canvas.ctxEyeLightingEnable) {
1155: canvas
1156: .ctxUpdateEyeLightingEnable(
1157: canvas.ctx,
1158: canvas.view.localEyeLightingEnable);
1159: canvas.ctxEyeLightingEnable = canvas.view.localEyeLightingEnable;
1160: }
1161:
1162: // stereo setup
1163: boolean useStereo = cvCache.getUseStereo();
1164: if (useStereo) {
1165: num_stereo_passes = 2;
1166: stereo_mode = Canvas3D.FIELD_LEFT;
1167:
1168: sharedStereoZBuffer = VirtualUniverse.mc.sharedStereoZBuffer;
1169: } else {
1170: num_stereo_passes = 1;
1171: stereo_mode = Canvas3D.FIELD_ALL;
1172:
1173: // just in case user set flag -
1174: // disable since we are not in stereo
1175: sharedStereoZBuffer = false;
1176: }
1177:
1178: // full screen anti-aliasing setup
1179: if (canvas.view
1180: .getSceneAntialiasingEnable()
1181: && canvas.sceneAntialiasingAvailable) {
1182:
1183: if (!VirtualUniverse.mc.isD3D()
1184: && ((canvas.extensionsSupported & Canvas3D.MULTISAMPLE) == 0)
1185: || !canvas.sceneAntialiasingMultiSamplesAvailable) {
1186: doAccum = true;
1187: num_accum_passes = NUM_ACCUMULATION_SAMPLES;
1188:
1189: System
1190: .arraycopy(
1191: cvCache
1192: .getLeftProjection().mat,
1193: 0,
1194: accumLeftProj.mat,
1195: 0, 16);
1196:
1197: accumDxFactor = (canvas.canvasViewCache
1198: .getPhysicalWindowWidth() / canvas.canvasViewCache
1199: .getCanvasWidth())
1200: * canvas.view.fieldOfView;
1201:
1202: accumDyFactor = (canvas.canvasViewCache
1203: .getPhysicalWindowHeight() / canvas.canvasViewCache
1204: .getCanvasHeight())
1205: * canvas.view.fieldOfView;
1206:
1207: accumLeftX = accumLeftProj.mat[3];
1208: accumLeftY = accumLeftProj.mat[7];
1209:
1210: if (useStereo) {
1211: System
1212: .arraycopy(
1213: cvCache
1214: .getRightProjection().mat,
1215: 0,
1216: accumRightProj.mat,
1217: 0, 16);
1218: accumRightX = accumRightProj.mat[3];
1219: accumRightY = accumRightProj.mat[7];
1220: }
1221:
1222: if (renderBin.geometryBackground != null) {
1223: System
1224: .arraycopy(
1225: cvCache
1226: .getInfLeftProjection().mat,
1227: 0,
1228: accumInfLeftProj.mat,
1229: 0, 16);
1230: accumInfLeftX = accumInfLeftProj.mat[3];
1231: accumInfLeftY = accumInfLeftProj.mat[7];
1232: if (useStereo) {
1233: System
1234: .arraycopy(
1235: cvCache
1236: .getInfRightProjection().mat,
1237: 0,
1238: accumInfRightProj.mat,
1239: 0, 16);
1240: accumInfRightX = accumInfRightProj.mat[3];
1241: accumInfRightY = accumInfRightProj.mat[7];
1242: }
1243: }
1244: } else {
1245:
1246: if (!canvas.antialiasingSet) {
1247: // System.err.println("Renderer : Enable FullSceneAntialiasing");
1248:
1249: canvas
1250: .setFullSceneAntialiasing(
1251: canvas.ctx,
1252: true);
1253: canvas.antialiasingSet = true;
1254: }
1255: }
1256: } else {
1257:
1258: if (canvas.antialiasingSet) {
1259: // System.err.println("Renderer : Disable SceneAntialiasing");
1260: canvas.setFullSceneAntialiasing(
1261: canvas.ctx, false);
1262: canvas.antialiasingSet = false;
1263: }
1264: }
1265:
1266: // background geometry setup
1267: if (renderBin.geometryBackground != null) {
1268: renderBin.updateInfVworldToVpc();
1269: }
1270:
1271: // setup default render mode - render to both eyes
1272: canvas.setRenderMode(canvas.ctx,
1273: Canvas3D.FIELD_ALL,
1274: canvas.useDoubleBuffer);
1275:
1276: canvas.beginScene();
1277:
1278: // this is if the background image resizes with the canvas
1279: int winWidth = cvCache.getCanvasWidth();
1280: int winHeight = cvCache.getCanvasHeight();
1281:
1282: // clear background if not full screen antialiasing
1283: // and not in stereo mode
1284: if (!doAccum && !sharedStereoZBuffer) {
1285: BackgroundRetained bg = renderBin.background;
1286:
1287: canvas.clear(bg, winWidth, winHeight);
1288:
1289: }
1290:
1291: // handle preRender callback
1292: if (VirtualUniverse.mc.doDsiRenderLock) {
1293: canvas.drawingSurfaceObject.unLock();
1294: }
1295: canvas.view.inCanvasCallback = true;
1296:
1297: try {
1298: canvas.preRender();
1299: } catch (RuntimeException e) {
1300: System.err
1301: .println("Exception occurred during Canvas3D callback:");
1302: e.printStackTrace();
1303: } catch (Error e) {
1304: // Issue 264 - catch Error so Renderer doesn't die
1305: System.err
1306: .println("Error occurred during Canvas3D callback:");
1307: e.printStackTrace();
1308: }
1309: canvas.view.inCanvasCallback = false;
1310:
1311: if ((VirtualUniverse.mc.doDsiRenderLock)
1312: && (!canvas.drawingSurfaceObject
1313: .renderLock())) {
1314: if ((offBufRetained != null)
1315: && offBufRetained
1316: .isByReference()) {
1317: offBufRetained.geomLock.unLock();
1318: }
1319: canvas.offScreenRendering = false;
1320: break doneRender;
1321: }
1322:
1323: // render loop
1324: for (pass = 0; pass < num_stereo_passes; pass++) {
1325: if (doAccum) {
1326: canvas.clearAccum(canvas.ctx);
1327: }
1328: canvas.setRenderMode(canvas.ctx,
1329: stereo_mode,
1330: canvas.useDoubleBuffer);
1331:
1332: for (apass = 0; apass < num_accum_passes; apass++) {
1333:
1334: // jitter projection matrix and clear background
1335: // for full screen anti-aliasing rendering
1336: if (doAccum) {
1337: accumDx = ACCUM_SAMPLES_X[apass]
1338: * accumDxFactor;
1339: accumDy = ACCUM_SAMPLES_Y[apass]
1340: * accumDyFactor;
1341:
1342: accumLeftProj.mat[3] = accumLeftX
1343: + accumLeftProj.mat[0]
1344: * accumDx
1345: + accumLeftProj.mat[1]
1346: * accumDy;
1347:
1348: accumLeftProj.mat[7] = accumLeftY
1349: + accumLeftProj.mat[4]
1350: * accumDx
1351: + accumLeftProj.mat[5]
1352: * accumDy;
1353:
1354: if (useStereo) {
1355: accumRightProj.mat[3] = accumRightX
1356: + accumRightProj.mat[0]
1357: * accumDx
1358: + accumRightProj.mat[1]
1359: * accumDy;
1360:
1361: accumRightProj.mat[7] = accumRightY
1362: + accumRightProj.mat[4]
1363: * accumDx
1364: + accumRightProj.mat[5]
1365: * accumDy;
1366: }
1367:
1368: if (renderBin.geometryBackground != null) {
1369: accumInfLeftProj.mat[3] = accumInfLeftX
1370: + accumInfLeftProj.mat[0]
1371: * accumDx
1372: + accumInfLeftProj.mat[1]
1373: * accumDy;
1374:
1375: accumInfLeftProj.mat[7] = accumInfLeftY
1376: + accumInfLeftProj.mat[4]
1377: * accumDx
1378: + accumInfLeftProj.mat[5]
1379: * accumDy;
1380:
1381: if (useStereo) {
1382: accumInfRightProj.mat[3] = accumInfRightX
1383: + accumInfRightProj.mat[0]
1384: * accumDx
1385: + accumInfRightProj.mat[1]
1386: * accumDy;
1387:
1388: accumInfRightProj.mat[7] = accumInfRightY
1389: + accumInfRightProj.mat[4]
1390: * accumDx
1391: + accumInfRightProj.mat[5]
1392: * accumDy;
1393: }
1394: }
1395: }
1396:
1397: // clear background for stereo and
1398: // accumulation buffer cases
1399: if (doAccum || sharedStereoZBuffer) {
1400: BackgroundRetained bg = renderBin.background;
1401:
1402: canvas.clear(bg, winWidth,
1403: winHeight);
1404:
1405: }
1406:
1407: // render background geometry
1408: if (renderBin.geometryBackground != null) {
1409:
1410: // setup rendering matrices
1411: if (pass == 0) {
1412: canvas.vpcToEc = cvCache
1413: .getInfLeftVpcToEc();
1414: if (doAccum) {
1415: canvas
1416: .setProjectionMatrix(
1417: canvas.ctx,
1418: accumInfLeftProj);
1419: } else {
1420: canvas
1421: .setProjectionMatrix(
1422: canvas.ctx,
1423: cvCache
1424: .getInfLeftProjection());
1425: }
1426: } else {
1427: canvas.vpcToEc = cvCache
1428: .getInfRightVpcToEc();
1429: if (doAccum) {
1430: canvas
1431: .setProjectionMatrix(
1432: canvas.ctx,
1433: accumInfRightProj);
1434: } else {
1435: canvas
1436: .setProjectionMatrix(
1437: canvas.ctx,
1438: cvCache
1439: .getInfRightProjection());
1440: }
1441: }
1442: canvas.vworldToEc
1443: .mul(
1444: canvas.vpcToEc,
1445: cvCache
1446: .getInfVworldToVpc());
1447:
1448: // render background geometry
1449: renderBin
1450: .renderBackground(canvas);
1451: }
1452:
1453: // setup rendering matrices
1454: if (pass == 0) {
1455: canvas.vpcToEc = cvCache
1456: .getLeftVpcToEc();
1457: if (doAccum) {
1458: canvas.setProjectionMatrix(
1459: canvas.ctx,
1460: accumLeftProj);
1461: } else {
1462: canvas
1463: .setProjectionMatrix(
1464: canvas.ctx,
1465: cvCache
1466: .getLeftProjection());
1467: }
1468: } else {
1469: canvas.vpcToEc = cvCache
1470: .getRightVpcToEc();
1471: if (doAccum) {
1472: canvas.setProjectionMatrix(
1473: canvas.ctx,
1474: accumRightProj);
1475: } else {
1476: canvas
1477: .setProjectionMatrix(
1478: canvas.ctx,
1479: cvCache
1480: .getRightProjection());
1481: }
1482: }
1483: canvas.vworldToEc.mul(
1484: canvas.vpcToEc, cvCache
1485: .getVworldToVpc());
1486:
1487: synchronized (cvCache) {
1488: if (pass == 0) {
1489: canvas
1490: .setFrustumPlanes(cvCache
1491: .getLeftFrustumPlanesInVworld());
1492: } else {
1493: canvas
1494: .setFrustumPlanes(cvCache
1495: .getRightFrustumPlanesInVworld());
1496: }
1497: }
1498:
1499: // Force view matrix dirty for each eye.
1500: if (useStereo) {
1501: canvas.canvasDirty |= Canvas3D.VIEW_MATRIX_DIRTY;
1502: }
1503:
1504: // render opaque geometry
1505: renderBin.renderOpaque(canvas);
1506:
1507: // render ordered geometry
1508: renderBin.renderOrdered(canvas);
1509:
1510: // handle renderField callback
1511: if (VirtualUniverse.mc.doDsiRenderLock) {
1512: canvas.drawingSurfaceObject
1513: .unLock();
1514: }
1515: canvas.view.inCanvasCallback = true;
1516: try {
1517: canvas.renderField(stereo_mode);
1518: } catch (RuntimeException e) {
1519: System.err
1520: .println("Exception occurred during Canvas3D callback:");
1521: e.printStackTrace();
1522: } catch (Error e) {
1523: // Issue 264 - catch Error so Renderer doesn't die
1524: System.err
1525: .println("Error occurred during Canvas3D callback:");
1526: e.printStackTrace();
1527: }
1528: canvas.view.inCanvasCallback = false;
1529: if ((VirtualUniverse.mc.doDsiRenderLock)
1530: && (!canvas.drawingSurfaceObject
1531: .renderLock())) {
1532: if ((offBufRetained != null)
1533: && offBufRetained
1534: .isByReference()) {
1535: offBufRetained.geomLock
1536: .unLock();
1537: }
1538: canvas.offScreenRendering = false;
1539: break doneRender;
1540: }
1541:
1542: // render transparent geometry
1543: renderBin.renderTransparent(canvas);
1544:
1545: if (doAccum)
1546: canvas.accum(canvas.ctx,
1547: accumValue);
1548: }
1549:
1550: if (doAccum)
1551: canvas.accumReturn(canvas.ctx);
1552: if (useStereo) {
1553: stereo_mode = Canvas3D.FIELD_RIGHT;
1554: canvas.rightStereoPass = true;
1555: }
1556: }
1557: canvas.imageReady = true;
1558: canvas.rightStereoPass = false;
1559:
1560: // reset renderMode
1561: canvas.setRenderMode(canvas.ctx,
1562: Canvas3D.FIELD_ALL,
1563: canvas.useDoubleBuffer);
1564:
1565: // handle postRender callback
1566: if (VirtualUniverse.mc.doDsiRenderLock) {
1567: canvas.drawingSurfaceObject.unLock();
1568: }
1569: canvas.view.inCanvasCallback = true;
1570:
1571: try {
1572: canvas.postRender();
1573: } catch (RuntimeException e) {
1574: System.err
1575: .println("Exception occurred during Canvas3D callback:");
1576: e.printStackTrace();
1577: } catch (Error e) {
1578: // Issue 264 - catch Error so Renderer doesn't die
1579: System.err
1580: .println("Error occurred during Canvas3D callback:");
1581: e.printStackTrace();
1582: }
1583: canvas.view.inCanvasCallback = false;
1584:
1585: // end offscreen rendering
1586: if (canvas.offScreenRendering) {
1587:
1588: canvas.syncRender(canvas.ctx, true);
1589: canvas.endOffScreenRendering();
1590: canvas.offScreenRendering = false;
1591:
1592: // Issue 489 - don't call postSwap here for auto-offscreen,
1593: // since it will be called later by the SWAP operation
1594: if (canvas.manualRendering) {
1595: // do the postSwap for offscreen here
1596: canvas.view.inCanvasCallback = true;
1597: try {
1598: canvas.postSwap();
1599: } catch (RuntimeException e) {
1600: System.err
1601: .println("Exception occurred during Canvas 3D callback:");
1602: e.printStackTrace();
1603: } catch (Error e) {
1604: // Issue 264 - catch Error so Renderer doesn't die
1605: System.err
1606: .println("Error occurred during Canvas3D callback:");
1607: e.printStackTrace();
1608: }
1609:
1610: if (offBufRetained.isByReference()) {
1611: offBufRetained.geomLock
1612: .unLock();
1613: }
1614:
1615: canvas.view.inCanvasCallback = false;
1616:
1617: canvas.releaseCtx();
1618: }
1619: }
1620:
1621: canvas.endScene();
1622:
1623: if (MasterControl
1624: .isStatsLoggable(Level.INFO)) {
1625: // Instrumentation of Java 3D renderer
1626: long deltaTime = System.nanoTime()
1627: - startRenderTime;
1628: VirtualUniverse.mc.recordTime(
1629: MasterControl.TimeType.RENDER,
1630: deltaTime);
1631: }
1632:
1633: } else { // if (renderBin != null)
1634: if ((offBufRetained != null)
1635: && offBufRetained.isByReference()) {
1636: offBufRetained.geomLock.unLock();
1637: }
1638: }
1639: }
1640: }
1641:
1642: // clear array to prevent memory leaks
1643: if (opArg == RENDER) {
1644: m[0] = null;
1645: } else {
1646: Arrays.fill(m, 0, totalMessages, null);
1647: }
1648: }
1649: } catch (NullPointerException ne) {
1650: // Print NPE, but otherwise ignore it
1651: ne.printStackTrace();
1652: if (canvas != null) {
1653: if (canvas.ctx != null) {
1654: canvas.endScene();
1655: }
1656: // drawingSurfaceObject will safely ignore
1657: // this request if this is not lock before
1658: canvas.drawingSurfaceObject.unLock();
1659:
1660: }
1661: } catch (RuntimeException ex) {
1662: ex.printStackTrace();
1663:
1664: if (canvas != null) {
1665: if (canvas.ctx != null) {
1666: canvas.endScene();
1667: }
1668: // drawingSurfaceObject will safely ignore
1669: // this request if this is not lock before
1670: canvas.drawingSurfaceObject.unLock();
1671: }
1672:
1673: // Issue 260 : indicate fatal error and notify error listeners
1674: canvas.setFatalError();
1675: RenderingError err = new RenderingError(
1676: RenderingError.UNEXPECTED_RENDERING_ERROR, J3dI18N
1677: .getString("Renderer8"));
1678: err.setCanvas3D(canvas);
1679: if (canvas != null) {
1680: err.setGraphicsDevice(canvas.graphicsConfiguration
1681: .getDevice());
1682: }
1683: notifyErrorListeners(err);
1684: }
1685: }
1686:
1687: // resource clean up
1688: void shutdown() {
1689: removeAllCtxs();
1690: Pipeline.getPipeline().cleanupRenderer();
1691: }
1692:
1693: void cleanup() {
1694: super .cleanup();
1695: renderMessage = new J3dMessage[1];
1696: rendererStructure = new RendererStructure();
1697: bgVworldToVpc = new Transform3D();
1698: sharedCtx = null;
1699: sharedCtxTimeStamp = 0;
1700: sharedCtxDisplay = 0;
1701: sharedCtxDrawable = null;
1702: dirtyRenderMoleculeList.clear();
1703: dirtyRenderAtomList.clear();
1704: dirtyDlistPerRinfoList.clear();
1705: textureIdResourceFreeList.clear();
1706: displayListResourceFreeList.clear();
1707: onScreen = null;
1708: offScreen = null;
1709: m = null;
1710: nmesg = 0;
1711: }
1712:
1713: // This is only invoked from removeCtx()/removeAllCtxs()
1714: // with drawingSurface already lock
1715: final void makeCtxCurrent(Context sharedCtx, long display,
1716: Drawable drawable) {
1717: if (sharedCtx != currentCtx || drawable != currentDrawable) {
1718: Canvas3D.useCtx(sharedCtx, display, drawable);
1719: /*
1720: if(!Canvas3D.useCtx(sharedCtx, display, drawable)) {
1721: Thread.dumpStack();
1722: System.err.println("useCtx Fail");
1723: }
1724: */
1725: currentCtx = sharedCtx;
1726: currentDrawable = drawable;
1727: }
1728: }
1729:
1730: // No need to free graphics2d and background if it is from
1731: // Canvas3D postRequest() offScreen rendering since the
1732: // user thread will not wait for it. Also we can just
1733: // reuse it as Canvas3D did not destroy.
1734: private void removeCtx(Canvas3D cv, long display,
1735: Drawable drawable, Context ctx, boolean resetCtx,
1736: boolean freeBackground, boolean destroyOffScreenBuffer) {
1737:
1738: synchronized (VirtualUniverse.mc.contextCreationLock) {
1739: if (ctx != null) {
1740: int idx = listOfCtxs.indexOf(ctx);
1741: if (idx >= 0) {
1742: listOfCtxs.remove(idx);
1743: listOfCanvases.remove(idx);
1744: // Issue 326 : don't check display variable here
1745: if ((drawable != null) && cv.added) {
1746: // cv.ctx may reset to -1 here so we
1747: // always use the ctx pass in.
1748: if (cv.drawingSurfaceObject.renderLock()) {
1749: // if it is the last one, free shared resources
1750: if (sharedCtx != null) {
1751: if (listOfCtxs.isEmpty()) {
1752: makeCtxCurrent(sharedCtx,
1753: sharedCtxDisplay,
1754: sharedCtxDrawable);
1755: freeResourcesInFreeList(null);
1756: freeContextResources();
1757: Canvas3D.destroyContext(
1758: sharedCtxDisplay,
1759: sharedCtxDrawable,
1760: sharedCtx);
1761: currentCtx = null;
1762: currentDrawable = null;
1763: } else {
1764: freeResourcesInFreeList(cv);
1765: }
1766: cv.makeCtxCurrent(ctx, display,
1767: drawable);
1768: } else {
1769: cv.makeCtxCurrent(ctx, display,
1770: drawable);
1771: cv.freeResourcesInFreeList(ctx);
1772: }
1773: cv.freeContextResources(this ,
1774: freeBackground, ctx);
1775: Canvas3D.destroyContext(display, drawable,
1776: ctx);
1777: currentCtx = null;
1778: currentDrawable = null;
1779: cv.drawingSurfaceObject.unLock();
1780: }
1781: }
1782: }
1783:
1784: if (resetCtx) {
1785: cv.ctx = null;
1786: }
1787:
1788: if ((sharedCtx != null) && listOfCtxs.isEmpty()) {
1789: sharedCtx = null;
1790: sharedCtxTimeStamp = 0;
1791: }
1792: cv.ctxTimeStamp = 0;
1793: }
1794:
1795: // Fix for issue 18.
1796: // Since we are now the renderer thread,
1797: // we can safely execute destroyOffScreenBuffer.
1798: if (destroyOffScreenBuffer) {
1799: cv.destroyOffScreenBuffer(ctx, display, cv.fbConfig,
1800: drawable);
1801: cv.offScreenBufferPending = false;
1802: }
1803: }
1804: }
1805:
1806: void removeAllCtxs() {
1807: Canvas3D cv;
1808:
1809: synchronized (VirtualUniverse.mc.contextCreationLock) {
1810:
1811: for (int i = listOfCanvases.size() - 1; i >= 0; i--) {
1812: cv = (Canvas3D) listOfCanvases.get(i);
1813:
1814: if ((cv.screen != null) && (cv.ctx != null)) {
1815: // Issue 326 : don't check display variable here
1816: if ((cv.drawable != null) && cv.added) {
1817: if (cv.drawingSurfaceObject.renderLock()) {
1818: // We need to free sharedCtx resource
1819: // first before last non-sharedCtx to
1820: // workaround Nvidia driver bug under Linux
1821: // that crash on freeTexture ID:4685156
1822: if ((i == 0) && (sharedCtx != null)) {
1823: makeCtxCurrent(sharedCtx,
1824: sharedCtxDisplay,
1825: sharedCtxDrawable);
1826: freeResourcesInFreeList(null);
1827: freeContextResources();
1828: Canvas3D.destroyContext(
1829: sharedCtxDisplay,
1830: sharedCtxDrawable, sharedCtx);
1831: currentCtx = null;
1832: currentDrawable = null;
1833: }
1834: cv.makeCtxCurrent();
1835: cv.freeResourcesInFreeList(cv.ctx);
1836: cv.freeContextResources(this , true, cv.ctx);
1837: Canvas3D.destroyContext(cv.screen.display,
1838: cv.drawable, cv.ctx);
1839: currentCtx = null;
1840: currentDrawable = null;
1841: cv.drawingSurfaceObject.unLock();
1842: }
1843: }
1844: }
1845:
1846: cv.ctx = null;
1847: cv.ctxTimeStamp = 0;
1848: }
1849:
1850: if (sharedCtx != null) {
1851: sharedCtx = null;
1852: sharedCtxTimeStamp = 0;
1853: }
1854: listOfCanvases.clear();
1855: listOfCtxs.clear();
1856: }
1857: }
1858:
1859: // handle free resource in the FreeList
1860: void freeResourcesInFreeList(Canvas3D cv) {
1861: Iterator it;
1862: boolean isFreeTex = (textureIdResourceFreeList.size() > 0);
1863: boolean isFreeDL = (displayListResourceFreeList.size() > 0);
1864: ArrayList list;
1865: int i, val;
1866: GeometryArrayRetained geo;
1867:
1868: if (isFreeTex || isFreeDL) {
1869: if (cv != null) {
1870: cv.makeCtxCurrent(sharedCtx);
1871: }
1872:
1873: if (isFreeDL) {
1874: for (it = displayListResourceFreeList.iterator(); it
1875: .hasNext();) {
1876: val = ((Integer) it.next()).intValue();
1877: if (val <= 0) {
1878: continue;
1879: }
1880: Canvas3D.freeDisplayList(sharedCtx, val);
1881: }
1882: displayListResourceFreeList.clear();
1883: }
1884: if (isFreeTex) {
1885: for (it = textureIdResourceFreeList.iterator(); it
1886: .hasNext();) {
1887: val = ((Integer) it.next()).intValue();
1888: if (val <= 0) {
1889: continue;
1890: }
1891: if (val >= textureIDResourceTable.size()) {
1892: MasterControl.getCoreLogger().severe(
1893: "Error in freeResourcesInFreeList : ResourceIDTableSize = "
1894: + textureIDResourceTable.size()
1895: + " val = " + val);
1896: } else {
1897: Object obj = textureIDResourceTable.get(val);
1898: if (obj instanceof TextureRetained) {
1899: TextureRetained tex = (TextureRetained) obj;
1900: synchronized (tex.resourceLock) {
1901: tex.resourceCreationMask &= ~rendererBit;
1902: if (tex.resourceCreationMask == 0) {
1903: tex.freeTextureId(val);
1904: }
1905: }
1906: }
1907:
1908: textureIDResourceTable.set(val, null);
1909: }
1910: Canvas3D.freeTexture(sharedCtx, val);
1911: }
1912: textureIdResourceFreeList.clear();
1913: }
1914: if (cv != null) {
1915: cv.makeCtxCurrent(cv.ctx);
1916: }
1917: }
1918: }
1919:
1920: final void addTextureResource(int id, Object obj) {
1921: if (textureIDResourceTable.size() <= id) {
1922: for (int i = textureIDResourceTable.size(); i < id; i++) {
1923: textureIDResourceTable.add(null);
1924: }
1925: textureIDResourceTable.add(obj);
1926: } else {
1927: textureIDResourceTable.set(id, obj);
1928: }
1929: }
1930:
1931: void freeContextResources() {
1932: Object obj;
1933: TextureRetained tex;
1934:
1935: for (int id = textureIDResourceTable.size() - 1; id >= 0; id--) {
1936: obj = textureIDResourceTable.get(id);
1937: if (obj == null) {
1938: continue;
1939: }
1940: Canvas3D.freeTexture(sharedCtx, id);
1941: if (obj instanceof TextureRetained) {
1942: tex = (TextureRetained) obj;
1943: synchronized (tex.resourceLock) {
1944: tex.resourceCreationMask &= ~rendererBit;
1945: if (tex.resourceCreationMask == 0) {
1946: tex.freeTextureId(id);
1947: }
1948: }
1949: }
1950: }
1951: textureIDResourceTable.clear();
1952:
1953: // displayList is free in Canvas.freeContextResources()
1954: }
1955:
1956: /**
1957: * Send a message to the notification thread, which will call the
1958: * shader error listeners.
1959: */
1960: static void notifyErrorListeners(RenderingError err) {
1961: J3dNotification notification = new J3dNotification();
1962: notification.type = J3dNotification.RENDERING_ERROR;
1963: notification.universe = null;//cv.view.universe;
1964: notification.args[0] = err;
1965: VirtualUniverse.mc.sendNotification(notification);
1966: }
1967:
1968: // Default rendering error listener class
1969: private static RenderingErrorListener defaultErrorListener = null;
1970:
1971: synchronized static RenderingErrorListener getDefaultErrorListener() {
1972: if (defaultErrorListener == null) {
1973: defaultErrorListener = new DefaultErrorListener();
1974: }
1975:
1976: return defaultErrorListener;
1977: }
1978:
1979: static class DefaultErrorListener implements RenderingErrorListener {
1980: public void errorOccurred(RenderingError error) {
1981: System.err.println();
1982: System.err
1983: .println("DefaultRenderingErrorListener.errorOccurred:");
1984: error.printVerbose();
1985: System.exit(1);
1986: }
1987: }
1988:
1989: }
|