Source Code Cross Referenced for MasterControl.java in  » 6.0-JDK-Modules » java-3d » javax » media » j3d » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » 6.0 JDK Modules » java 3d » javax.media.j3d 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * $RCSfile: MasterControl.java,v $
0003:         *
0004:         * Copyright 1998-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.39 $
0028:         * $Date: 2008/02/28 20:17:26 $
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.*;
0041:        import java.awt.*;
0042:        import java.util.logging.Level;
0043:        import java.util.logging.Logger;
0044:
0045:        class MasterControl {
0046:
0047:            /**
0048:             * Options for the runMonitor 
0049:             */
0050:            static final int CHECK_FOR_WORK = 0;
0051:            static final int SET_WORK = 1;
0052:            static final int RUN_THREADS = 2;
0053:            static final int THREAD_DONE = 3;
0054:            static final int SET_WORK_FOR_REQUEST_RENDERER = 5;
0055:            static final int RUN_RENDERER_CLEANUP = 6;
0056:
0057:            // The thread states for MC
0058:            static final int SLEEPING = 0;
0059:            static final int RUNNING = 1;
0060:            static final int WAITING_FOR_THREADS = 3;
0061:            static final int WAITING_FOR_CPU = 4;
0062:            static final int WAITING_FOR_RENDERER_CLEANUP = 5;
0063:
0064:            // Constants used in renderer thread argument
0065:            static final Integer REQUESTRENDER = new Integer(
0066:                    Renderer.REQUESTRENDER);
0067:            static final Integer RENDER = new Integer(Renderer.RENDER);
0068:            static final Integer SWAP = new Integer(Renderer.SWAP);
0069:
0070:            // Constants used for request from user threads
0071:            static final Integer ACTIVATE_VIEW = new Integer(1);
0072:            static final Integer DEACTIVATE_VIEW = new Integer(2);
0073:            static final Integer START_VIEW = new Integer(3);
0074:            static final Integer STOP_VIEW = new Integer(4);
0075:            static final Integer REEVALUATE_CANVAS = new Integer(5);
0076:            static final Integer UNREGISTER_VIEW = new Integer(6);
0077:            static final Integer PHYSICAL_ENV_CHANGE = new Integer(7);
0078:            static final Integer INPUTDEVICE_CHANGE = new Integer(8);
0079:            static final Integer EMPTY_UNIVERSE = new Integer(9);
0080:            static final Integer START_RENDERER = new Integer(10);
0081:            static final Integer STOP_RENDERER = new Integer(11);
0082:            static final Integer RENDER_ONCE = new Integer(12);
0083:            static final Integer FREE_CONTEXT = new Integer(13);
0084:            static final Integer FREE_DRAWING_SURFACE = new Integer(14);
0085:            static final Integer FREE_MESSAGE = new Integer(15);
0086:            static final Integer RESET_CANVAS = new Integer(16);
0087:            static final Integer GETBESTCONFIG = new Integer(17);
0088:            static final Integer ISCONFIGSUPPORT = new Integer(18);
0089:            static final Integer SET_GRAPHICSCONFIG_FEATURES = new Integer(19);
0090:            static final Integer SET_QUERYPROPERTIES = new Integer(20);
0091:            static final Integer SET_VIEW = new Integer(21);
0092:
0093:            // Developer logger for reporting informational messages; see getDevLogger()
0094:            private static boolean devLoggerEnabled = false;
0095:            private static Logger devLogger;
0096:
0097:            // Stats logger for reporting runtime statistics; see getStatsLogger()
0098:            private static boolean statsLoggerEnabled = false;
0099:            private static Logger statsLogger;
0100:
0101:            // Core logger for reporting internal errors, warning, and
0102:            // informational messages; see getCoreLogger()
0103:            private static boolean coreLoggerEnabled = false;
0104:            private static Logger coreLogger;
0105:
0106:            // Flag indicating that the rendering pipeline libraries are loaded
0107:            private static boolean librariesLoaded = false;
0108:
0109:            // Issue 257: flag indicating that we are running in "appletLauncher" mode
0110:            // and should use JNLPAppletLauncher to load any native libraries
0111:            private static boolean appletLauncher = false;
0112:
0113:            /**
0114:             * reference to MasterControl thread
0115:             */
0116:            private MasterControlThread mcThread = null;
0117:
0118:            /**
0119:             * The list of views that are currently registered
0120:             */
0121:            private UnorderList views = new UnorderList(1, View.class);
0122:
0123:            /**
0124:             * by MIK OF CLASSX
0125:             *
0126:             * the flag to indicate whether the background of the offscreen
0127:             * canvas must be transparent or not false by default
0128:             */
0129:            boolean transparentOffScreen = false;
0130:
0131:            /**
0132:             * Flag to indicate whether Pbuffers are used for off-screen
0133:             * rendering; true by default.  Set by the "j3d.usePbuffer"
0134:             * property, When this flag is set to false, Bitmap (Windows) or
0135:             * Pixmap (UNIX) rendering will be used
0136:             */
0137:            boolean usePbuffer = true;
0138:
0139:            /**
0140:             * Flag to indicate whether should renderer view frustum culling is done;
0141:             * true by default.
0142:             * Set by the -Dj3d.viewFrustumCulling property, When this flag is
0143:             * set to false, the renderer view frustum culling is turned off.
0144:             */
0145:            boolean viewFrustumCulling = true;
0146:
0147:            /**
0148:             * the flag to indicate whether the geometry should be locked or not
0149:             */
0150:
0151:            private boolean lockGeometry = false;
0152:
0153:            /**
0154:             * The number of registered views that are active 
0155:             */
0156:            private int numActiveViews = 0;
0157:
0158:            /**
0159:             * The list of active universes get from View
0160:             */
0161:            private UnorderList activeUniverseList = new UnorderList(
0162:                    VirtualUniverse.class);
0163:
0164:            /**
0165:             * The list of universes register from View
0166:             */
0167:            private UnorderList regUniverseList = new UnorderList(
0168:                    VirtualUniverse.class);
0169:
0170:            /**
0171:             * A lock used for accessing time structures.
0172:             */
0173:            private Object timeLock = new Object();
0174:
0175:            /**
0176:             * The current "time" value
0177:             */
0178:            private long time = 0;
0179:
0180:            /**
0181:             * Use to assign threadOpts in Renderer thread. 
0182:             */
0183:            private long waitTimestamp = 0;
0184:
0185:            /**
0186:             * The current list of work threads
0187:             */
0188:            private UnorderList stateWorkThreads = new UnorderList(
0189:                    J3dThreadData.class);
0190:            private UnorderList renderWorkThreads = new UnorderList(
0191:                    J3dThreadData.class);
0192:            private UnorderList requestRenderWorkThreads = new UnorderList(
0193:                    J3dThreadData.class);
0194:
0195:            /**
0196:             * The current list of work threads
0197:             */
0198:            private UnorderList renderThreadData = new UnorderList(
0199:                    J3dThreadData.class);
0200:
0201:            /**
0202:             * The list of input device scheduler thread
0203:             */
0204:            private UnorderList inputDeviceThreads = new UnorderList(1,
0205:                    InputDeviceScheduler.class);
0206:
0207:            /**
0208:             * A flag that is true when the thread lists need updating
0209:             */
0210:            private boolean threadListsChanged;
0211:
0212:            /**
0213:             * Markers for the last transform structure update thread
0214:             * and the last update thread.
0215:             */
0216:            private int lastTransformStructureThread = 0;
0217:            private int lastStructureUpdateThread = 0;
0218:
0219:            /**
0220:             * The current time snapshots
0221:             */
0222:            private long currentTime;
0223:
0224:            // Only one Timer thread in the system.
0225:            TimerThread timerThread;
0226:
0227:            // Only one Notification thread in the system.
0228:            private NotificationThread notificationThread;
0229:
0230:            /**
0231:             * This flag indicates that MC is running
0232:             */
0233:            volatile boolean running = true;
0234:
0235:            /**
0236:             * This flag indicates that MC has work to do
0237:             */
0238:            private boolean workToDo = false;
0239:
0240:            /**
0241:             * This flag indicates that there is work for requestRenderer
0242:             */
0243:            private boolean requestRenderWorkToDo = false;
0244:
0245:            /** 
0246:             * The number of THREAD_DONE messages pending
0247:             */
0248:            private int threadPending = 0;
0249:            private int renderPending = 0;
0250:            private int statePending = 0;
0251:
0252:            /**
0253:             * State variables for work lists
0254:             */
0255:            private boolean renderWaiting = false;
0256:            private boolean stateWaiting = false;
0257:
0258:            /**
0259:             * The current state of the MC thread
0260:             */
0261:            private int state = SLEEPING;
0262:
0263:            // time for sleep in order to met the minimum frame duration
0264:            private long sleepTime = 0;
0265:
0266:            /**
0267:             * The number of cpu's Java 3D may use
0268:             */
0269:            private int cpuLimit;
0270:
0271:            /**
0272:             * A list of mirror objects to be updated
0273:             */
0274:            private UnorderList mirrorObjects = new UnorderList(
0275:                    ObjectUpdate.class);
0276:
0277:            /**
0278:             * The renderingAttributesStructure for updating node component 
0279:             * objects
0280:             */
0281:            private RenderingAttributesStructure renderingAttributesStructure = new RenderingAttributesStructure();
0282:
0283:            /**
0284:             * The default rendering method
0285:             */
0286:            private DefaultRenderMethod defaultRenderMethod = null;
0287:
0288:            /**
0289:             * The text3D rendering method
0290:             */
0291:            private Text3DRenderMethod text3DRenderMethod = null;
0292:
0293:            /**
0294:             * The vertex array rendering method
0295:             */
0296:            private VertexArrayRenderMethod vertexArrayRenderMethod = null;
0297:
0298:            /**
0299:             * The displayList rendering method
0300:             */
0301:            private DisplayListRenderMethod displayListRenderMethod = null;
0302:
0303:            /**
0304:             * The compressed geometry rendering method
0305:             */
0306:            private CompressedGeometryRenderMethod compressedGeometryRenderMethod = null;
0307:
0308:            /**
0309:             * The oriented shape3D rendering method
0310:             */
0311:            private OrientedShape3DRenderMethod orientedShape3DRenderMethod = null;
0312:
0313:            /**
0314:             * This is the start time upon which alpha's and behaviors
0315:             * are synchronized to. It is initialized once, the first time
0316:             * that a MasterControl object is created.
0317:             */
0318:            static long systemStartTime = 0L;
0319:
0320:            // Flag indicating that we are on a Windows OS
0321:            private static boolean isWindowsOs = false;
0322:
0323:            // Flag indicating we are on MacOS
0324:            private static boolean isMacOs = false;
0325:
0326:            // This is a counter for texture id's, valid id starts from 1
0327:            private int textureIdCount = 0;
0328:
0329:            // This is lock for both 2D/3D textureIds;
0330:            private Object textureIdLock = new Object();
0331:
0332:            // This is a time stamp used when context is created
0333:            private long contextTimeStamp = 0;
0334:
0335:            // This is an array of  canvasIds in used
0336:            private boolean[] canvasIds = null;
0337:            private int canvasFreeIndex = 0;
0338:            private Object canvasIdLock = new Object();
0339:
0340:            // This is a counter for rendererBit
0341:            private int rendererCount = 0;
0342:
0343:            // Flag that indicates whether to shared display context or not
0344:            boolean isSharedCtx = false;
0345:
0346:            // Flag that tells us to use NV_register_combiners
0347:            boolean useCombiners = false;
0348:
0349:            // Flag that indicates whether compile is disabled or not
0350:            boolean disableCompile = false;
0351:
0352:            // Flag that indicates whether or not compaction occurs
0353:            boolean doCompaction = true;
0354:
0355:            // Flag that indicates whether separate specular color is disabled or not
0356:            boolean disableSeparateSpecularColor = false;
0357:
0358:            // Flag that indicates whether DisplayList is used or not
0359:            boolean isDisplayList = true;
0360:
0361:            // If this flag is set, then by-ref geometry will not be
0362:            // put in display list
0363:            boolean buildDisplayListIfPossible = false;
0364:
0365:            // If this flag is set, then geometry arrays with vertex attributes can
0366:            // be in display list.
0367:            boolean vertexAttrsInDisplayList = false;
0368:
0369:            // Issue 249 - flag that indicates whether the soleUser optimization is permitted
0370:            boolean allowSoleUser = false;
0371:
0372:            // Issue 266 - Flag indicating whether null graphics configs are allowed
0373:            // Set by -Dj3d.allowNullGraphicsConfig property
0374:            // Setting this flag causes Canvas3D to allow a null GraphicsConfiguration
0375:            // for on-screen canvases. This is only for backward compatibility with
0376:            // legacy applications.
0377:            boolean allowNullGraphicsConfig = false;
0378:
0379:            // Issue 239 - Flag indicating whether the stencil buffer is cleared by
0380:            // default each frame when the color and depth buffers are cleared.
0381:            // Note that this is a partial solution, since we eventually want an API
0382:            // to control this.
0383:            boolean stencilClear = false;
0384:
0385:            // The global shading language being used. Using a ShaderProgram
0386:            // with a shading language other than the one specified by
0387:            // globalShadingLanguage will cause a ShaderError to be generated,
0388:            static int globalShadingLanguage = Shader.SHADING_LANGUAGE_GLSL;
0389:
0390:            // Flags indicating whether the Cg or GLSL libraries are available; we still need
0391:            // to check for the actual extension support when the Canvas3D with its associated context
0392:            // is created. Note that these are qualifed by the above globalShadingLanguage, so at
0393:            // most one of these two flags will be true;
0394:            static boolean cgLibraryAvailable = false;
0395:            static boolean glslLibraryAvailable = false;
0396:
0397:            // REQUESTCLEANUP messages argument
0398:            static Integer REMOVEALLCTXS_CLEANUP = new Integer(1);
0399:            static Integer REMOVECTX_CLEANUP = new Integer(2);
0400:            static Integer REMOVENOTIFY_CLEANUP = new Integer(3);
0401:            static Integer RESETCANVAS_CLEANUP = new Integer(4);
0402:            static Integer FREECONTEXT_CLEANUP = new Integer(5);
0403:
0404:            // arguments for renderer resource cleanup run
0405:            Object rendererCleanupArgs[] = {
0406:                    new Integer(Renderer.REQUESTCLEANUP), null, null };
0407:
0408:            // Context creation should obtain this lock, so that
0409:            // first_time and all the extension initilialization
0410:            // are done in the MT safe manner
0411:            Object contextCreationLock = new Object();
0412:
0413:            // Flag that indicates whether to lock the DSI while rendering
0414:            boolean doDsiRenderLock = false;
0415:
0416:            // Flag that indicates the pre-1.5 behavior of enforcing power-of-two
0417:            // textures. If set, then any non-power-of-two textures will throw an
0418:            // exception.
0419:            boolean enforcePowerOfTwo = false;
0420:
0421:            // Flag that indicates whether the framebuffer is sharing the
0422:            // Z-buffer with both the left and right eyes when in stereo mode.
0423:            // If this is true, we need to clear the Z-buffer between rendering
0424:            // to the left and right eyes.
0425:            boolean sharedStereoZBuffer = true;
0426:
0427:            // True to disable all underlying multisampling API so it uses
0428:            // the setting in the driver. 
0429:            boolean implicitAntialiasing = false;
0430:
0431:            // False to disable compiled vertex array extensions if support
0432:            boolean isCompiledVertexArray = true;
0433:
0434:            // Number of reserved vertex attribute locations for GLSL (must be at
0435:            // least 1).
0436:            // Issue 269 - need to reserve up to 6 vertex attribtue locations to ensure
0437:            // that we don't collide with a predefined gl_* attribute on nVidia cards.
0438:            int glslVertexAttrOffset = 6;
0439:
0440:            // Hashtable that maps a GraphicsDevice to its associated
0441:            // Screen3D--this is only used for on-screen Canvas3Ds
0442:            Hashtable deviceScreenMap = new Hashtable();
0443:
0444:            // Use to store all requests from user threads.
0445:            UnorderList requestObjList = new UnorderList();
0446:            private UnorderList requestTypeList = new UnorderList(Integer.class);
0447:
0448:            // Temporary storage to store stop request for requestViewList
0449:            private UnorderList tempViewList = new UnorderList();
0450:            private UnorderList renderOnceList = new UnorderList();
0451:
0452:            // This flag is true when there is pending request
0453:            // i.e. false when the above requestxxx Lists are all empty.
0454:            private boolean pendingRequest = false;
0455:
0456:            // Root ThreadGroup for creating Java 3D threads
0457:            private static ThreadGroup rootThreadGroup;
0458:
0459:            // Thread priority for all Java 3D threads
0460:            private static int threadPriority;
0461:
0462:            static private Object mcThreadLock = new Object();
0463:
0464:            private ArrayList timestampUpdateList = new ArrayList(3);
0465:
0466:            private UnorderList freeMessageList = new UnorderList(8);
0467:
0468:            // Native AWT object
0469:            long awt;
0470:
0471:            // Maximum number of lights
0472:            int maxLights;
0473:
0474:            // This is used for D3D only
0475:            int resendTexTimestamp = 0;
0476:
0477:            // Indicates that the property to disable Xinerama mode was set and
0478:            // successfully disabled.
0479:            boolean xineramaDisabled = false;
0480:
0481:            // Set by the -Dj3d.sortShape3DBounds property, When this flag is
0482:            // set to true, the bounds of the Shape3D node will be used in
0483:            // place of the computed GeometryArray bounds for transparency
0484:            // sorting for those Shape3D nodes whose boundsAutoCompute
0485:            // attribute is set to false.
0486:            boolean sortShape3DBounds = false;
0487:
0488:            //Set by -Dj3d.forceReleaseView property.
0489:            //Setting this flag as true disables the bug fix 4267395 in View deactivate().
0490:            //The bug 4267395 can lock-up *some* systems, but the bug fix can
0491:            //produce memory leaks in applications which creates and destroy Canvas3D
0492:            //from time to time.
0493:            //Set as true if you have memory leaks after disposing Canvas3D.
0494:            //Default false value does affect Java3D View dispose behavior.
0495:            boolean forceReleaseView = false;
0496:
0497:            // Issue 561: Set by -Dj3d.releaseBoundingBoxMemory property.
0498:            // When set to true, the per-instance fields used in bounding box
0499:            // transformation are released at the end of transform methods. This saves
0500:            // a significant amount of memory in large scenes containing huge amounts
0501:            // of bounding boxes. Setting this false can improve performance when
0502:            // lots of transforms are performed. The default is false.
0503:            boolean releaseBoundingBoxMemory = false;
0504:
0505:            // Issue 480: Cache the bounds of nodes so that getBounds does not 
0506:            // recompute the boounds of the entire graph per call
0507:            boolean cacheAutoComputedBounds = false;
0508:
0509:            // issue 544
0510:            boolean useBoxForGroupBounds = false;
0511:
0512:            /**
0513:             * Constructs a new MasterControl object.  Note that there is
0514:             * exatly one MasterControl object, created statically by
0515:             * VirtualUniverse.
0516:             */
0517:            MasterControl() {
0518:                assert librariesLoaded;
0519:
0520:                // Get AWT handle
0521:                awt = Pipeline.getPipeline().getAWT();
0522:
0523:                // Initialize the start time upon which alpha's and behaviors
0524:                // are synchronized to (if it isn't already set).
0525:                if (systemStartTime == 0L) {
0526:                    systemStartTime = J3dClock.currentTimeMillis();
0527:                }
0528:
0529:                if (J3dDebug.devPhase) {
0530:                    // Check to see whether debug mode is allowed
0531:                    J3dDebug.debug = getBooleanProperty("j3d.debug", false,
0532:                            "J3dDebug.debug");
0533:                }
0534:
0535:                // Check to see whether shared contexts are allowed
0536:                if (!isD3D()) {
0537:                    isSharedCtx = getBooleanProperty("j3d.sharedctx",
0538:                            isSharedCtx, "shared contexts");
0539:                }
0540:
0541:                doCompaction = getBooleanProperty("j3d.docompaction",
0542:                        doCompaction, "compaction");
0543:
0544:                // by MIK OF CLASSX
0545:                transparentOffScreen = getBooleanProperty(
0546:                        "j3d.transparentOffScreen", transparentOffScreen,
0547:                        "transparent OffScreen");
0548:
0549:                usePbuffer = getBooleanProperty("j3d.usePbuffer", usePbuffer,
0550:                        "Off-screen Pbuffer");
0551:
0552:                viewFrustumCulling = getBooleanProperty(
0553:                        "j3d.viewFrustumCulling", viewFrustumCulling,
0554:                        "View frustum culling in the renderer is");
0555:
0556:                sortShape3DBounds = getBooleanProperty("j3d.sortShape3DBounds",
0557:                        sortShape3DBounds,
0558:                        "Shape3D bounds enabled for transparency sorting",
0559:                        "Shape3D bounds *ignored* for transparency sorting");
0560:
0561:                forceReleaseView = getBooleanProperty("j3d.forceReleaseView",
0562:                        forceReleaseView,
0563:                        "forceReleaseView  after Canvas3D dispose enabled",
0564:                        "forceReleaseView  after Canvas3D dispose disabled");
0565:
0566:                releaseBoundingBoxMemory = getBooleanProperty(
0567:                        "j3d.releaseBoundingBoxMemory",
0568:                        releaseBoundingBoxMemory,
0569:                        "releasing memory after bounding box transform");
0570:
0571:                useCombiners = getBooleanProperty("j3d.usecombiners",
0572:                        useCombiners,
0573:                        "Using NV_register_combiners if available",
0574:                        "NV_register_combiners disabled");
0575:
0576:                if (getProperty("j3d.disablecompile") != null) {
0577:                    disableCompile = true;
0578:                    System.err.println("Java 3D: BranchGroup.compile disabled");
0579:                }
0580:
0581:                if (getProperty("j3d.disableSeparateSpecular") != null) {
0582:                    disableSeparateSpecularColor = true;
0583:                    System.err
0584:                            .println("Java 3D: separate specular color disabled if possible");
0585:                }
0586:
0587:                isDisplayList = getBooleanProperty("j3d.displaylist",
0588:                        isDisplayList, "display list");
0589:
0590:                implicitAntialiasing = getBooleanProperty(
0591:                        "j3d.implicitAntialiasing", implicitAntialiasing,
0592:                        "implicit antialiasing");
0593:
0594:                isCompiledVertexArray = getBooleanProperty(
0595:                        "j3d.compiledVertexArray", isCompiledVertexArray,
0596:                        "compiled vertex array");
0597:
0598:                boolean j3dOptimizeSpace = getBooleanProperty(
0599:                        "j3d.optimizeForSpace", true, "optimize for space");
0600:
0601:                if (isDisplayList) {
0602:                    // Build Display list for by-ref geometry
0603:                    // ONLY IF optimizeForSpace is false
0604:                    if (!j3dOptimizeSpace) {
0605:                        buildDisplayListIfPossible = true;
0606:                    }
0607:
0608:                    // Build display lists for geometry with vertex attributes
0609:                    // ONLY if we are in GLSL mode and GLSL shaders are available
0610:                    if (glslLibraryAvailable) {
0611:                        vertexAttrsInDisplayList = true;
0612:                    }
0613:                }
0614:
0615:                // Check to see whether Renderer can run without DSI lock
0616:                doDsiRenderLock = getBooleanProperty("j3d.renderLock",
0617:                        doDsiRenderLock, "render lock");
0618:
0619:                // Check to see whether we enforce power-of-two textures
0620:                enforcePowerOfTwo = getBooleanProperty(
0621:                        "j3d.textureEnforcePowerOfTwo", enforcePowerOfTwo,
0622:                        "checking power-of-two textures");
0623:
0624:                // Issue 249 - check to see whether the soleUser optimization is permitted
0625:                allowSoleUser = getBooleanProperty("j3d.allowSoleUser",
0626:                        allowSoleUser, "sole-user mode");
0627:
0628:                // Issue 266 - check to see whether null graphics configs are allowed
0629:                allowNullGraphicsConfig = getBooleanProperty(
0630:                        "j3d.allowNullGraphicsConfig", allowNullGraphicsConfig,
0631:                        "null graphics configs");
0632:
0633:                // Issue 239 - check to see whether per-frame stencil clear is enabled
0634:                stencilClear = getBooleanProperty("j3d.stencilClear",
0635:                        stencilClear, "per-frame stencil clear");
0636:
0637:                // Check to see if stereo mode is sharing the Z-buffer for both eyes.
0638:                sharedStereoZBuffer = getBooleanProperty(
0639:                        "j3d.sharedstereozbuffer", sharedStereoZBuffer,
0640:                        "shared stereo Z buffer");
0641:
0642:                // Get the maximum number of concurrent threads (CPUs)
0643:                final int defaultThreadLimit = getNumberOfProcessors() + 1;
0644:                Integer threadLimit = (Integer) java.security.AccessController
0645:                        .doPrivileged(new java.security.PrivilegedAction() {
0646:                            public Object run() {
0647:                                return Integer.getInteger("j3d.threadLimit",
0648:                                        defaultThreadLimit);
0649:                            }
0650:                        });
0651:
0652:                cpuLimit = threadLimit.intValue();
0653:                if (cpuLimit < 1)
0654:                    cpuLimit = 1;
0655:                if (J3dDebug.debug || cpuLimit != defaultThreadLimit) {
0656:                    System.err.println("Java 3D: concurrent threadLimit = "
0657:                            + cpuLimit);
0658:                }
0659:
0660:                // Get the input device scheduler sampling time
0661:                Integer samplingTime = (Integer) java.security.AccessController
0662:                        .doPrivileged(new java.security.PrivilegedAction() {
0663:                            public Object run() {
0664:                                return Integer.getInteger(
0665:                                        "j3d.deviceSampleTime", 0);
0666:                            }
0667:                        });
0668:
0669:                if (samplingTime.intValue() > 0) {
0670:                    InputDeviceScheduler.samplingTime = samplingTime.intValue();
0671:                    System.err.println("Java 3D: Input device sampling time = "
0672:                            + samplingTime + " ms");
0673:                }
0674:
0675:                // Get the glslVertexAttrOffset
0676:                final int defaultGLSLVertexAttrOffset = glslVertexAttrOffset;
0677:                Integer vattrOffset = (Integer) java.security.AccessController
0678:                        .doPrivileged(new java.security.PrivilegedAction() {
0679:                            public Object run() {
0680:                                return Integer.getInteger(
0681:                                        "j3d.glslVertexAttrOffset",
0682:                                        defaultGLSLVertexAttrOffset);
0683:                            }
0684:                        });
0685:
0686:                glslVertexAttrOffset = vattrOffset.intValue();
0687:                if (glslVertexAttrOffset < 1) {
0688:                    glslVertexAttrOffset = 1;
0689:                }
0690:                if (J3dDebug.debug
0691:                        || glslVertexAttrOffset != defaultGLSLVertexAttrOffset) {
0692:                    System.err.println("Java 3D: glslVertexAttrOffset = "
0693:                            + glslVertexAttrOffset);
0694:                }
0695:
0696:                // See if Xinerama should be disabled for better performance.
0697:                boolean disableXinerama = false;
0698:                if (getProperty("j3d.disableXinerama") != null) {
0699:                    disableXinerama = true;
0700:                }
0701:
0702:                // Issue 480 : Cache bounds returned by getBounds()
0703:                cacheAutoComputedBounds = getBooleanProperty(
0704:                        "j3d.cacheAutoComputeBounds", cacheAutoComputedBounds,
0705:                        "Cache AutoCompute Bounds, accelerates getBounds()");
0706:
0707:                // Issue 544
0708:                useBoxForGroupBounds = getBooleanProperty(
0709:                        "j3d.useBoxForGroupBounds", useBoxForGroupBounds,
0710:                        "Use of BoundingBox for group geometric bounds");
0711:
0712:                // Initialize the native J3D library
0713:                if (!Pipeline.getPipeline().initializeJ3D(disableXinerama)) {
0714:                    throw new RuntimeException(J3dI18N
0715:                            .getString("MasterControl0"));
0716:                }
0717:
0718:                if (xineramaDisabled) {
0719:                    // initializeJ3D() successfully disabled Xinerama.
0720:                    System.err.println("Java 3D: Xinerama disabled");
0721:                } else if (disableXinerama) {
0722:                    // j3d.disableXinerama is true, but attempt failed.
0723:                    System.err.println("Java 3D: could not disable Xinerama");
0724:                }
0725:
0726:                // Check for obsolete properties
0727:                String[] obsoleteProps = { "j3d.backgroundtexture",
0728:                        "j3d.forceNormalized", "j3d.g2ddrawpixel",
0729:                        "j3d.simulatedMultiTexture", "j3d.useFreeLists", };
0730:                for (int i = 0; i < obsoleteProps.length; i++) {
0731:                    if (getProperty(obsoleteProps[i]) != null) {
0732:                        System.err.println("Java 3D: " + obsoleteProps[i]
0733:                                + " property ignored");
0734:                    }
0735:                }
0736:
0737:                // Get the maximum Lights
0738:                maxLights = Pipeline.getPipeline().getMaximumLights();
0739:
0740:                // create the freelists 
0741:                FreeListManager.createFreeLists();
0742:
0743:                // create an array canvas use registers
0744:                // The 32 limit can be lifted once the
0745:                // resourceXXXMasks in other classes 
0746:                // are change not to use integer.
0747:                canvasIds = new boolean[32];
0748:                for (int i = 0; i < canvasIds.length; i++) {
0749:                    canvasIds[i] = false;
0750:                }
0751:                canvasFreeIndex = 0;
0752:            }
0753:
0754:            private static boolean initLogger(Logger logger, Level defaultLevel) {
0755:                if (logger == null) {
0756:                    return false;
0757:                }
0758:
0759:                if (defaultLevel != null && logger.getLevel() == null
0760:                        && Logger.getLogger("j3d").getLevel() == null) {
0761:
0762:                    try {
0763:                        // Set default logger level rather than inheriting from system global
0764:                        logger.setLevel(defaultLevel);
0765:                    } catch (SecurityException ex) {
0766:                        System.err.println(ex);
0767:                        return false;
0768:                    }
0769:                }
0770:
0771:                return logger.isLoggable(Level.SEVERE);
0772:            }
0773:
0774:            // Called by the static initializer to initialize the loggers
0775:            private static void initLoggers() {
0776:                coreLogger = Logger.getLogger("j3d.core");
0777:                devLogger = Logger.getLogger("j3d.developer");
0778:                statsLogger = Logger.getLogger("j3d.stats");
0779:
0780:                java.security.AccessController
0781:                        .doPrivileged(new java.security.PrivilegedAction() {
0782:                            public Object run() {
0783:                                coreLoggerEnabled = initLogger(coreLogger, null);
0784:                                devLoggerEnabled = initLogger(devLogger,
0785:                                        Level.OFF);
0786:                                statsLoggerEnabled = initLogger(statsLogger,
0787:                                        Level.OFF);
0788:                                return null;
0789:                            }
0790:                        });
0791:            }
0792:
0793:            /**
0794:             * Get the developer logger -- OFF by default
0795:             *
0796:             * WARNING - for probable incorrect or inconsistent api usage
0797:             * INFO - for informational messages such as performance hints (less verbose than FINE)
0798:             * FINE - for informational messages from inner loops
0799:             * FINER - using default values which may not be optimal
0800:             */
0801:            static Logger getDevLogger() {
0802:                return devLogger;
0803:            }
0804:
0805:            static boolean isDevLoggable(Level level) {
0806:                return devLoggerEnabled && devLogger.isLoggable(level);
0807:            }
0808:
0809:            /**
0810:             * Get the stats logger -- OFF by default
0811:             *
0812:             * WARNING - statistical anomalies
0813:             * INFO - basic performance stats - not too verbose and minimally intrusive
0814:             * FINE - somewhat verbose and intrusive
0815:             * FINER - more verbose and intrusive
0816:             * FINEST - most verbose and intrusive
0817:             */
0818:            static Logger getStatsLogger() {
0819:                return statsLogger;
0820:            }
0821:
0822:            static boolean isStatsLoggable(Level level) {
0823:                return statsLoggerEnabled && statsLogger.isLoggable(level);
0824:            }
0825:
0826:            /**
0827:             * Get the core logger -- level is INFO by default
0828:             *
0829:             * SEVERE - Serious internal errors
0830:             * WARNING - Possible internal errors or anomalies
0831:             * INFO - General informational messages
0832:             * FINE - Internal debugging information - somewhat verbose
0833:             * FINER - Internal debugging information - more verbose
0834:             * FINEST - Internal debugging information - most verbose
0835:             */
0836:            static Logger getCoreLogger() {
0837:                return coreLogger;
0838:            }
0839:
0840:            static boolean isCoreLoggable(Level level) {
0841:                return coreLoggerEnabled && coreLogger.isLoggable(level);
0842:            }
0843:
0844:            private static String getProperty(final String prop) {
0845:                return (String) java.security.AccessController
0846:                        .doPrivileged(new java.security.PrivilegedAction() {
0847:                            public Object run() {
0848:                                return System.getProperty(prop);
0849:                            }
0850:                        });
0851:            }
0852:
0853:            private static boolean getBooleanProperty(String prop,
0854:                    boolean defaultValue, String trueMsg, String falseMsg) {
0855:                boolean value = defaultValue;
0856:                String propValue = getProperty(prop);
0857:
0858:                if (propValue != null) {
0859:                    value = Boolean.valueOf(propValue).booleanValue();
0860:                    System.err.println("Java 3D: "
0861:                            + (value ? trueMsg : falseMsg));
0862:                }
0863:                return value;
0864:            }
0865:
0866:            private static boolean getBooleanProperty(String prop,
0867:                    boolean defaultValue, String msg) {
0868:                return getBooleanProperty(prop, defaultValue,
0869:                        (msg + " enabled"), (msg + " disabled"));
0870:            }
0871:
0872:            /**
0873:             * Method to create and initialize the rendering Pipeline object,
0874:             * and to load the native libraries needed by Java 3D. This is
0875:             * called by the static initializer in VirtualUniverse <i>before</i>
0876:             * the MasterControl object is created.
0877:             */
0878:            static void loadLibraries() {
0879:                assert !librariesLoaded;
0880:
0881:                // Get platform system properties
0882:                String osName = getProperty("os.name").toLowerCase();
0883:                String sunArchDataModel = getProperty("sun.arch.data.model");
0884:
0885:                // Set global flags based on platform architecture
0886:                isMacOs = osName != null && osName.startsWith("mac");
0887:                isWindowsOs = osName != null && osName.startsWith("windows");
0888:                boolean isWindowsVista = isWindowsOs
0889:                        && osName.indexOf("vista") != -1;
0890:                boolean is64Bit = (sunArchDataModel != null)
0891:                        && sunArchDataModel.equals("64");
0892:
0893:                // Issue 257: check to see if the sun.jnlp.applet.launcher property is set to true
0894:                String sunAppletLauncher = getProperty("sun.jnlp.applet.launcher");
0895:                appletLauncher = Boolean.valueOf(sunAppletLauncher);
0896:
0897:                if (isCoreLoggable(Level.CONFIG)) {
0898:                    StringBuffer strBuf = new StringBuffer();
0899:                    strBuf.append("MasterControl.loadLibraries()\n").append(
0900:                            "    osName [lower-case] = \"").append(osName)
0901:                            .append("\"").append(", sunArchDataModel = ")
0902:                            .append(sunArchDataModel).append("\n").append(
0903:                                    "    is64Bit = ").append(is64Bit).append(
0904:                                    ", isWindowsOs = ").append(isWindowsOs)
0905:                            .append(", isMacOs = ").append(isMacOs).append(
0906:                                    ", isWindowsVista = ").append(
0907:                                    isWindowsVista);
0908:                    getCoreLogger().config(strBuf.toString());
0909:                }
0910:
0911:                // Initialize the Pipeline object associated with the
0912:                // renderer specified by the "j3d.rend" system property.
0913:                //
0914:                // XXXX : We should consider adding support for a more flexible,
0915:                // dynamic selection scheme via an API call.
0916:
0917:                // Default rendering pipeline is the JOGL pipeline on MacOS and the
0918:                // native OpenGL pipeline on all other platforms.
0919:                Pipeline.Type pipelineType = isMacOs ? Pipeline.Type.JOGL
0920:                        : Pipeline.Type.NATIVE_OGL;
0921:
0922:                final String rendStr = getProperty("j3d.rend");
0923:                boolean nativeOglRequested = false;
0924:                if (rendStr == null) {
0925:                    // Use default pipeline
0926:                } else if (rendStr.equals("ogl") && !isMacOs) {
0927:                    pipelineType = Pipeline.Type.NATIVE_OGL;
0928:                    nativeOglRequested = true;
0929:                } else if (rendStr.equals("d3d") && isWindowsOs) {
0930:                    pipelineType = Pipeline.Type.NATIVE_D3D;
0931:                } else if (rendStr.equals("jogl")) {
0932:                    pipelineType = Pipeline.Type.JOGL;
0933:                } else if (rendStr.equals("noop")) {
0934:                    pipelineType = Pipeline.Type.NOOP;
0935:                } else {
0936:                    System.err.println("Java 3D: Unrecognized renderer: "
0937:                            + rendStr);
0938:                    // Use default pipeline
0939:                }
0940:
0941:                // Issue 452 : if we are on 32-bit Windows, then check whether we
0942:                // can and should use OpenGL. Note that we can't do this on 64-bit
0943:                // Windows until we have a 64-bit D3D pipeline.
0944:                if (isWindowsOs && !is64Bit
0945:                        && pipelineType == Pipeline.Type.NATIVE_OGL) {
0946:                    if (!Pipeline.useNativeOgl(isWindowsVista,
0947:                            nativeOglRequested)) {
0948:                        pipelineType = Pipeline.Type.NATIVE_D3D;
0949:                    }
0950:                }
0951:
0952:                // Construct the singleton Pipeline instance
0953:                Pipeline.createPipeline(pipelineType);
0954:
0955:                // Get the global j3d.shadingLanguage system property
0956:                final String slStr = getProperty("j3d.shadingLanguage");
0957:                if (slStr != null) {
0958:                    boolean found = false;
0959:                    if (slStr.equals("GLSL")) {
0960:                        globalShadingLanguage = Shader.SHADING_LANGUAGE_GLSL;
0961:                        found = true;
0962:                    } else if (slStr.equals("Cg")) {
0963:                        globalShadingLanguage = Shader.SHADING_LANGUAGE_CG;
0964:                        found = true;
0965:                    }
0966:
0967:                    if (found) {
0968:                        System.err
0969:                                .println("Java 3D: Setting global shading language to "
0970:                                        + slStr);
0971:                    } else {
0972:                        System.err
0973:                                .println("Java 3D: Unrecognized shading language: "
0974:                                        + slStr);
0975:                    }
0976:                }
0977:
0978:                // Load all required libraries
0979:                Pipeline.getPipeline().loadLibraries(globalShadingLanguage);
0980:
0981:                // Check whether the Cg library is available
0982:                if (globalShadingLanguage == Shader.SHADING_LANGUAGE_CG) {
0983:                    cgLibraryAvailable = Pipeline.getPipeline()
0984:                            .isCgLibraryAvailable();
0985:                }
0986:
0987:                // Check whether the GLSL library is available
0988:                if (globalShadingLanguage == Shader.SHADING_LANGUAGE_GLSL) {
0989:                    glslLibraryAvailable = Pipeline.getPipeline()
0990:                            .isGLSLLibraryAvailable();
0991:                }
0992:
0993:                assert !(glslLibraryAvailable && cgLibraryAvailable) : "ERROR: cannot support both GLSL and CG at the same time";
0994:
0995:                librariesLoaded = true;
0996:            }
0997:
0998:            /**
0999:             * Invoke from InputDeviceScheduler to create an
1000:             * InputDeviceBlockingThread. 
1001:             */
1002:            InputDeviceBlockingThread getInputDeviceBlockingThread(
1003:                    final InputDevice device) {
1004:
1005:                return (InputDeviceBlockingThread) java.security.AccessController
1006:                        .doPrivileged(new java.security.PrivilegedAction() {
1007:                            public Object run() {
1008:                                synchronized (rootThreadGroup) {
1009:                                    Thread thread = new InputDeviceBlockingThread(
1010:                                            rootThreadGroup, device);
1011:                                    thread.setPriority(threadPriority);
1012:                                    return thread;
1013:                                }
1014:                            }
1015:                        });
1016:            }
1017:
1018:            /**
1019:             * Set thread priority to all threads under Java3D thread group.
1020:             */
1021:            void setThreadPriority(final int pri) {
1022:                synchronized (rootThreadGroup) {
1023:                    threadPriority = pri;
1024:                    java.security.AccessController
1025:                            .doPrivileged(new java.security.PrivilegedAction() {
1026:                                public Object run() {
1027:                                    Thread list[] = new Thread[rootThreadGroup
1028:                                            .activeCount()];
1029:                                    int count = rootThreadGroup.enumerate(list);
1030:                                    for (int i = count - 1; i >= 0; i--) {
1031:                                        list[i].setPriority(pri);
1032:                                    }
1033:                                    return null;
1034:                                }
1035:                            });
1036:                }
1037:            }
1038:
1039:            /**
1040:             * Return Java3D thread priority
1041:             */
1042:            int getThreadPriority() {
1043:                return threadPriority;
1044:            }
1045:
1046:            /**
1047:             * This returns the a unused renderer bit
1048:             */
1049:            int getRendererBit() {
1050:                return (1 << rendererCount++);
1051:            }
1052:
1053:            /**
1054:             * This returns the a unused renderer bit
1055:             */
1056:            int getRendererId() {
1057:                return rendererCount++;
1058:            }
1059:
1060:            /**
1061:             * This returns a context creation time stamp
1062:             * Note: this has to be called under the contextCreationLock
1063:             */
1064:            long getContextTimeStamp() {
1065:                return (++contextTimeStamp);
1066:            }
1067:
1068:            /**
1069:             * This returns the a unused displayListId
1070:             */
1071:            Integer getDisplayListId() {
1072:                return (Integer) FreeListManager
1073:                        .getObject(FreeListManager.DISPLAYLIST);
1074:            }
1075:
1076:            void freeDisplayListId(Integer id) {
1077:                FreeListManager.freeObject(FreeListManager.DISPLAYLIST, id);
1078:            }
1079:
1080:            /**
1081:             * This returns the a unused textureId
1082:             */
1083:            int getTexture2DId() {
1084:                // MasterControl has to handle the ID itself.  2D and 3D ideas must
1085:                // never be the same, so the counter has to be in the MasterControl
1086:                MemoryFreeList textureIds = FreeListManager
1087:                        .getFreeList(FreeListManager.TEXTURE2D);
1088:                int id;
1089:
1090:                synchronized (textureIdLock) {
1091:                    if (textureIds.size() > 0) {
1092:                        id = ((Integer) FreeListManager
1093:                                .getObject(FreeListManager.TEXTURE2D))
1094:                                .intValue();
1095:                    } else {
1096:                        id = (++textureIdCount);
1097:                    }
1098:                    return id;
1099:                }
1100:            }
1101:
1102:            int getTexture3DId() {
1103:                // MasterControl has to handle the ID itself.  2D and 3D ideas must
1104:                // never be the same, so the counter has to be in the MasterControl
1105:                MemoryFreeList textureIds = FreeListManager
1106:                        .getFreeList(FreeListManager.TEXTURE3D);
1107:                synchronized (textureIdLock) {
1108:                    if (textureIds.size > 0) {
1109:                        return ((Integer) FreeListManager
1110:                                .getObject(FreeListManager.TEXTURE3D))
1111:                                .intValue();
1112:                    } else
1113:                        return (++textureIdCount);
1114:                }
1115:            }
1116:
1117:            void freeTexture2DId(int id) {
1118:                FreeListManager.freeObject(FreeListManager.TEXTURE2D,
1119:                        new Integer(id));
1120:            }
1121:
1122:            void freeTexture3DId(int id) {
1123:                FreeListManager.freeObject(FreeListManager.TEXTURE3D,
1124:                        new Integer(id));
1125:            }
1126:
1127:            int getCanvasId() {
1128:                int i;
1129:
1130:                synchronized (canvasIdLock) {
1131:                    // Master control need to keep count itself        
1132:                    for (i = canvasFreeIndex; i < canvasIds.length; i++) {
1133:                        if (canvasIds[i] == false)
1134:                            break;
1135:                    }
1136:
1137:                    if (i >= canvasIds.length) {
1138:                        throw new RuntimeException(
1139:                                "Cannot render to more than 32 Canvas3Ds");
1140:                    }
1141:
1142:                    canvasIds[i] = true;
1143:                    canvasFreeIndex = i + 1;
1144:                }
1145:
1146:                return i;
1147:
1148:            }
1149:
1150:            void freeCanvasId(int canvasId) {
1151:                // Valid range is [0, 31]
1152:                synchronized (canvasIdLock) {
1153:
1154:                    canvasIds[canvasId] = false;
1155:                    if (canvasFreeIndex > canvasId) {
1156:                        canvasFreeIndex = canvasId;
1157:                    }
1158:                }
1159:            }
1160:
1161:            /**
1162:             * Create a Renderer if it is not already done so.
1163:             * This is used for GraphicsConfigTemplate3D passing 
1164:             * graphics call to RequestRenderer, and for creating
1165:             * an off-screen buffer for an off-screen Canvas3D.
1166:             */
1167:            private Renderer createRenderer(GraphicsConfiguration gc) {
1168:                final GraphicsDevice gd = gc.getDevice();
1169:
1170:                Renderer rdr = (Renderer) Screen3D.deviceRendererMap.get(gd);
1171:                if (rdr != null) {
1172:                    return rdr;
1173:                }
1174:
1175:                java.security.AccessController
1176:                        .doPrivileged(new java.security.PrivilegedAction() {
1177:                            public Object run() {
1178:                                Renderer r;
1179:                                synchronized (rootThreadGroup) {
1180:                                    r = new Renderer(rootThreadGroup);
1181:                                    r.initialize();
1182:                                    r.setPriority(threadPriority);
1183:                                    Screen3D.deviceRendererMap.put(gd, r);
1184:                                }
1185:                                return null;
1186:                            }
1187:                        });
1188:
1189:                threadListsChanged = true;
1190:
1191:                return (Renderer) Screen3D.deviceRendererMap.get(gd);
1192:            }
1193:
1194:            /**
1195:             * Post the request in queue
1196:             */
1197:            void postRequest(Integer type, Object obj) {
1198:
1199:                synchronized (mcThreadLock) {
1200:                    synchronized (requestObjList) {
1201:                        if (mcThread == null) {
1202:                            if ((type == ACTIVATE_VIEW)
1203:                                    || (type == GETBESTCONFIG)
1204:                                    || (type == SET_VIEW)
1205:                                    || (type == ISCONFIGSUPPORT)
1206:                                    || (type == SET_QUERYPROPERTIES)
1207:                                    || (type == SET_GRAPHICSCONFIG_FEATURES)) {
1208:                                createMasterControlThread();
1209:                                requestObjList.add(obj);
1210:                                requestTypeList.add(type);
1211:                                pendingRequest = true;
1212:                            } else if (type == EMPTY_UNIVERSE) {
1213:                                destroyUniverseThreads((VirtualUniverse) obj);
1214:                            } else if (type == STOP_VIEW) {
1215:                                View v = (View) obj;
1216:                                v.stopViewCount = -1;
1217:                                v.isRunning = false;
1218:                            } else if (type == STOP_RENDERER) {
1219:                                if (obj instanceof  Canvas3D) {
1220:                                    ((Canvas3D) obj).isRunningStatus = false;
1221:                                } else {
1222:                                    ((Renderer) obj).userStop = true;
1223:                                }
1224:                            } else if (type == UNREGISTER_VIEW) {
1225:                                ((View) obj).doneUnregister = true;
1226:                            } else {
1227:                                requestObjList.add(obj);
1228:                                requestTypeList.add(type);
1229:                                pendingRequest = true;
1230:                            }
1231:                        } else {
1232:                            requestObjList.add(obj);
1233:                            requestTypeList.add(type);
1234:                            pendingRequest = true;
1235:                        }
1236:                    }
1237:                }
1238:
1239:                setWork();
1240:            }
1241:
1242:            /**
1243:             * This procedure is invoked when isRunning is false.  
1244:             * Return true when there is no more pending request so that 
1245:             * Thread can terminate. Otherwise we have to recreate
1246:             * the MC related threads.
1247:             */
1248:            boolean mcThreadDone() {
1249:                synchronized (mcThreadLock) {
1250:                    synchronized (requestObjList) {
1251:                        if (!pendingRequest) {
1252:                            mcThread = null;
1253:                            if (renderingAttributesStructure.updateThread != null) {
1254:                                renderingAttributesStructure.updateThread
1255:                                        .finish();
1256:                                renderingAttributesStructure.updateThread = null;
1257:                            }
1258:                            renderingAttributesStructure = new RenderingAttributesStructure();
1259:                            if (timerThread != null) {
1260:                                timerThread.finish();
1261:                                timerThread = null;
1262:                            }
1263:                            if (notificationThread != null) {
1264:                                notificationThread.finish();
1265:                                notificationThread = null;
1266:                            }
1267:                            requestObjList.clear();
1268:                            requestTypeList.clear();
1269:                            return true;
1270:                        }
1271:                        running = true;
1272:                        createMCThreads();
1273:                        return false;
1274:                    }
1275:                }
1276:            }
1277:
1278:            /**
1279:             * Returns whether we are using D3D.
1280:             * TODO: most code that cares about this should move into the pipeline
1281:             */
1282:            final boolean isD3D() {
1283:                return Pipeline.getPipeline().getPipelineType() == Pipeline.Type.NATIVE_D3D;
1284:            }
1285:
1286:            /**
1287:             * Returns whether we are running on Windows
1288:             * TODO: most code that cares about this should move into the pipeline
1289:             */
1290:            static final boolean isWindows() {
1291:                return isWindowsOs;
1292:            }
1293:
1294:            /**
1295:             * Returns a flag indicating whether the sun.jnlp.applet.launcher system
1296:             * property is set to true.
1297:             */
1298:            static boolean isAppletLauncher() {
1299:                return appletLauncher;
1300:            }
1301:
1302:            /**
1303:             * This method increments and returns the next time value
1304:             * timeLock must get before this procedure is invoked
1305:             */
1306:            final long getTime() {
1307:                return (time++);
1308:            }
1309:
1310:            /** 
1311:             * This takes a given message and parses it out to the structures and
1312:             * marks its time value.
1313:             */
1314:            void processMessage(J3dMessage message) {
1315:
1316:                synchronized (timeLock) {
1317:                    message.time = getTime();
1318:                    sendMessage(message);
1319:                }
1320:                setWork();
1321:            }
1322:
1323:            /** 
1324:             * This takes an array of messages and parses them out to the structures and
1325:             * marks the time value. Make sure, setWork() is done at the very end
1326:             * to make sure all the messages will be processed in the same frame
1327:             */
1328:            void processMessage(J3dMessage[] messages) {
1329:
1330:                synchronized (timeLock) {
1331:                    long time = getTime();
1332:
1333:                    for (int i = 0; i < messages.length; i++) {
1334:                        messages[i].time = time;
1335:                        sendMessage(messages[i]);
1336:                    }
1337:                }
1338:                setWork();
1339:            }
1340:
1341:            /**
1342:             * This takes the specified notification message and sends it to the
1343:             * notification thread for processing.
1344:             */
1345:            void sendNotification(J3dNotification notification) {
1346:                notificationThread.addNotification(notification);
1347:            }
1348:
1349:            /**
1350:             * Create and start the MasterControl Thread.
1351:             */
1352:            void createMasterControlThread() {
1353:                // Issue 364: don't create master control thread if already created
1354:                if (mcThread != null) {
1355:                    return;
1356:                }
1357:
1358:                running = true;
1359:                workToDo = true;
1360:                state = RUNNING;
1361:                java.security.AccessController
1362:                        .doPrivileged(new java.security.PrivilegedAction() {
1363:                            public Object run() {
1364:                                synchronized (rootThreadGroup) {
1365:                                    mcThread = new MasterControlThread(
1366:                                            rootThreadGroup);
1367:                                    mcThread.setPriority(threadPriority);
1368:                                }
1369:                                return null;
1370:                            }
1371:                        });
1372:            }
1373:
1374:            // assuming the timeLock is already acquired
1375:
1376:            /**
1377:             * Send a message to another Java 3D thread.
1378:             */
1379:            void sendMessage(J3dMessage message) {
1380:
1381:                synchronized (message) {
1382:                    VirtualUniverse u = message.universe;
1383:                    int targetThreads = message.threads;
1384:
1385:                    if (isCoreLoggable(Level.FINEST)) {
1386:                        dumpMessage("sendMessage", message);
1387:                    }
1388:
1389:                    if ((targetThreads & J3dThread.UPDATE_RENDERING_ATTRIBUTES) != 0) {
1390:                        renderingAttributesStructure.addMessage(message);
1391:                    }
1392:
1393:                    // GraphicsContext3D send message with universe = null
1394:                    if (u != null) {
1395:                        if ((targetThreads & J3dThread.UPDATE_GEOMETRY) != 0) {
1396:                            u.geometryStructure.addMessage(message);
1397:                        }
1398:                        if ((targetThreads & J3dThread.UPDATE_TRANSFORM) != 0) {
1399:                            u.transformStructure.addMessage(message);
1400:                        }
1401:                        if ((targetThreads & J3dThread.UPDATE_BEHAVIOR) != 0) {
1402:                            u.behaviorStructure.addMessage(message);
1403:                        }
1404:                        if ((targetThreads & J3dThread.UPDATE_SOUND) != 0) {
1405:                            u.soundStructure.addMessage(message);
1406:                        }
1407:                        if ((targetThreads & J3dThread.UPDATE_RENDERING_ENVIRONMENT) != 0) {
1408:                            u.renderingEnvironmentStructure.addMessage(message);
1409:                        }
1410:                    }
1411:
1412:                    if ((targetThreads & J3dThread.SOUND_SCHEDULER) != 0) {
1413:                        // Note that we don't check for active view
1414:                        if (message.view != null
1415:                                && message.view.soundScheduler != null) {
1416:                            // This make sure that message won't lost even
1417:                            // though this view not yet register
1418:                            message.view.soundScheduler.addMessage(message);
1419:                        } else {
1420:                            synchronized (views) {
1421:                                View v[] = (View[]) views.toArray(false);
1422:                                int i = views.arraySize() - 1;
1423:                                if (u == null) {
1424:                                    while (i >= 0) {
1425:                                        v[i--].soundScheduler
1426:                                                .addMessage(message);
1427:                                    }
1428:                                } else {
1429:                                    while (i >= 0) {
1430:                                        if (v[i].universe == u) {
1431:                                            v[i].soundScheduler
1432:                                                    .addMessage(message);
1433:                                        }
1434:                                        i--;
1435:                                    }
1436:                                }
1437:                            }
1438:                        }
1439:                    }
1440:
1441:                    if ((targetThreads & J3dThread.UPDATE_RENDER) != 0) {
1442:                        // Note that we don't check for active view
1443:                        if (message.view != null
1444:                                && message.view.renderBin != null) {
1445:                            // This make sure that message won't lost even
1446:                            // though this view not yet register
1447:                            message.view.renderBin.addMessage(message);
1448:                        } else {
1449:                            synchronized (views) {
1450:                                View v[] = (View[]) views.toArray(false);
1451:                                int i = views.arraySize() - 1;
1452:                                if (u == null) {
1453:                                    while (i >= 0) {
1454:                                        v[i--].renderBin.addMessage(message);
1455:                                    }
1456:                                } else {
1457:                                    while (i >= 0) {
1458:                                        if (v[i].universe == u) {
1459:                                            v[i].renderBin.addMessage(message);
1460:                                        }
1461:                                        i--;
1462:                                    }
1463:                                }
1464:                            }
1465:                        }
1466:                    }
1467:
1468:                    if (message.getRefcount() == 0) {
1469:                        message.clear();
1470:                    }
1471:                }
1472:            }
1473:
1474:            /**
1475:             * Send a message to another Java 3D thread.
1476:             * This variant is only call by TimerThread for Input Device Scheduler
1477:             * or to redraw all View for RenderThread
1478:             */
1479:            void sendRunMessage(int targetThreads) {
1480:
1481:                synchronized (timeLock) {
1482:
1483:                    long time = getTime();
1484:
1485:                    if ((targetThreads & J3dThread.INPUT_DEVICE_SCHEDULER) != 0) {
1486:                        synchronized (inputDeviceThreads) {
1487:                            InputDeviceScheduler ds[] = (InputDeviceScheduler[]) inputDeviceThreads
1488:                                    .toArray(false);
1489:                            for (int i = inputDeviceThreads.size() - 1; i >= 0; i--) {
1490:                                if (ds[i].physicalEnv.activeViewRef > 0) {
1491:                                    ds[i].getThreadData().lastUpdateTime = time;
1492:                                }
1493:                            }
1494:
1495:                            // timerThread instance in MC will set to null in
1496:                            // destroyUniverseThreads() so we need to check if
1497:                            // TimerThread kick in to sendRunMessage() after that.
1498:                            // It happens because TimerThread is the only thread run
1499:                            // asychronizously with MasterControl thread. 
1500:
1501:                            if (timerThread != null) {
1502:                                // Notify TimerThread to wakeup this procedure 
1503:                                // again next time. 
1504:                                timerThread.addInputDeviceSchedCond();
1505:                            }
1506:                        }
1507:                    }
1508:                    if ((targetThreads & J3dThread.RENDER_THREAD) != 0) {
1509:                        synchronized (renderThreadData) {
1510:                            J3dThreadData[] threads = (J3dThreadData[]) renderThreadData
1511:                                    .toArray(false);
1512:                            int i = renderThreadData.arraySize() - 1;
1513:                            J3dThreadData thr;
1514:                            while (i >= 0) {
1515:                                thr = threads[i--];
1516:                                if (thr.view.renderBinReady) {
1517:                                    thr.lastUpdateTime = time;
1518:                                }
1519:                            }
1520:                        }
1521:                    }
1522:                }
1523:                setWork();
1524:            }
1525:
1526:            /**
1527:             * Send a message to another Java 3D thread.
1528:             * This variant is only call by TimerThread for Sound Scheduler
1529:             */
1530:            void sendRunMessage(long waitTime, View view, int targetThreads) {
1531:
1532:                synchronized (timeLock) {
1533:
1534:                    long time = getTime();
1535:
1536:                    if ((targetThreads & J3dThread.SOUND_SCHEDULER) != 0) {
1537:                        if (view.soundScheduler != null) {
1538:                            view.soundScheduler.threadData.lastUpdateTime = time;
1539:                        }
1540:                        // wakeup this procedure next time
1541:                        // QUESTION: waitTime calculated some milliseconds BEFORE
1542:                        //     this methods getTime() called - shouldn't actual 
1543:                        //     sound Complete time be passed by SoundScheduler
1544:                        // QUESTION: will this wake up only soundScheduler associated
1545:                        //     with this view?? (since only it's lastUpdateTime is set)
1546:                        //     or all soundSchedulers??
1547:                        timerThread.addSoundSchedCond(time + waitTime);
1548:                    }
1549:                }
1550:                setWork();
1551:            }
1552:
1553:            /**
1554:             * Send a message to another Java 3D thread.
1555:             * This variant is only called to update Render Thread
1556:             */
1557:            void sendRunMessage(View v, int targetThreads) {
1558:
1559:                synchronized (timeLock) {
1560:                    long time = getTime();
1561:
1562:                    if ((targetThreads & J3dThread.RENDER_THREAD) != 0) {
1563:                        synchronized (renderThreadData) {
1564:                            J3dThreadData[] threads = (J3dThreadData[]) renderThreadData
1565:                                    .toArray(false);
1566:                            int i = renderThreadData.arraySize() - 1;
1567:                            J3dThreadData thr;
1568:                            while (i >= 0) {
1569:                                thr = threads[i--];
1570:                                if (thr.view == v && v.renderBinReady) {
1571:                                    thr.lastUpdateTime = time;
1572:                                }
1573:                            }
1574:                        }
1575:                    }
1576:                }
1577:                setWork();
1578:            }
1579:
1580:            /**
1581:             * This sends a run message to the given threads.
1582:             */
1583:            void sendRunMessage(VirtualUniverse u, int targetThreads) {
1584:                // We don't sendRunMessage to update structure except Behavior
1585:
1586:                synchronized (timeLock) {
1587:                    long time = getTime();
1588:
1589:                    if ((targetThreads & J3dThread.BEHAVIOR_SCHEDULER) != 0) {
1590:                        if (u.behaviorScheduler != null) {
1591:                            u.behaviorScheduler.getThreadData(null, null).lastUpdateTime = time;
1592:                        }
1593:                    }
1594:
1595:                    if ((targetThreads & J3dThread.UPDATE_BEHAVIOR) != 0) {
1596:                        u.behaviorStructure.threadData.lastUpdateTime = time;
1597:                    }
1598:
1599:                    if ((targetThreads & J3dThread.UPDATE_GEOMETRY) != 0) {
1600:                        u.geometryStructure.threadData.lastUpdateTime = time;
1601:                    }
1602:
1603:                    if ((targetThreads & J3dThread.UPDATE_SOUND) != 0) {
1604:                        u.soundStructure.threadData.lastUpdateTime = time;
1605:                    }
1606:
1607:                    if ((targetThreads & J3dThread.SOUND_SCHEDULER) != 0) {
1608:                        synchronized (views) {
1609:                            View v[] = (View[]) views.toArray(false);
1610:                            for (int i = views.arraySize() - 1; i >= 0; i--) {
1611:                                if ((v[i].soundScheduler != null)
1612:                                        && (v[i].universe == u)) {
1613:                                    v[i].soundScheduler.threadData.lastUpdateTime = time;
1614:                                }
1615:                            }
1616:                        }
1617:                    }
1618:
1619:                    if ((targetThreads & J3dThread.RENDER_THREAD) != 0) {
1620:
1621:                        synchronized (renderThreadData) {
1622:                            J3dThreadData[] threads = (J3dThreadData[]) renderThreadData
1623:                                    .toArray(false);
1624:                            int i = renderThreadData.arraySize() - 1;
1625:                            J3dThreadData thr;
1626:                            while (i >= 0) {
1627:                                thr = threads[i--];
1628:                                if (thr.view.universe == u
1629:                                        && thr.view.renderBinReady) {
1630:                                    thr.lastUpdateTime = time;
1631:                                }
1632:                            }
1633:                        }
1634:                    }
1635:                }
1636:
1637:                setWork();
1638:            }
1639:
1640:            /**
1641:             * Return a clone of View, we can't access 
1642:             * individual element of View after getting the size
1643:             * in separate API call without synchronized views.
1644:             */
1645:            UnorderList cloneView() {
1646:                return (UnorderList) views.clone();
1647:            }
1648:
1649:            /**
1650:             * Return true if view is already registered with MC
1651:             */
1652:            boolean isRegistered(View view) {
1653:                return views.contains(view);
1654:            }
1655:
1656:            /**
1657:             * This snapshots the time values to be used for this iteration.
1658:             * Note that this method is called without the timeLock held.
1659:             * We must synchronize on timeLock to prevent updating
1660:             * thread.lastUpdateTime from user thread in sendMessage()
1661:             * or sendRunMessage().
1662:             */
1663:            private void updateTimeValues() {
1664:                synchronized (timeLock) {
1665:                    int i = 0;
1666:                    J3dThreadData lastThread = null;
1667:                    J3dThreadData thread = null;
1668:                    long lastTime = currentTime;
1669:
1670:                    currentTime = getTime();
1671:
1672:                    J3dThreadData threads[] = (J3dThreadData[]) stateWorkThreads
1673:                            .toArray(false);
1674:                    int size = stateWorkThreads.arraySize();
1675:
1676:                    while (i < lastTransformStructureThread) {
1677:                        thread = threads[i++];
1678:
1679:                        if ((thread.lastUpdateTime > thread.lastRunTime)
1680:                                && !thread.thread.userStop) {
1681:                            lastThread = thread;
1682:                            thread.needsRun = true;
1683:                            thread.threadOpts = J3dThreadData.CONT_THREAD;
1684:                            thread.lastRunTime = currentTime;
1685:                        } else {
1686:                            thread.needsRun = false;
1687:                        }
1688:                    }
1689:
1690:                    if (lastThread != null) {
1691:                        lastThread.threadOpts = J3dThreadData.WAIT_ALL_THREADS;
1692:                        lastThread = null;
1693:                    }
1694:
1695:                    while (i < lastStructureUpdateThread) {
1696:                        thread = threads[i++];
1697:                        if ((thread.lastUpdateTime > thread.lastRunTime)
1698:                                && !thread.thread.userStop) {
1699:                            lastThread = thread;
1700:                            thread.needsRun = true;
1701:                            thread.threadOpts = J3dThreadData.CONT_THREAD;
1702:                            thread.lastRunTime = currentTime;
1703:                        } else {
1704:                            thread.needsRun = false;
1705:                        }
1706:                    }
1707:                    if (lastThread != null) {
1708:                        lastThread.threadOpts = J3dThreadData.WAIT_ALL_THREADS;
1709:                        lastThread = null;
1710:                    }
1711:
1712:                    while (i < size) {
1713:                        thread = threads[i++];
1714:                        if ((thread.lastUpdateTime > thread.lastRunTime)
1715:                                && !thread.thread.userStop) {
1716:                            lastThread = thread;
1717:                            thread.needsRun = true;
1718:                            thread.threadOpts = J3dThreadData.CONT_THREAD;
1719:                            thread.lastRunTime = currentTime;
1720:                        } else {
1721:                            thread.needsRun = false;
1722:                        }
1723:                    }
1724:                    if (lastThread != null) {
1725:                        lastThread.threadOpts = J3dThreadData.WAIT_ALL_THREADS;
1726:                        lastThread = null;
1727:                    }
1728:
1729:                    threads = (J3dThreadData[]) renderWorkThreads
1730:                            .toArray(false);
1731:                    size = renderWorkThreads.arraySize();
1732:                    View v;
1733:                    J3dThreadData lastRunThread = null;
1734:                    waitTimestamp++;
1735:                    sleepTime = 0L;
1736:
1737:                    boolean threadToRun = false; // Not currently used
1738:
1739:                    // Fix for Issue 12: loop through the list of threads, calling
1740:                    // computeCycleTime() exactly once per view. This ensures that
1741:                    // all threads for a given view see consistent values for
1742:                    // isMinCycleTimeAchieve and sleepTime.
1743:                    v = null;
1744:                    for (i = 0; i < size; i++) {
1745:                        thread = threads[i];
1746:                        if (thread.view != v) {
1747:                            thread.view.computeCycleTime();
1748:                            // Set sleepTime to the value needed to satify the
1749:                            // minimum cycle time of the slowest view
1750:                            if (thread.view.sleepTime > sleepTime) {
1751:                                sleepTime = thread.view.sleepTime;
1752:                            }
1753:                        }
1754:                        v = thread.view;
1755:                    }
1756:
1757:                    v = null;
1758:                    for (i = 0; i < size; i++) {
1759:                        thread = threads[i];
1760:                        if (thread.canvas == null) { // Only for swap thread
1761:                            ((Object[]) thread.threadArgs)[3] = null;
1762:                        }
1763:                        if ((thread.lastUpdateTime > thread.lastRunTime)
1764:                                && !thread.thread.userStop) {
1765:
1766:                            if (thread.thread.lastWaitTimestamp == waitTimestamp) {
1767:                                // This renderer thread is repeated. We must wait 
1768:                                // until all previous renderer threads done before
1769:                                // allowing this thread to continue. Note that
1770:                                // lastRunThread can't be null in this case.
1771:                                waitTimestamp++;
1772:                                if (thread.view != v) {
1773:                                    // A new View is start
1774:                                    v = thread.view;
1775:                                    threadToRun = true;
1776:                                    lastRunThread.threadOpts = (J3dThreadData.STOP_TIMER | J3dThreadData.WAIT_ALL_THREADS);
1777:                                    ((Object[]) lastRunThread.threadArgs)[3] = lastRunThread.view;
1778:                                    thread.threadOpts = (J3dThreadData.START_TIMER | J3dThreadData.CONT_THREAD);
1779:                                } else {
1780:                                    if ((lastRunThread.threadOpts & J3dThreadData.START_TIMER) != 0) {
1781:                                        lastRunThread.threadOpts = (J3dThreadData.START_TIMER | J3dThreadData.WAIT_ALL_THREADS);
1782:
1783:                                    } else {
1784:                                        lastRunThread.threadOpts = J3dThreadData.WAIT_ALL_THREADS;
1785:                                    }
1786:                                    thread.threadOpts = J3dThreadData.CONT_THREAD;
1787:
1788:                                }
1789:                            } else {
1790:                                if (thread.view != v) {
1791:                                    v = thread.view;
1792:                                    threadToRun = true;
1793:                                    // Although the renderer thread is not
1794:                                    // repeated. We still need to wait all
1795:                                    // previous renderer threads if new View
1796:                                    // start.
1797:                                    if (lastRunThread != null) {
1798:                                        lastRunThread.threadOpts = (J3dThreadData.STOP_TIMER | J3dThreadData.WAIT_ALL_THREADS);
1799:                                        ((Object[]) lastRunThread.threadArgs)[3] = lastRunThread.view;
1800:                                    }
1801:                                    thread.threadOpts = (J3dThreadData.START_TIMER | J3dThreadData.CONT_THREAD);
1802:                                } else {
1803:                                    thread.threadOpts = J3dThreadData.CONT_THREAD;
1804:                                }
1805:                            }
1806:                            thread.thread.lastWaitTimestamp = waitTimestamp;
1807:                            thread.needsRun = true;
1808:                            thread.lastRunTime = currentTime;
1809:                            lastRunThread = thread;
1810:                        } else {
1811:                            thread.needsRun = false;
1812:                        }
1813:                    }
1814:
1815:                    if (lastRunThread != null) {
1816:                        lastRunThread.threadOpts = (J3dThreadData.STOP_TIMER
1817:                                | J3dThreadData.WAIT_ALL_THREADS | J3dThreadData.LAST_STOP_TIMER);
1818:                        lockGeometry = true;
1819:                        ((Object[]) lastRunThread.threadArgs)[3] = lastRunThread.view;
1820:                    } else {
1821:                        lockGeometry = false;
1822:                    }
1823:                }
1824:
1825:                // Issue 275 - go to sleep without holding timeLock
1826:                // Sleep for the amount of time needed to satisfy the minimum
1827:                // cycle time for all views.
1828:                if (sleepTime > 0) {
1829:                    // System.err.println("MasterControl: sleep(" + sleepTime + ")");
1830:                    try {
1831:                        Thread.sleep(sleepTime);
1832:                    } catch (InterruptedException e) {
1833:                        System.err.println(e);
1834:                    }
1835:                    // System.err.println("MasterControl: done sleeping");
1836:                }
1837:            }
1838:
1839:            private void createUpdateThread(J3dStructure structure) {
1840:                final J3dStructure s = structure;
1841:
1842:                if (s.updateThread == null) {
1843:                    java.security.AccessController
1844:                            .doPrivileged(new java.security.PrivilegedAction() {
1845:                                public Object run() {
1846:                                    synchronized (rootThreadGroup) {
1847:                                        s.updateThread = new StructureUpdateThread(
1848:                                                rootThreadGroup, s,
1849:                                                s.threadType);
1850:                                        s.updateThread
1851:                                                .setPriority(threadPriority);
1852:                                    }
1853:                                    return null;
1854:                                }
1855:                            });
1856:                    s.updateThread.initialize();
1857:                    s.threadData.thread = s.updateThread;
1858:                    // This takes into accout for thread that just destroy and
1859:                    // create again. In this case the threadData may receive
1860:                    // message before the thread actually created. We don't want 
1861:                    // the currentTime to overwrite the update time of which
1862:                    // is set by threadData when get message.
1863:                    s.threadData.lastUpdateTime = Math.max(currentTime,
1864:                            s.threadData.lastUpdateTime);
1865:                }
1866:            }
1867:
1868:            private void emptyMessageList(J3dStructure structure, View v) {
1869:                if (structure != null) {
1870:                    if (v == null) {
1871:                        if (structure.threadData != null) {
1872:                            structure.threadData.thread = null;
1873:                        }
1874:
1875:                        if (structure.updateThread != null) {
1876:                            structure.updateThread.structure = null;
1877:                        }
1878:                        structure.updateThread = null;
1879:                    }
1880:                    boolean otherViewExist = false;
1881:                    if ((v != null) && (v.universe != null)) {
1882:                        // Check if there is any other View register with the
1883:                        // same universe
1884:                        for (int i = views.size() - 1; i >= 0; i--) {
1885:                            if (((View) views.get(i)).universe == v.universe) {
1886:                                otherViewExist = true;
1887:                                break;
1888:                            }
1889:                        }
1890:                    }
1891:
1892:                    UnorderList mlist = structure.messageList;
1893:                    // Note that message is add at the end of array
1894:                    synchronized (mlist) {
1895:                        int size = mlist.size();
1896:                        if (size > 0) {
1897:                            J3dMessage mess[] = (J3dMessage[]) mlist
1898:                                    .toArray(false);
1899:                            J3dMessage m;
1900:                            int i = 0;
1901:
1902:                            Object oldRef = null;
1903:                            while (i < size) {
1904:                                m = mess[i];
1905:                                if ((v == null)
1906:                                        || (m.view == v)
1907:                                        || ((m.view == null) && !otherViewExist)) {
1908:                                    if (m.type == J3dMessage.INSERT_NODES) {
1909:                                        // There is another View register request
1910:                                        // immediately following, so no need 
1911:                                        // to remove message.
1912:                                        break;
1913:                                    }
1914:                                    // Some other thread may still using this
1915:                                    // message so we should not directly
1916:                                    // add this message to free lists
1917:                                    m.decRefcount();
1918:                                    mlist.removeOrdered(i);
1919:                                    size--;
1920:                                } else {
1921:                                    i++;
1922:                                }
1923:                            }
1924:                        }
1925:                    }
1926:                }
1927:            }
1928:
1929:            private void destroyUpdateThread(J3dStructure structure) {
1930:                // If unregisterView message got before EMPTY_UNIVERSE
1931:                // message, then updateThread is already set to null.
1932:                if (structure.updateThread != null) {
1933:                    structure.updateThread.finish();
1934:                    structure.updateThread.structure = null;
1935:                    structure.updateThread = null;
1936:                }
1937:                structure.threadData.thread = null;
1938:                structure.clearMessages();
1939:            }
1940:
1941:            /**
1942:             * This register a View with MasterControl.  
1943:             * The View has at least one Canvas3D added to a container.
1944:             */
1945:            private void registerView(View v) {
1946:                final VirtualUniverse univ = v.universe;
1947:
1948:                if (views.contains(v) && regUniverseList.contains(univ)) {
1949:                    return; // already register
1950:                }
1951:
1952:                if (timerThread == null) {
1953:                    // This handle the case when MC shutdown and restart in
1954:                    // a series of pending request
1955:                    running = true;
1956:                    createMCThreads();
1957:                }
1958:                // If viewId is null, assign one ..
1959:                v.assignViewId();
1960:
1961:                // Create thread if not done before
1962:                createUpdateThread(univ.behaviorStructure);
1963:                createUpdateThread(univ.geometryStructure);
1964:                createUpdateThread(univ.soundStructure);
1965:                createUpdateThread(univ.renderingEnvironmentStructure);
1966:                createUpdateThread(univ.transformStructure);
1967:
1968:                // create Behavior scheduler
1969:                J3dThreadData threadData = null;
1970:
1971:                if (univ.behaviorScheduler == null) {
1972:                    java.security.AccessController
1973:                            .doPrivileged(new java.security.PrivilegedAction() {
1974:                                public Object run() {
1975:                                    synchronized (rootThreadGroup) {
1976:                                        univ.behaviorScheduler = new BehaviorScheduler(
1977:                                                rootThreadGroup, univ);
1978:                                        univ.behaviorScheduler
1979:                                                .setPriority(threadPriority);
1980:                                    }
1981:                                    return null;
1982:                                }
1983:                            });
1984:                    univ.behaviorScheduler.initialize();
1985:                    univ.behaviorScheduler.userStop = v.stopBehavior;
1986:                    threadData = univ.behaviorScheduler.getThreadData(null,
1987:                            null);
1988:                    threadData.thread = univ.behaviorScheduler;
1989:                    threadData.threadType = J3dThread.BEHAVIOR_SCHEDULER;
1990:                    threadData.lastUpdateTime = Math.max(currentTime,
1991:                            threadData.lastUpdateTime);
1992:                }
1993:
1994:                createUpdateThread(v.renderBin);
1995:                createUpdateThread(v.soundScheduler);
1996:
1997:                if (v.physicalEnvironment != null) {
1998:                    v.physicalEnvironment.addUser(v);
1999:                }
2000:                // create InputDeviceScheduler
2001:                evaluatePhysicalEnv(v);
2002:
2003:                regUniverseList.addUnique(univ);
2004:                views.addUnique(v);
2005:            }
2006:
2007:            /**
2008:             * This unregister a View with MasterControl.  
2009:             * The View no longer has any Canvas3Ds in a container.
2010:             */
2011:            private void unregisterView(View v) {
2012:
2013:                if (!views.remove(v)) {
2014:                    v.active = false;
2015:                    v.doneUnregister = true;
2016:                    return; // already unregister
2017:                }
2018:
2019:                if (v.active) {
2020:                    viewDeactivate(v);
2021:                }
2022:
2023:                if (J3dDebug.devPhase) {
2024:                    J3dDebug
2025:                            .doDebug(J3dDebug.masterControl, J3dDebug.LEVEL_1,
2026:                                    "MC: Destroy Sound Scheduler and RenderBin Update thread");
2027:                }
2028:
2029:                v.soundScheduler.updateThread.finish();
2030:                v.renderBin.updateThread.finish();
2031:                v.soundScheduler.updateThread = null;
2032:                v.renderBin.updateThread = null;
2033:
2034:                // remove VirtualUniverse related threads if Universe
2035:                // is empty
2036:                VirtualUniverse univ = v.universe;
2037:                int i;
2038:
2039:                synchronized (timeLock) {
2040:                    // The reason we need to sync. with timeLock is because we
2041:                    // don't want user thread running sendMessage() to 
2042:                    // dispatch it in different structure queue when
2043:                    // part of the structure list is empty at the same time.
2044:                    // This will cause inconsistence in the message reference
2045:                    // count.
2046:                    emptyMessageList(v.soundScheduler, v);
2047:                    emptyMessageList(v.renderBin, v);
2048:
2049:                    if (univ.isEmpty()) {
2050:                        destroyUniverseThreads(univ);
2051:                    } else {
2052:                        emptyMessageList(univ.behaviorStructure, v);
2053:                        emptyMessageList(univ.geometryStructure, v);
2054:                        emptyMessageList(univ.soundStructure, v);
2055:                        emptyMessageList(univ.renderingEnvironmentStructure, v);
2056:                        emptyMessageList(univ.transformStructure, v);
2057:                    }
2058:                }
2059:
2060:                if (v.physicalEnvironment != null) {
2061:                    v.physicalEnvironment.removeUser(v);
2062:                }
2063:
2064:                // remove all InputDeviceScheduler if this is the last View
2065:                UnorderList list = new UnorderList(1, PhysicalEnvironment.class);
2066:                for (Enumeration e = PhysicalEnvironment.physicalEnvMap.keys(); e
2067:                        .hasMoreElements();) {
2068:                    PhysicalEnvironment phyEnv = (PhysicalEnvironment) e
2069:                            .nextElement();
2070:                    InputDeviceScheduler sched = (InputDeviceScheduler) PhysicalEnvironment.physicalEnvMap
2071:                            .get(phyEnv);
2072:                    for (i = phyEnv.users.size() - 1; i >= 0; i--) {
2073:                        if (views.contains((View) phyEnv.users.get(i))) {
2074:                            // at least one register view refer to it.
2075:                            break;
2076:                        }
2077:                    }
2078:                    if (i < 0) {
2079:                        if (J3dDebug.devPhase) {
2080:                            J3dDebug.doDebug(J3dDebug.masterControl,
2081:                                    J3dDebug.LEVEL_1,
2082:                                    "MC: Destroy InputDeviceScheduler thread "
2083:                                            + sched);
2084:                        }
2085:                        sched.finish();
2086:                        phyEnv.inputsched = null;
2087:                        list.add(phyEnv);
2088:                    }
2089:                }
2090:                for (i = list.size() - 1; i >= 0; i--) {
2091:                    PhysicalEnvironment.physicalEnvMap.remove(list.get(i));
2092:                }
2093:
2094:                freeContext(v);
2095:
2096:                if (views.isEmpty()) {
2097:                    if (J3dDebug.devPhase) {
2098:                        J3dDebug.doDebug(J3dDebug.masterControl,
2099:                                J3dDebug.LEVEL_1, "MC: Destroy all Renderers");
2100:                    }
2101:                    // remove all Renderers if this is the last View
2102:                    for (Enumeration e = Screen3D.deviceRendererMap.elements(); e
2103:                            .hasMoreElements();) {
2104:                        Renderer rdr = (Renderer) e.nextElement();
2105:                        Screen3D scr;
2106:
2107:                        rendererCleanupArgs[2] = REMOVEALLCTXS_CLEANUP;
2108:                        runMonitor(RUN_RENDERER_CLEANUP, null, null, null, rdr);
2109:                        scr = rdr.onScreen;
2110:                        if (scr != null) {
2111:                            if (scr.renderer != null) {
2112:                                rendererCleanupArgs[2] = REMOVEALLCTXS_CLEANUP;
2113:                                runMonitor(RUN_RENDERER_CLEANUP, null, null,
2114:                                        null, scr.renderer);
2115:                                scr.renderer = null;
2116:                            }
2117:
2118:                        }
2119:                        scr = rdr.offScreen;
2120:                        if (scr != null) {
2121:                            if (scr.renderer != null) {
2122:                                rendererCleanupArgs[2] = REMOVEALLCTXS_CLEANUP;
2123:                                runMonitor(RUN_RENDERER_CLEANUP, null, null,
2124:                                        null, scr.renderer);
2125:                                scr.renderer = null;
2126:                            }
2127:                        }
2128:                        rdr.onScreen = null;
2129:                        rdr.offScreen = null;
2130:                    }
2131:
2132:                    // cleanup ThreadData corresponds to the view in renderer
2133:                    for (Enumeration e = Screen3D.deviceRendererMap.elements(); e
2134:                            .hasMoreElements();) {
2135:                        Renderer rdr = (Renderer) e.nextElement();
2136:                        rdr.cleanup();
2137:                    }
2138:                    // We have to reuse renderer even though MC exit
2139:                    // see bug 4363279
2140:                    //  Screen3D.deviceRendererMap.clear();
2141:
2142:                } else {
2143:                    // cleanup ThreadData corresponds to the view in renderer
2144:                    for (Enumeration e = Screen3D.deviceRendererMap.elements(); e
2145:                            .hasMoreElements();) {
2146:                        Renderer rdr = (Renderer) e.nextElement();
2147:                        rdr.cleanupView();
2148:                    }
2149:                }
2150:
2151:                freeMessageList.add(univ);
2152:                freeMessageList.add(v);
2153:
2154:                evaluateAllCanvases();
2155:                stateWorkThreads.clear();
2156:                renderWorkThreads.clear();
2157:                requestRenderWorkThreads.clear();
2158:                threadListsChanged = true;
2159:
2160:                // This notify VirtualUniverse waitForMC() thread to continue
2161:                v.doneUnregister = true;
2162:            }
2163:
2164:            /**
2165:             * This procedure create MC thread that start together with MC.
2166:             */
2167:            void createMCThreads() {
2168:
2169:                // There is only one renderingAttributesUpdate Thread globally
2170:                createUpdateThread(renderingAttributesStructure);
2171:
2172:                // Create timer thread
2173:                java.security.AccessController
2174:                        .doPrivileged(new java.security.PrivilegedAction() {
2175:                            public Object run() {
2176:                                synchronized (rootThreadGroup) {
2177:                                    timerThread = new TimerThread(
2178:                                            rootThreadGroup);
2179:                                    timerThread.setPriority(threadPriority);
2180:                                }
2181:                                return null;
2182:                            }
2183:                        });
2184:                timerThread.start();
2185:
2186:                // Create notification thread
2187:                java.security.AccessController
2188:                        .doPrivileged(new java.security.PrivilegedAction() {
2189:                            public Object run() {
2190:                                synchronized (rootThreadGroup) {
2191:                                    notificationThread = new NotificationThread(
2192:                                            rootThreadGroup);
2193:                                    notificationThread
2194:                                            .setPriority(threadPriority);
2195:                                }
2196:                                return null;
2197:                            }
2198:                        });
2199:                notificationThread.start();
2200:            }
2201:
2202:            /**
2203:             * Destroy all VirtualUniverse related threads.
2204:             * This procedure may call two times when Locale detach in a
2205:             * live viewPlatform.
2206:             */
2207:            private void destroyUniverseThreads(VirtualUniverse univ) {
2208:
2209:                if (regUniverseList.contains(univ)) {
2210:                    if (J3dDebug.devPhase) {
2211:                        J3dDebug.doDebug(J3dDebug.masterControl,
2212:                                J3dDebug.LEVEL_1,
2213:                                "MC: Destroy universe threads " + univ);
2214:                    }
2215:                    destroyUpdateThread(univ.behaviorStructure);
2216:                    destroyUpdateThread(univ.geometryStructure);
2217:                    destroyUpdateThread(univ.soundStructure);
2218:                    destroyUpdateThread(univ.renderingEnvironmentStructure);
2219:                    destroyUpdateThread(univ.transformStructure);
2220:                    univ.behaviorScheduler.finish();
2221:                    univ.behaviorScheduler.free();
2222:                    univ.behaviorScheduler = null;
2223:                    univ.initMCStructure();
2224:                    activeUniverseList.remove(univ);
2225:                    regUniverseList.remove(univ);
2226:                } else {
2227:                    emptyMessageList(univ.behaviorStructure, null);
2228:                    emptyMessageList(univ.geometryStructure, null);
2229:                    emptyMessageList(univ.soundStructure, null);
2230:                    emptyMessageList(univ.renderingEnvironmentStructure, null);
2231:                    emptyMessageList(univ.transformStructure, null);
2232:                }
2233:
2234:                if (regUniverseList.isEmpty() && views.isEmpty()) {
2235:                    if (J3dDebug.devPhase) {
2236:                        J3dDebug
2237:                                .doDebug(J3dDebug.masterControl,
2238:                                        J3dDebug.LEVEL_1,
2239:                                        "MC: Destroy RenderingAttributes Update and Timer threads");
2240:                    }
2241:                    if (renderingAttributesStructure.updateThread != null) {
2242:                        renderingAttributesStructure.updateThread.finish();
2243:                        renderingAttributesStructure.updateThread = null;
2244:                    }
2245:                    renderingAttributesStructure.messageList.clear();
2246:                    renderingAttributesStructure.objList = new ArrayList();
2247:                    renderingAttributesStructure = new RenderingAttributesStructure();
2248:                    if (timerThread != null) {
2249:                        timerThread.finish();
2250:                        timerThread = null;
2251:                    }
2252:                    if (notificationThread != null) {
2253:                        notificationThread.finish();
2254:                        notificationThread = null;
2255:                    }
2256:
2257:                    // shouldn't all of these be synchronized ???
2258:                    synchronized (VirtualUniverse.mc.deviceScreenMap) {
2259:                        deviceScreenMap.clear();
2260:                    }
2261:
2262:                    mirrorObjects.clear();
2263:                    // Note: We should not clear the DISPLAYLIST/TEXTURE
2264:                    // list here because other structure may release them
2265:                    // later 
2266:
2267:                    for (int i = 0; i < canvasIds.length; i++) {
2268:                        canvasIds[i] = false;
2269:                    }
2270:                    canvasFreeIndex = 0;
2271:
2272:                    renderOnceList.clear();
2273:                    timestampUpdateList.clear();
2274:
2275:                    defaultRenderMethod = null;
2276:                    text3DRenderMethod = null;
2277:                    vertexArrayRenderMethod = null;
2278:                    displayListRenderMethod = null;
2279:                    compressedGeometryRenderMethod = null;
2280:                    orientedShape3DRenderMethod = null;
2281:                    // Terminate MC thread
2282:                    running = false;
2283:                }
2284:            }
2285:
2286:            /**
2287:             * Note that we have to go through all views instead of
2288:             * evaluate only the canvas in a single view since each screen
2289:             * may share by multiple view
2290:             */
2291:            private void evaluateAllCanvases() {
2292:
2293:                synchronized (renderThreadData) {
2294:                    // synchronized to prevent lost message when
2295:                    // renderThreadData is clear
2296:
2297:                    // First remove all renderrenderThreadData
2298:                    renderThreadData.clear();
2299:
2300:                    // Second reset canvasCount to zero
2301:                    View viewArr[] = (View[]) views.toArray(false);
2302:                    for (int i = views.size() - 1; i >= 0; i--) {
2303:                        viewArr[i].getCanvasList(true); // force canvas cache update
2304:                        Screen3D screens[] = viewArr[i].getScreens();
2305:                        for (int j = screens.length - 1; j >= 0; j--) {
2306:                            screens[j].canvasCount = 0;
2307:                        }
2308:                    }
2309:
2310:                    // Third create render thread and message thread
2311:                    for (int i = views.size() - 1; i >= 0; i--) {
2312:                        View v = viewArr[i];
2313:                        Canvas3D canvasList[][] = v.getCanvasList(false);
2314:                        if (!v.active) {
2315:                            continue;
2316:                        }
2317:
2318:                        for (int j = canvasList.length - 1; j >= 0; j--) {
2319:                            boolean added = false;
2320:
2321:                            for (int k = canvasList[j].length - 1; k >= 0; k--) {
2322:                                Canvas3D cv = canvasList[j][k];
2323:
2324:                                final Screen3D screen = cv.screen;
2325:
2326:                                if (cv.active) {
2327:                                    if (screen.canvasCount++ == 0) {
2328:                                        // Create Renderer, one per screen
2329:                                        if (screen.renderer == null) {
2330:                                            // get the renderer created for the graphics 
2331:                                            // device of the screen of the canvas
2332:                                            // No need to synchronized since only
2333:                                            // MC use it. 
2334:                                            Renderer rdr = (Renderer) screen.deviceRendererMap
2335:                                                    .get(cv.screen.graphicsDevice);
2336:                                            if (rdr == null) {
2337:                                                java.security.AccessController
2338:                                                        .doPrivileged(new java.security.PrivilegedAction() {
2339:                                                            public Object run() {
2340:
2341:                                                                synchronized (rootThreadGroup) {
2342:                                                                    screen.renderer = new Renderer(
2343:                                                                            rootThreadGroup);
2344:                                                                    screen.renderer
2345:                                                                            .setPriority(threadPriority);
2346:                                                                }
2347:                                                                return null;
2348:                                                            }
2349:                                                        });
2350:                                                screen.renderer.initialize();
2351:                                                screen.deviceRendererMap.put(
2352:                                                        screen.graphicsDevice,
2353:                                                        screen.renderer);
2354:                                            } else {
2355:                                                screen.renderer = rdr;
2356:                                            }
2357:                                        }
2358:                                    }
2359:                                    // offScreen canvases will be handled by the
2360:                                    // request renderer, so don't add offScreen canvas
2361:                                    // the render list
2362:                                    //
2363:                                    // Issue 131: Automatic offscreen canvases need to
2364:                                    // be added to onscreen list. Special case.
2365:                                    //
2366:                                    // TODO KCR Issue 131: this should probably be
2367:                                    // changed to a list of screens since multiple
2368:                                    // off-screen canvases (either auto or manual) can
2369:                                    // be used by the same renderer
2370:                                    if (!cv.manualRendering) {
2371:                                        screen.renderer.onScreen = screen;
2372:                                    } else {
2373:                                        screen.renderer.offScreen = screen;
2374:                                        continue;
2375:                                    }
2376:
2377:                                    if (!added) {
2378:                                        // Swap message data thread, one per 
2379:                                        // screen only. Note that we don't set
2380:                                        // lastUpdateTime for this thread so
2381:                                        // that it won't run in the first round
2382:                                        J3dThreadData renderData = screen.renderer
2383:                                                .getThreadData(v, null);
2384:                                        renderThreadData.add(renderData);
2385:
2386:                                        // only if renderBin is ready then we
2387:                                        // update the lastUpdateTime to make it run 
2388:                                        if (v.renderBinReady) {
2389:                                            renderData.lastUpdateTime = Math
2390:                                                    .max(
2391:                                                            currentTime,
2392:                                                            renderData.lastUpdateTime);
2393:                                        }
2394:                                        added = true;
2395:                                    }
2396:                                    // Renderer message data thread
2397:                                    J3dThreadData renderData = screen.renderer
2398:                                            .getThreadData(v, cv);
2399:                                    renderThreadData.add(renderData);
2400:                                    if (v.renderBinReady) {
2401:                                        renderData.lastUpdateTime = Math.max(
2402:                                                currentTime,
2403:                                                renderData.lastUpdateTime);
2404:                                    }
2405:                                }
2406:                            }
2407:                        }
2408:
2409:                    }
2410:                }
2411:
2412:                threadListsChanged = true;
2413:            }
2414:
2415:            private void evaluatePhysicalEnv(View v) {
2416:                final PhysicalEnvironment env = v.physicalEnvironment;
2417:
2418:                if (env.inputsched == null) {
2419:                    java.security.AccessController
2420:                            .doPrivileged(new java.security.PrivilegedAction() {
2421:                                public Object run() {
2422:                                    synchronized (rootThreadGroup) {
2423:                                        env.inputsched = new InputDeviceScheduler(
2424:                                                rootThreadGroup, env);
2425:                                        env.inputsched
2426:                                                .setPriority(threadPriority);
2427:                                    }
2428:                                    return null;
2429:                                }
2430:                            });
2431:                    env.inputsched.start();
2432:                    PhysicalEnvironment.physicalEnvMap.put(env, env.inputsched);
2433:                }
2434:                threadListsChanged = true;
2435:            }
2436:
2437:            final private void addToStateThreads(J3dThreadData threadData) {
2438:                if (threadData.thread.active) {
2439:                    stateWorkThreads.add(threadData);
2440:                }
2441:            }
2442:
2443:            private void assignNewPrimaryView(VirtualUniverse univ) {
2444:
2445:                View currentPrimary = univ.getCurrentView();
2446:
2447:                if (currentPrimary != null) {
2448:                    currentPrimary.primaryView = false;
2449:                }
2450:
2451:                View v[] = (View[]) views.toArray(false);
2452:                int nviews = views.size();
2453:                for (int i = 0; i < nviews; i++) {
2454:                    View view = v[i];
2455:                    if (view.active && view.isRunning
2456:                            && (univ == view.universe)) {
2457:                        view.primaryView = true;
2458:                        univ.setCurrentView(view);
2459:                        return;
2460:                    }
2461:                }
2462:                univ.setCurrentView(null);
2463:            }
2464:
2465:            /**
2466:             * This returns the default RenderMethod
2467:             */
2468:            RenderMethod getDefaultRenderMethod() {
2469:                if (defaultRenderMethod == null) {
2470:                    defaultRenderMethod = new DefaultRenderMethod();
2471:                }
2472:                return defaultRenderMethod;
2473:            }
2474:
2475:            /**
2476:             * This returns the text3d RenderMethod
2477:             */
2478:            RenderMethod getText3DRenderMethod() {
2479:                if (text3DRenderMethod == null) {
2480:                    text3DRenderMethod = new Text3DRenderMethod();
2481:                }
2482:                return text3DRenderMethod;
2483:            }
2484:
2485:            /**
2486:             * This returns the vertexArray RenderMethod
2487:             */
2488:            RenderMethod getVertexArrayRenderMethod() {
2489:                if (vertexArrayRenderMethod == null) {
2490:                    vertexArrayRenderMethod = new VertexArrayRenderMethod();
2491:                }
2492:                return vertexArrayRenderMethod;
2493:            }
2494:
2495:            /**
2496:             * This returns the displayList RenderMethod
2497:             */
2498:            RenderMethod getDisplayListRenderMethod() {
2499:                if (displayListRenderMethod == null) {
2500:                    displayListRenderMethod = new DisplayListRenderMethod();
2501:                }
2502:                return displayListRenderMethod;
2503:            }
2504:
2505:            /**
2506:             * This returns the compressed geometry RenderMethod
2507:             */
2508:            RenderMethod getCompressedGeometryRenderMethod() {
2509:                if (compressedGeometryRenderMethod == null) {
2510:                    compressedGeometryRenderMethod = new CompressedGeometryRenderMethod();
2511:                }
2512:                return compressedGeometryRenderMethod;
2513:            }
2514:
2515:            /**
2516:             * This returns the oriented shape3d RenderMethod
2517:             */
2518:            RenderMethod getOrientedShape3DRenderMethod() {
2519:                if (orientedShape3DRenderMethod == null) {
2520:                    orientedShape3DRenderMethod = new OrientedShape3DRenderMethod();
2521:                }
2522:                return orientedShape3DRenderMethod;
2523:            }
2524:
2525:            /** 
2526:             * This notifies MasterControl that the given view has been activated
2527:             */
2528:            private void viewActivate(View v) {
2529:
2530:                VirtualUniverse univ = v.universe;
2531:
2532:                if (univ == null) {
2533:                    return;
2534:                }
2535:
2536:                if (!views.contains(v) || !regUniverseList.contains(univ)) {
2537:                    registerView(v);
2538:                } else if (v.active) {
2539:                    evaluateAllCanvases();
2540:                    return;
2541:                }
2542:
2543:                if ((univ.activeViewCount == 0)) {
2544:                    univ.geometryStructure.resetConditionMet();
2545:                    univ.behaviorStructure.resetConditionMet();
2546:                }
2547:
2548:                if (v.isRunning) {
2549:                    numActiveViews++;
2550:                    univ.activeViewCount++;
2551:                    renderingAttributesStructure.updateThread.active = true;
2552:                    univ.transformStructure.updateThread.active = true;
2553:                    univ.geometryStructure.updateThread.active = true;
2554:                    univ.soundStructure.updateThread.active = true;
2555:                    univ.renderingEnvironmentStructure.updateThread.active = true;
2556:                }
2557:                univ.behaviorScheduler.active = true;
2558:                univ.behaviorStructure.updateThread.active = true;
2559:
2560:                activeUniverseList.addUnique(univ);
2561:
2562:                if (v.isRunning) {
2563:                    v.soundScheduler.activate();
2564:                    v.renderBin.updateThread.active = true;
2565:                }
2566:                v.active = true;
2567:
2568:                if (v.physicalEnvironment.activeViewRef++ == 0) {
2569:                    v.physicalEnvironment.inputsched.activate();
2570:                }
2571:
2572:                if (univ.getCurrentView() == null) {
2573:                    assignNewPrimaryView(univ);
2574:                }
2575:
2576:                evaluateAllCanvases();
2577:                v.inRenderThreadData = true;
2578:                threadListsChanged = true;
2579:                // Notify GeometryStructure to query visible atom again
2580:                // We should send message instead of just setting
2581:                // v.vDirtyMask = View.VISIBILITY_POLICY_DIRTY;  
2582:                // since RenderBin may not run immediately next time.
2583:                // In this case the dirty flag will lost since 
2584:                // updateViewCache() will reset it to 0.
2585:                v.renderBin.reactivateView = true;
2586:            }
2587:
2588:            /**
2589:             * Release context associate with view
2590:             */
2591:            private void freeContext(View v) {
2592:                Canvas3D[][] canvasList = v.getCanvasList(false);
2593:
2594:                for (int j = canvasList.length - 1; j >= 0; j--) {
2595:                    for (int k = canvasList[j].length - 1; k >= 0; k--) {
2596:                        Canvas3D cv = canvasList[j][k];
2597:                        if (!cv.validCanvas) {
2598:                            if ((cv.screen != null)
2599:                                    && (cv.screen.renderer != null)) {
2600:                                rendererCleanupArgs[1] = cv;
2601:                                rendererCleanupArgs[2] = FREECONTEXT_CLEANUP;
2602:                                runMonitor(RUN_RENDERER_CLEANUP, null, null,
2603:                                        null, cv.screen.renderer);
2604:                                rendererCleanupArgs[1] = null;
2605:                            }
2606:                        }
2607:                    }
2608:                }
2609:            }
2610:
2611:            /** 
2612:             * This notifies MasterControl that the given view has been deactivated
2613:             */
2614:            private void viewDeactivate(View v) {
2615:
2616:                if (!views.contains(v) || !v.active) {
2617:                    v.active = false;
2618:                    evaluateAllCanvases();
2619:                    return;
2620:                }
2621:
2622:                VirtualUniverse univ = v.universe;
2623:
2624:                if (v.isRunning) {
2625:                    // if stopView() invoke before, no need to decrement count
2626:                    --numActiveViews;
2627:                    --univ.activeViewCount;
2628:                }
2629:
2630:                if (numActiveViews == 0) {
2631:                    renderingAttributesStructure.updateThread.active = false;
2632:                }
2633:
2634:                if (univ.activeViewCount == 0) {
2635:                    // check if destroyUniverseThread invoked before
2636:                    if (univ.behaviorScheduler != null) {
2637:                        univ.behaviorScheduler.deactivate();
2638:                        univ.transformStructure.updateThread.active = false;
2639:                        univ.geometryStructure.updateThread.active = false;
2640:                        univ.behaviorStructure.updateThread.active = false;
2641:                        univ.soundStructure.updateThread.active = false;
2642:                        univ.renderingEnvironmentStructure.updateThread.active = false;
2643:                        activeUniverseList.remove(univ);
2644:                    }
2645:                }
2646:
2647:                v.soundScheduler.deactivate();
2648:                v.renderBin.updateThread.active = false;
2649:                v.active = false;
2650:                if (--v.physicalEnvironment.activeViewRef == 0) {
2651:                    v.physicalEnvironment.inputsched.deactivate();
2652:                }
2653:                assignNewPrimaryView(univ);
2654:
2655:                evaluateAllCanvases();
2656:
2657:                freeContext(v);
2658:
2659:                v.inRenderThreadData = false;
2660:                threadListsChanged = true;
2661:            }
2662:
2663:            /** 
2664:             * This notifies MasterControl to start given view
2665:             */
2666:            private void startView(View v) {
2667:
2668:                if (!views.contains(v) || v.isRunning || !v.active) {
2669:                    v.isRunning = true;
2670:                    return;
2671:                }
2672:
2673:                numActiveViews++;
2674:                renderingAttributesStructure.updateThread.active = true;
2675:
2676:                VirtualUniverse univ = v.universe;
2677:
2678:                univ.activeViewCount++;
2679:                univ.transformStructure.updateThread.active = true;
2680:                univ.geometryStructure.updateThread.active = true;
2681:                univ.soundStructure.updateThread.active = true;
2682:                univ.renderingEnvironmentStructure.updateThread.active = true;
2683:                v.renderBin.updateThread.active = true;
2684:                v.soundScheduler.activate();
2685:                v.isRunning = true;
2686:                if (univ.getCurrentView() == null) {
2687:                    assignNewPrimaryView(univ);
2688:                }
2689:                threadListsChanged = true;
2690:            }
2691:
2692:            /** 
2693:             * This notifies MasterControl to stop given view
2694:             */
2695:            private void stopView(View v) {
2696:                if (!views.contains(v) || !v.isRunning || !v.active) {
2697:                    v.isRunning = false;
2698:                    return;
2699:                }
2700:
2701:                if (--numActiveViews == 0) {
2702:                    renderingAttributesStructure.updateThread.active = false;
2703:                }
2704:                VirtualUniverse univ = v.universe;
2705:
2706:                if (--univ.activeViewCount == 0) {
2707:                    univ.transformStructure.updateThread.active = false;
2708:                    univ.geometryStructure.updateThread.active = false;
2709:                    univ.renderingEnvironmentStructure.updateThread.active = false;
2710:                    univ.soundStructure.updateThread.active = false;
2711:                }
2712:
2713:                v.renderBin.updateThread.active = false;
2714:                v.soundScheduler.deactivate();
2715:                v.isRunning = false;
2716:                assignNewPrimaryView(univ);
2717:                threadListsChanged = true;
2718:            }
2719:
2720:            // Call from user thread
2721:            void addInputDeviceScheduler(InputDeviceScheduler ds) {
2722:                synchronized (inputDeviceThreads) {
2723:                    inputDeviceThreads.add(ds);
2724:                    if (inputDeviceThreads.size() == 1) {
2725:                        timerThread.addInputDeviceSchedCond();
2726:                    }
2727:                }
2728:                postRequest(INPUTDEVICE_CHANGE, null);
2729:            }
2730:
2731:            // Call from user thread
2732:            void removeInputDeviceScheduler(InputDeviceScheduler ds) {
2733:                inputDeviceThreads.remove(ds);
2734:                postRequest(INPUTDEVICE_CHANGE, null);
2735:            }
2736:
2737:            /**
2738:             * Add an object to the mirror object list
2739:             */
2740:            void addMirrorObject(ObjectUpdate o) {
2741:                mirrorObjects.add(o);
2742:            }
2743:
2744:            /**
2745:             * This updates any mirror objects.  It is called when threads 
2746:             * are done.
2747:             */
2748:            void updateMirrorObjects() {
2749:                ObjectUpdate objs[] = (ObjectUpdate[]) mirrorObjects
2750:                        .toArray(false);
2751:                int sz = mirrorObjects.arraySize();
2752:
2753:                for (int i = 0; i < sz; i++) {
2754:                    objs[i].updateObject();
2755:                }
2756:                mirrorObjects.clear();
2757:            }
2758:
2759:            /**
2760:             * This fun little method does all the hard work of setting up the
2761:             * work thread list.
2762:             */
2763:            private void updateWorkThreads() {
2764:
2765:                stateWorkThreads.clear();
2766:                renderWorkThreads.clear();
2767:                requestRenderWorkThreads.clear();
2768:
2769:                // First the global rendering attributes structure update
2770:                if (numActiveViews > 0) {
2771:                    addToStateThreads(renderingAttributesStructure
2772:                            .getUpdateThreadData());
2773:                }
2774:
2775:                // Next, each of the transform structure updates
2776:                VirtualUniverse universes[] = (VirtualUniverse[]) activeUniverseList
2777:                        .toArray(false);
2778:                VirtualUniverse univ;
2779:                int i;
2780:                int size = activeUniverseList.arraySize();
2781:
2782:                for (i = size - 1; i >= 0; i--) {
2783:                    addToStateThreads(universes[i].transformStructure
2784:                            .getUpdateThreadData());
2785:                }
2786:                lastTransformStructureThread = stateWorkThreads.size();
2787:
2788:                // Next, the GeometryStructure, BehaviorStructure, 
2789:                //       RenderingEnvironmentStructure, and SoundStructure
2790:                for (i = size - 1; i >= 0; i--) {
2791:                    univ = universes[i];
2792:                    addToStateThreads(univ.geometryStructure
2793:                            .getUpdateThreadData());
2794:                    addToStateThreads(univ.behaviorStructure
2795:                            .getUpdateThreadData());
2796:                    addToStateThreads(univ.renderingEnvironmentStructure
2797:                            .getUpdateThreadData());
2798:                    addToStateThreads(univ.soundStructure.getUpdateThreadData());
2799:                }
2800:
2801:                lastStructureUpdateThread = stateWorkThreads.size();
2802:
2803:                // Next, the BehaviorSchedulers
2804:                for (i = size - 1; i >= 0; i--) {
2805:                    addToStateThreads(universes[i].behaviorScheduler
2806:                            .getThreadData(null, null));
2807:                }
2808:
2809:                // Now InputDeviceScheduler
2810:
2811:                InputDeviceScheduler ds[] = (InputDeviceScheduler[]) inputDeviceThreads
2812:                        .toArray(true);
2813:                for (i = inputDeviceThreads.size() - 1; i >= 0; i--) {
2814:                    J3dThreadData threadData = ds[i].getThreadData();
2815:                    threadData.thread.active = true;
2816:                    addToStateThreads(threadData);
2817:                }
2818:
2819:                // Now the RenderBins and SoundSchedulers
2820:                View viewArr[] = (View[]) views.toArray(false);
2821:                J3dThreadData thread;
2822:
2823:                for (i = views.size() - 1; i >= 0; i--) {
2824:                    View v = viewArr[i];
2825:                    if (v.active && v.isRunning) {
2826:                        addToStateThreads(v.renderBin.getUpdateThreadData());
2827:                        addToStateThreads(v.soundScheduler
2828:                                .getUpdateThreadData());
2829:                        Canvas3D canvasList[][] = v.getCanvasList(false);
2830:                        int longestScreenList = v.getLongestScreenList();
2831:                        Object args[] = null;
2832:                        // renderer render 
2833:                        for (int j = 0; j < longestScreenList; j++) {
2834:                            for (int k = 0; k < canvasList.length; k++) {
2835:                                if (j < canvasList[k].length) {
2836:                                    Canvas3D cv = canvasList[k][j];
2837:                                    // Issue 131: setup renderer unless manualRendering
2838:                                    if (cv.active && cv.isRunningStatus
2839:                                            && !cv.manualRendering) {
2840:                                        if (cv.screen.renderer == null) {
2841:                                            continue;
2842:                                        }
2843:                                        thread = cv.screen.renderer
2844:                                                .getThreadData(v, cv);
2845:                                        renderWorkThreads.add(thread);
2846:                                        args = (Object[]) thread.threadArgs;
2847:                                        args[0] = RENDER;
2848:                                        args[1] = cv;
2849:                                        args[2] = v;
2850:                                    }
2851:                                }
2852:                            }
2853:                        }
2854:
2855:                        // renderer swap
2856:                        for (int j = 0; j < canvasList.length; j++) {
2857:                            for (int k = 0; k < canvasList[j].length; k++) {
2858:                                Canvas3D cv = canvasList[j][k];
2859:                                // create swap thread only if there is at
2860:                                // least one active canvas
2861:                                // Issue 131: only if not manualRendering
2862:                                if (cv.active && cv.isRunningStatus
2863:                                        && !cv.manualRendering) {
2864:                                    if (cv.screen.renderer == null) {
2865:                                        // Should not happen
2866:                                        continue;
2867:                                    }
2868:                                    thread = cv.screen.renderer.getThreadData(
2869:                                            v, null);
2870:                                    renderWorkThreads.add(thread);
2871:                                    args = (Object[]) thread.threadArgs;
2872:                                    args[0] = SWAP;
2873:                                    args[1] = v;
2874:                                    args[2] = canvasList[j];
2875:                                    break;
2876:                                }
2877:                            }
2878:                        }
2879:                    }
2880:                }
2881:
2882:                thread = null;
2883:
2884:                for (Enumeration e = Screen3D.deviceRendererMap.elements(); e
2885:                        .hasMoreElements();) {
2886:                    Renderer rdr = (Renderer) e.nextElement();
2887:                    thread = rdr.getThreadData(null, null);
2888:                    requestRenderWorkThreads.add(thread);
2889:                    thread.threadOpts = J3dThreadData.CONT_THREAD;
2890:                    ((Object[]) thread.threadArgs)[0] = REQUESTRENDER;
2891:                }
2892:
2893:                if (thread != null) {
2894:                    thread.threadOpts |= J3dThreadData.WAIT_ALL_THREADS;
2895:                }
2896:
2897:                threadListsChanged = false;
2898:
2899:                //	 dumpWorkThreads();
2900:            }
2901:
2902:            void dumpWorkThreads() {
2903:                System.err.println("-----------------------------");
2904:                System.err.println("MasterControl/dumpWorkThreads");
2905:
2906:                J3dThreadData threads[];
2907:                int size = 0;
2908:
2909:                for (int k = 0; k < 3; k++) {
2910:                    switch (k) {
2911:                    case 0:
2912:                        threads = (J3dThreadData[]) stateWorkThreads
2913:                                .toArray(false);
2914:                        size = stateWorkThreads.arraySize();
2915:                        break;
2916:                    case 1:
2917:                        threads = (J3dThreadData[]) renderWorkThreads
2918:                                .toArray(false);
2919:                        size = renderWorkThreads.arraySize();
2920:                        break;
2921:                    default:
2922:                        threads = (J3dThreadData[]) requestRenderWorkThreads
2923:                                .toArray(false);
2924:                        size = requestRenderWorkThreads.arraySize();
2925:                        break;
2926:                    }
2927:
2928:                    for (int i = 0; i < size; i++) {
2929:                        J3dThreadData thread = threads[i];
2930:                        System.err
2931:                                .println("Thread " + i + ": " + thread.thread);
2932:                        System.err.println("\tOps: " + thread.threadOpts);
2933:                        if (thread.threadArgs != null) {
2934:                            Object[] args = (Object[]) thread.threadArgs;
2935:                            System.err.print("\tArgs: ");
2936:                            for (int j = 0; j < args.length; j++) {
2937:                                System.err.print(args[j] + " ");
2938:                            }
2939:                        }
2940:                        System.err.println("");
2941:                    }
2942:                }
2943:                System.err.println("-----------------------------");
2944:            }
2945:
2946:            /**
2947:             * A convienence wrapper function for various parts of the system
2948:             * to force MC to run.
2949:             */
2950:            final void setWork() {
2951:                runMonitor(SET_WORK, null, null, null, null);
2952:            }
2953:
2954:            final void setWorkForRequestRenderer() {
2955:                runMonitor(SET_WORK_FOR_REQUEST_RENDERER, null, null, null,
2956:                        null);
2957:            }
2958:
2959:            /**
2960:             * Call from GraphicsConfigTemplate to evaluate current
2961:             * capabilities using Renderer thread to invoke native
2962:             * graphics library functions. This avoid MT-safe problem
2963:             * when using thread directly invoke graphics functions.
2964:             */
2965:            void sendRenderMessage(GraphicsConfiguration gc, Object arg,
2966:                    Integer mtype) {
2967:                Renderer rdr = createRenderer(gc);
2968:                J3dMessage renderMessage = new J3dMessage();
2969:                renderMessage.threads = J3dThread.RENDER_THREAD;
2970:                renderMessage.type = J3dMessage.RENDER_IMMEDIATE;
2971:                renderMessage.universe = null;
2972:                renderMessage.view = null;
2973:                renderMessage.args[0] = null;
2974:                renderMessage.args[1] = arg;
2975:                renderMessage.args[2] = mtype;
2976:                rdr.rendererStructure.addMessage(renderMessage);
2977:                setWorkForRequestRenderer();
2978:            }
2979:
2980:            // Issue for Issue 175
2981:            // Pass DestroyCtxAndOffScreenBuffer to the Renderer thread for execution.
2982:            void sendDestroyCtxAndOffScreenBuffer(Canvas3D c) {
2983:                // Assertion check. Look for comment in sendCreateOffScreenBuffer.
2984:                GraphicsDevice gd = c.graphicsConfiguration.getDevice();
2985:                assert Screen3D.deviceRendererMap.get(gd) != null;
2986:
2987:                synchronized (mcThreadLock) {
2988:                    // Issue 364: create master control thread if needed
2989:                    createMasterControlThread();
2990:                    assert mcThread != null;
2991:
2992:                    Renderer rdr = createRenderer(c.graphicsConfiguration);
2993:                    J3dMessage createMessage = new J3dMessage();
2994:                    createMessage.threads = J3dThread.RENDER_THREAD;
2995:                    createMessage.type = J3dMessage.DESTROY_CTX_AND_OFFSCREENBUFFER;
2996:                    createMessage.universe = null;
2997:                    createMessage.view = null;
2998:                    createMessage.args[0] = c;
2999:                    // Fix for issue 340: send display, drawable & ctx in msg
3000:                    createMessage.args[1] = new Long(c.screen.display);
3001:                    createMessage.args[2] = c.drawable;
3002:                    createMessage.args[3] = c.ctx;
3003:                    rdr.rendererStructure.addMessage(createMessage);
3004:                    synchronized (requestObjList) {
3005:                        setWorkForRequestRenderer();
3006:                        pendingRequest = true;
3007:                    }
3008:                }
3009:            }
3010:
3011:            // Fix for Issue 18
3012:            // Pass CreateOffScreenBuffer to the Renderer thread for execution.
3013:            void sendCreateOffScreenBuffer(Canvas3D c) {
3014:                // Assertion check that the renderer has already been created.
3015:                // If it hasn't, this is very, very bad because it opens up
3016:                // the possibility of an MT race condition since this method
3017:                // can be called from the user's thread, possibly at the same
3018:                // time as the MasterControl thread is trying to create a new
3019:                // Renderer.  Fortunately, this should never happen since both
3020:                // the GraphicsTemplate3D methods that return a valid Graphics
3021:                // Configuration and the Canvas3D constructor will ultimately
3022:                // cause a renderer to be created via sendRenderMessage().
3023:                GraphicsDevice gd = c.graphicsConfiguration.getDevice();
3024:                J3dDebug.doAssert((Screen3D.deviceRendererMap.get(gd) != null),
3025:                        "Screen3D.deviceRendererMap.get(gd) != null");
3026:
3027:                synchronized (mcThreadLock) {
3028:                    // Create master control thread if needed
3029:                    createMasterControlThread();
3030:                    assert mcThread != null;
3031:
3032:                    // Fix for Issue 72 : call createRenderer rather than getting
3033:                    // the renderer from the canvas.screen object
3034:                    Renderer rdr = createRenderer(c.graphicsConfiguration);
3035:                    J3dMessage createMessage = new J3dMessage();
3036:                    createMessage.threads = J3dThread.RENDER_THREAD;
3037:                    createMessage.type = J3dMessage.CREATE_OFFSCREENBUFFER;
3038:                    createMessage.universe = null;
3039:                    createMessage.view = null;
3040:                    createMessage.args[0] = c;
3041:                    rdr.rendererStructure.addMessage(createMessage);
3042:                    synchronized (requestObjList) {
3043:                        setWorkForRequestRenderer();
3044:                        pendingRequest = true;
3045:                    }
3046:                }
3047:            }
3048:
3049:            // Issue 347 - Pass AllocateCanvasId to the Renderer thread for execution
3050:            void sendAllocateCanvasId(Canvas3D c) {
3051:                synchronized (mcThreadLock) {
3052:                    // Issue 364: create master control thread if needed
3053:                    createMasterControlThread();
3054:                    assert mcThread != null;
3055:
3056:                    Renderer rdr = createRenderer(c.graphicsConfiguration);
3057:                    J3dMessage createMessage = new J3dMessage();
3058:                    createMessage.threads = J3dThread.RENDER_THREAD;
3059:                    createMessage.type = J3dMessage.ALLOCATE_CANVASID;
3060:                    createMessage.universe = null;
3061:                    createMessage.view = null;
3062:                    createMessage.args[0] = c;
3063:                    rdr.rendererStructure.addMessage(createMessage);
3064:                    synchronized (requestObjList) {
3065:                        setWorkForRequestRenderer();
3066:                        pendingRequest = true;
3067:                    }
3068:                }
3069:            }
3070:
3071:            // Issue 347 - Pass AllocateCanvasId to the Renderer thread for execution
3072:            void sendFreeCanvasId(Canvas3D c) {
3073:                synchronized (mcThreadLock) {
3074:                    // Issue 364: create master control thread if needed
3075:                    createMasterControlThread();
3076:                    assert mcThread != null;
3077:
3078:                    Renderer rdr = createRenderer(c.graphicsConfiguration);
3079:                    J3dMessage createMessage = new J3dMessage();
3080:                    createMessage.threads = J3dThread.RENDER_THREAD;
3081:                    createMessage.type = J3dMessage.FREE_CANVASID;
3082:                    createMessage.universe = null;
3083:                    createMessage.view = null;
3084:                    createMessage.args[0] = c;
3085:                    rdr.rendererStructure.addMessage(createMessage);
3086:                    synchronized (requestObjList) {
3087:                        setWorkForRequestRenderer();
3088:                        pendingRequest = true;
3089:                    }
3090:                }
3091:            }
3092:
3093:            /**
3094:             * This is the MasterControl work method for Java 3D
3095:             */
3096:            void doWork() {
3097:                runMonitor(CHECK_FOR_WORK, null, null, null, null);
3098:
3099:                synchronized (timeLock) {
3100:                    synchronized (requestObjList) {
3101:                        if (pendingRequest) {
3102:                            handlePendingRequest();
3103:                        }
3104:                    }
3105:                }
3106:
3107:                if (!running) {
3108:                    return;
3109:                }
3110:
3111:                if (threadListsChanged) { // Check for new Threads
3112:                    updateWorkThreads();
3113:                }
3114:
3115:                synchronized (timeLock) {
3116:                    // This is neccesary to prevent updating 
3117:                    // thread.lastUpdateTime from user thread
3118:                    // in sendMessage() or sendRunMessage()
3119:                    updateTimeValues();
3120:                }
3121:
3122:                //This is temporary until the view model is updated
3123:                View v[] = (View[]) views.toArray(false);
3124:                for (int i = views.size() - 1; i >= 0; i--) {
3125:                    if (v[i].active) {
3126:                        v[i].updateViewCache();
3127:                        // update OrientedShape3D
3128:                        if ((v[i].viewCache.vcDirtyMask != 0 && !v[i].renderBin.orientedRAs
3129:                                .isEmpty())
3130:                                || (v[i].renderBin.cachedDirtyOrientedRAs != null && !v[i].renderBin.cachedDirtyOrientedRAs
3131:                                        .isEmpty())) {
3132:                            v[i].renderBin.updateOrientedRAs();
3133:                        }
3134:                    }
3135:                }
3136:
3137:                runMonitor(RUN_THREADS, stateWorkThreads, renderWorkThreads,
3138:                        requestRenderWorkThreads, null);
3139:
3140:                if (renderOnceList.size() > 0) {
3141:                    clearRenderOnceList();
3142:                }
3143:
3144:                manageMemory();
3145:
3146:            }
3147:
3148:            private void handlePendingRequest() {
3149:
3150:                Object objs[];
3151:                Integer types[];
3152:                int size;
3153:                boolean rendererRun = false;
3154:
3155:                objs = requestObjList.toArray(false);
3156:                types = (Integer[]) requestTypeList.toArray(false);
3157:                size = requestObjList.size();
3158:
3159:                for (int i = 0; i < size; i++) {
3160:                    // need to process request in order
3161:                    Integer type = types[i];
3162:                    Object o = objs[i];
3163:                    if (type == RESET_CANVAS) {
3164:                        Canvas3D cv = (Canvas3D) o;
3165:                        if ((cv.screen != null) && (cv.screen.renderer != null)) {
3166:                            rendererCleanupArgs[1] = o;
3167:                            rendererCleanupArgs[2] = RESETCANVAS_CLEANUP;
3168:                            runMonitor(RUN_RENDERER_CLEANUP, null, null, null,
3169:                                    cv.screen.renderer);
3170:                            rendererCleanupArgs[1] = null;
3171:                        }
3172:                        cv.reset();
3173:                        cv.view = null;
3174:                        cv.computeViewCache();
3175:                    } else if (type == ACTIVATE_VIEW) {
3176:                        viewActivate((View) o);
3177:                    } else if (type == DEACTIVATE_VIEW) {
3178:                        viewDeactivate((View) o);
3179:                    } else if (type == REEVALUATE_CANVAS) {
3180:                        evaluateAllCanvases();
3181:                    } else if (type == INPUTDEVICE_CHANGE) {
3182:                        inputDeviceThreads.clearMirror();
3183:                        threadListsChanged = true;
3184:                    } else if (type == START_VIEW) {
3185:                        startView((View) o);
3186:                    } else if (type == STOP_VIEW) {
3187:                        View v = (View) o;
3188:                        // Collision takes 3 rounds to finish its request
3189:                        if (++v.stopViewCount > 4) {
3190:                            v.stopViewCount = -1; // reset counter
3191:                            stopView(v);
3192:                        } else {
3193:                            tempViewList.add(v);
3194:                        }
3195:                    } else if (type == UNREGISTER_VIEW) {
3196:                        unregisterView((View) o);
3197:                    } else if (type == PHYSICAL_ENV_CHANGE) {
3198:                        evaluatePhysicalEnv((View) o);
3199:                    } else if (type == EMPTY_UNIVERSE) {
3200:                        // Issue 81: We need to process this message as long
3201:                        // as there are no views associated with this
3202:                        // universe. Previously, this message was ignored if
3203:                        // there were views associated with *any* universe,
3204:                        // which led to a memory / thread leak.
3205:                        boolean foundView = false;
3206:                        VirtualUniverse univ = (VirtualUniverse) o;
3207:                        View v[] = (View[]) views.toArray(false);
3208:                        for (int j = views.size() - 1; j >= 0; j--) {
3209:                            if (v[j].universe == univ) {
3210:                                foundView = true;
3211:                                break;
3212:                            }
3213:                        }
3214:                        if (!foundView) {
3215:                            destroyUniverseThreads(univ);
3216:                            threadListsChanged = true;
3217:                        }
3218:                    } else if (type == START_RENDERER) {
3219:                        if (o instanceof  Canvas3D) {
3220:                            Canvas3D c3d = (Canvas3D) o;
3221:                            if (!c3d.isFatalError()) {
3222:                                c3d.isRunningStatus = true;
3223:                            }
3224:                        } else {
3225:                            ((Renderer) o).userStop = false;
3226:                        }
3227:                        threadListsChanged = true;
3228:                    } else if (type == STOP_RENDERER) {
3229:                        if (o instanceof  Canvas3D) {
3230:                            ((Canvas3D) o).isRunningStatus = false;
3231:                        } else {
3232:                            ((Renderer) o).userStop = true;
3233:                        }
3234:                        threadListsChanged = true;
3235:                    } else if (type == RENDER_ONCE) {
3236:                        View v = (View) o;
3237:                        // temporary start View for renderonce
3238:                        // it will stop afterwards
3239:                        startView(v);
3240:                        renderOnceList.add(v);
3241:                        sendRunMessage(v, J3dThread.UPDATE_RENDER);
3242:                        threadListsChanged = true;
3243:                        rendererRun = true;
3244:                    } else if (type == FREE_CONTEXT) {
3245:                        Canvas3D cv = (Canvas3D) ((Object[]) o)[0];
3246:                        if ((cv.screen != null) && (cv.screen.renderer != null)) {
3247:                            rendererCleanupArgs[1] = o;
3248:                            rendererCleanupArgs[2] = REMOVECTX_CLEANUP;
3249:                            runMonitor(RUN_RENDERER_CLEANUP, null, null, null,
3250:                                    cv.screen.renderer);
3251:                            rendererCleanupArgs[1] = null;
3252:                        }
3253:                        rendererRun = true;
3254:                    } else if (type == FREE_DRAWING_SURFACE) {
3255:                        Pipeline.getPipeline().freeDrawingSurfaceNative(o);
3256:                    } else if (type == GETBESTCONFIG) {
3257:                        GraphicsConfiguration gc = ((GraphicsConfiguration[]) ((GraphicsConfigTemplate3D) o).testCfg)[0];
3258:                        sendRenderMessage(gc, o, type);
3259:                        rendererRun = true;
3260:                    } else if (type == ISCONFIGSUPPORT) {
3261:                        GraphicsConfiguration gc = (GraphicsConfiguration) ((GraphicsConfigTemplate3D) o).testCfg;
3262:                        sendRenderMessage(gc, o, type);
3263:                        rendererRun = true;
3264:                    } else if ((type == SET_GRAPHICSCONFIG_FEATURES)
3265:                            || (type == SET_QUERYPROPERTIES)) {
3266:                        GraphicsConfiguration gc = (GraphicsConfiguration) ((Canvas3D) o).graphicsConfiguration;
3267:                        sendRenderMessage(gc, o, type);
3268:                        rendererRun = true;
3269:                    } else if (type == SET_VIEW) {
3270:                        Canvas3D cv = (Canvas3D) o;
3271:                        cv.view = cv.pendingView;
3272:                        cv.computeViewCache();
3273:                    }
3274:                }
3275:
3276:                // Do it only after all universe/View is register
3277:                for (int i = 0; i < size; i++) {
3278:                    Integer type = types[i];
3279:                    if (type == FREE_MESSAGE) {
3280:                        if (objs[i] instanceof  VirtualUniverse) {
3281:                            VirtualUniverse u = (VirtualUniverse) objs[i];
3282:                            if (!regUniverseList.contains(u)) {
3283:                                emptyMessageList(u.behaviorStructure, null);
3284:                                emptyMessageList(u.geometryStructure, null);
3285:                                emptyMessageList(u.soundStructure, null);
3286:                                emptyMessageList(
3287:                                        u.renderingEnvironmentStructure, null);
3288:                            }
3289:                        } else if (objs[i] instanceof  View) {
3290:                            View v = (View) objs[i];
3291:                            if (!views.contains(v)) {
3292:                                emptyMessageList(v.soundScheduler, v);
3293:                                emptyMessageList(v.renderBin, v);
3294:                                if (v.resetUnivCount == v.universeCount) {
3295:                                    v.reset();
3296:                                    v.universe = null;
3297:                                    if (running == false) {
3298:                                        // MC is about to terminate
3299:
3300:                                        /*
3301:                                        // Don't free list cause there may
3302:                                        // have some other thread returning ID
3303:                                        // after it.
3304:                                        FreeListManager.clearList(FreeListManager.DISPLAYLIST);
3305:                                        FreeListManager.clearList(FreeListManager.TEXTURE2D);
3306:                                        FreeListManager.clearList(FreeListManager.TEXTURE3D);
3307:                                        
3308:                                        synchronized (textureIdLock) {
3309:                                            textureIdCount = 0;
3310:                                        }
3311:                                         */
3312:                                    }
3313:                                }
3314:                            }
3315:                        }
3316:
3317:                    }
3318:
3319:                }
3320:                requestObjList.clear();
3321:                requestTypeList.clear();
3322:
3323:                size = tempViewList.size();
3324:                if (size > 0) {
3325:                    if (running) {
3326:                        for (int i = 0; i < size; i++) {
3327:                            requestTypeList.add(STOP_VIEW);
3328:                            requestObjList.add(tempViewList.get(i));
3329:                        }
3330:                        setWork();
3331:                    } else { // MC will shutdown
3332:                        for (int i = 0; i < size; i++) {
3333:                            View v = (View) tempViewList.get(i);
3334:                            v.stopViewCount = -1;
3335:                            v.isRunning = false;
3336:                        }
3337:                    }
3338:                    tempViewList.clear();
3339:                    pendingRequest = true;
3340:                } else {
3341:                    pendingRequest = rendererRun || (requestObjList.size() > 0);
3342:
3343:                }
3344:
3345:                size = freeMessageList.size();
3346:                if (size > 0) {
3347:                    for (int i = 0; i < size; i++) {
3348:                        requestTypeList.add(FREE_MESSAGE);
3349:                        requestObjList.add(freeMessageList.get(i));
3350:                    }
3351:                    pendingRequest = true;
3352:                    freeMessageList.clear();
3353:                }
3354:                if (!running && (renderOnceList.size() > 0)) {
3355:                    clearRenderOnceList();
3356:                }
3357:
3358:                if (pendingRequest) {
3359:                    setWork();
3360:                }
3361:
3362:                if (rendererRun || requestRenderWorkToDo) {
3363:                    running = true;
3364:                }
3365:
3366:            }
3367:
3368:            private void clearRenderOnceList() {
3369:                for (int i = renderOnceList.size() - 1; i >= 0; i--) {
3370:                    View v = (View) renderOnceList.get(i);
3371:                    v.renderOnceFinish = true;
3372:                    // stop after render once
3373:                    stopView(v);
3374:                }
3375:                renderOnceList.clear();
3376:                threadListsChanged = true;
3377:
3378:            }
3379:
3380:            synchronized void runMonitor(int action,
3381:                    UnorderList stateThreadList, UnorderList renderThreadList,
3382:                    UnorderList requestRenderThreadList, J3dThread nthread) {
3383:
3384:                switch (action) {
3385:                case RUN_THREADS:
3386:                    int currentStateThread = 0;
3387:                    int currentRenderThread = 0;
3388:                    int currentRequestRenderThread = 0;
3389:                    View view;
3390:                    boolean done;
3391:                    J3dThreadData thread;
3392:                    J3dThreadData renderThreads[] = (J3dThreadData[]) renderThreadList
3393:                            .toArray(false);
3394:                    J3dThreadData stateThreads[] = (J3dThreadData[]) stateThreadList
3395:                            .toArray(false);
3396:                    J3dThreadData requestRenderThreads[] = (J3dThreadData[]) requestRenderThreadList
3397:                            .toArray(false);
3398:                    int renderThreadSize = renderThreadList.arraySize();
3399:                    int stateThreadSize = stateThreadList.arraySize();
3400:                    int requestRenderThreadSize = requestRenderThreadList
3401:                            .arraySize();
3402:
3403:                    done = false;
3404:
3405:                    //lock all the needed geometry and image component
3406:                    View[] allView = (View[]) views.toArray(false);
3407:                    View currentV;
3408:                    int i;
3409:
3410:                    if (lockGeometry) {
3411:                        for (i = views.arraySize() - 1; i >= 0; i--) {
3412:                            currentV = allView[i];
3413:                            currentV.renderBin.lockGeometry();
3414:                        }
3415:                    }
3416:
3417:                    while (!done) {
3418:                        // First try a RenderThread
3419:                        while (!renderWaiting
3420:                                && currentRenderThread != renderThreadSize) {
3421:                            thread = renderThreads[currentRenderThread++];
3422:                            if (!thread.needsRun) {
3423:                                continue;
3424:                            }
3425:                            if ((thread.threadOpts & J3dThreadData.START_TIMER) != 0) {
3426:                                view = (View) ((Object[]) thread.threadArgs)[2];
3427:                                view.frameNumber++;
3428:                                view.startTime = J3dClock.currentTimeMillis();
3429:                            }
3430:
3431:                            renderPending++;
3432:
3433:                            if (cpuLimit == 1) {
3434:                                thread.thread.args = (Object[]) thread.threadArgs;
3435:                                thread.thread.doWork(currentTime);
3436:                            } else {
3437:                                threadPending++;
3438:                                thread.thread.runMonitor(J3dThread.RUN,
3439:                                        currentTime,
3440:                                        (Object[]) thread.threadArgs);
3441:                            }
3442:
3443:                            if ((thread.threadOpts & J3dThreadData.STOP_TIMER) != 0) {
3444:                                view = (View) ((Object[]) thread.threadArgs)[3];
3445:                                timestampUpdateList.add(view);
3446:                            }
3447:
3448:                            if ((thread.threadOpts & J3dThreadData.LAST_STOP_TIMER) != 0) {
3449:                                // release lock on locked geometry and image component
3450:                                for (i = 0; i < views.arraySize(); i++) {
3451:                                    currentV = allView[i];
3452:                                    currentV.renderBin.releaseGeometry();
3453:                                }
3454:                            }
3455:
3456:                            if ((cpuLimit != 1)
3457:                                    && (thread.threadOpts & J3dThreadData.WAIT_ALL_THREADS) != 0) {
3458:
3459:                                renderWaiting = true;
3460:                            }
3461:
3462:                            if ((cpuLimit != 1) && (cpuLimit <= threadPending)) {
3463:                                state = WAITING_FOR_CPU;
3464:                                try {
3465:                                    wait();
3466:                                } catch (InterruptedException e) {
3467:                                    System.err.println(e);
3468:                                }
3469:                                state = RUNNING;
3470:                            }
3471:
3472:                        }
3473:                        // Now try state threads
3474:                        while (!stateWaiting
3475:                                && currentStateThread != stateThreadSize) {
3476:                            thread = stateThreads[currentStateThread++];
3477:
3478:                            if (!thread.needsRun) {
3479:                                continue;
3480:                            }
3481:
3482:                            statePending++;
3483:
3484:                            if (cpuLimit == 1) {
3485:                                thread.thread.args = (Object[]) thread.threadArgs;
3486:                                thread.thread.doWork(currentTime);
3487:                            } else {
3488:                                threadPending++;
3489:                                thread.thread.runMonitor(J3dThread.RUN,
3490:                                        currentTime,
3491:                                        (Object[]) thread.threadArgs);
3492:                            }
3493:                            if (cpuLimit != 1
3494:                                    && (thread.threadOpts & J3dThreadData.WAIT_ALL_THREADS) != 0) {
3495:                                stateWaiting = true;
3496:                            }
3497:
3498:                            if ((cpuLimit != 1) && (cpuLimit <= threadPending)) {
3499:                                // Fix bug 4686766 - always allow
3500:                                // renderer thread to continue if not finish 
3501:                                // geomLock can release for Behavior thread to 
3502:                                // continue.
3503:                                if (currentRenderThread == renderThreadSize) {
3504:                                    state = WAITING_FOR_CPU;
3505:                                    try {
3506:                                        wait();
3507:                                    } catch (InterruptedException e) {
3508:                                        System.err.println(e);
3509:                                    }
3510:                                    state = RUNNING;
3511:                                } else {
3512:                                    // Run renderer thread next time
3513:                                    break;
3514:                                }
3515:
3516:                            }
3517:                        }
3518:
3519:                        // Now try requestRender threads
3520:                        if (!renderWaiting
3521:                                && (currentRenderThread == renderThreadSize)) {
3522:                            currentRequestRenderThread = 0;
3523:                            while (!renderWaiting
3524:                                    && (currentRequestRenderThread != requestRenderThreadSize)) {
3525:
3526:                                thread = requestRenderThreads[currentRequestRenderThread++];
3527:
3528:                                renderPending++;
3529:
3530:                                if (cpuLimit == 1) {
3531:                                    thread.thread.args = (Object[]) thread.threadArgs;
3532:                                    thread.thread.doWork(currentTime);
3533:                                } else {
3534:                                    threadPending++;
3535:                                    thread.thread.runMonitor(J3dThread.RUN,
3536:                                            currentTime,
3537:                                            (Object[]) thread.threadArgs);
3538:                                }
3539:                                if (cpuLimit != 1
3540:                                        && (thread.threadOpts & J3dThreadData.WAIT_ALL_THREADS) != 0) {
3541:                                    renderWaiting = true;
3542:                                }
3543:                                if (cpuLimit != 1 && cpuLimit <= threadPending) {
3544:                                    state = WAITING_FOR_CPU;
3545:                                    try {
3546:                                        wait();
3547:                                    } catch (InterruptedException e) {
3548:                                        System.err.println(e);
3549:                                    }
3550:                                    state = RUNNING;
3551:                                }
3552:                            }
3553:                        }
3554:
3555:                        if (cpuLimit != 1) {
3556:                            if ((renderWaiting && (currentStateThread == stateThreadSize))
3557:                                    || (stateWaiting && currentRenderThread == renderThreadSize)
3558:                                    || (renderWaiting && stateWaiting)) {
3559:                                if (!requestRenderWorkToDo) {
3560:                                    state = WAITING_FOR_THREADS;
3561:                                    try {
3562:                                        wait();
3563:                                    } catch (InterruptedException e) {
3564:                                        System.err.println(e);
3565:                                    }
3566:                                    state = RUNNING;
3567:                                }
3568:                                requestRenderWorkToDo = false;
3569:                            }
3570:                        }
3571:
3572:                        if ((currentStateThread == stateThreadSize)
3573:                                && (currentRenderThread == renderThreadSize)
3574:                                && (currentRequestRenderThread == requestRenderThreadSize)
3575:                                && (threadPending == 0)) {
3576:                            for (int k = timestampUpdateList.size() - 1; k >= 0; k--) {
3577:                                View v = (View) timestampUpdateList.get(k);
3578:                                v.setFrameTimingValues();
3579:                                v.universe.behaviorStructure.incElapsedFrames();
3580:                            }
3581:                            timestampUpdateList.clear();
3582:                            updateMirrorObjects();
3583:                            done = true;
3584:
3585:                            if (isStatsLoggable(Level.INFO)) {
3586:                                // Instrumentation of Java 3D renderer
3587:                                logTimes();
3588:                            }
3589:                        }
3590:                    }
3591:                    break;
3592:
3593:                case THREAD_DONE:
3594:                    if (state != WAITING_FOR_RENDERER_CLEANUP) {
3595:
3596:                        threadPending--;
3597:                        assert threadPending >= 0 : ("threadPending = " + threadPending);
3598:                        if (nthread.type == J3dThread.RENDER_THREAD) {
3599:                            View v = (View) nthread.args[3];
3600:                            if (v != null) { // STOP_TIMER
3601:                                v.stopTime = J3dClock.currentTimeMillis();
3602:                            }
3603:
3604:                            if (--renderPending == 0) {
3605:                                renderWaiting = false;
3606:                            }
3607:                            assert renderPending >= 0 : ("renderPending = " + renderPending);
3608:                        } else {
3609:                            if (--statePending == 0) {
3610:                                stateWaiting = false;
3611:                            }
3612:                            assert statePending >= 0 : ("statePending = " + statePending);
3613:                        }
3614:                        if (state == WAITING_FOR_CPU
3615:                                || state == WAITING_FOR_THREADS) {
3616:                            notify();
3617:                        }
3618:                    } else {
3619:                        notify();
3620:                        state = RUNNING;
3621:                    }
3622:                    break;
3623:
3624:                case CHECK_FOR_WORK:
3625:                    if (!workToDo) {
3626:                        state = SLEEPING;
3627:                        // NOTE: this could wakeup spuriously (see issue 279), but it
3628:                        // will not cause any problems.
3629:                        try {
3630:                            wait();
3631:                        } catch (InterruptedException e) {
3632:                            System.err.println(e);
3633:                        }
3634:                        state = RUNNING;
3635:                    }
3636:                    workToDo = false;
3637:                    break;
3638:
3639:                case SET_WORK:
3640:                    workToDo = true;
3641:                    if (state == SLEEPING) {
3642:                        notify();
3643:                    }
3644:                    break;
3645:
3646:                case SET_WORK_FOR_REQUEST_RENDERER:
3647:                    requestRenderWorkToDo = true;
3648:                    workToDo = true;
3649:                    if (state == WAITING_FOR_CPU
3650:                            || state == WAITING_FOR_THREADS
3651:                            || state == SLEEPING) {
3652:                        notify();
3653:                    }
3654:                    break;
3655:
3656:                case RUN_RENDERER_CLEANUP:
3657:                    nthread.runMonitor(J3dThread.RUN, currentTime,
3658:                            rendererCleanupArgs);
3659:                    state = WAITING_FOR_RENDERER_CLEANUP;
3660:                    // Issue 279 - loop until state is set to running
3661:                    while (state != RUNNING) {
3662:                        try {
3663:                            wait();
3664:                        } catch (InterruptedException e) {
3665:                            System.err.println(e);
3666:                        }
3667:                    }
3668:                    break;
3669:
3670:                default:
3671:                    // Should never get here
3672:                    assert false : "missing case in switch statement";
3673:                }
3674:            }
3675:
3676:            // Static initializer
3677:            static {
3678:                // create ThreadGroup
3679:                java.security.AccessController
3680:                        .doPrivileged(new java.security.PrivilegedAction() {
3681:                            public Object run() {
3682:                                ThreadGroup parent;
3683:                                Thread thread = Thread.currentThread();
3684:                                threadPriority = thread.getPriority();
3685:                                rootThreadGroup = thread.getThreadGroup();
3686:                                while ((parent = rootThreadGroup.getParent()) != null) {
3687:                                    rootThreadGroup = parent;
3688:                                }
3689:                                rootThreadGroup = new ThreadGroup(
3690:                                        rootThreadGroup, "Java3D");
3691:                                // use the default maximum group priority
3692:                                return null;
3693:                            }
3694:                        });
3695:
3696:                // Initialize loggers
3697:                try {
3698:                    initLoggers();
3699:                } catch (RuntimeException ex) {
3700:                    System.err.println(ex);
3701:                }
3702:            }
3703:
3704:            static String mtype[] = { "INSERT_NODES", "REMOVE_NODES", "RUN",
3705:                    "TRANSFORM_CHANGED", "UPDATE_VIEW", "STOP_THREAD",
3706:                    "COLORINGATTRIBUTES_CHANGED", "LINEATTRIBUTES_CHANGED",
3707:                    "POINTATTRIBUTES_CHANGED", "POLYGONATTRIBUTES_CHANGED",
3708:                    "RENDERINGATTRIBUTES_CHANGED", "TEXTUREATTRIBUTES_CHANGED",
3709:                    "TRANSPARENCYATTRIBUTES_CHANGED", "MATERIAL_CHANGED",
3710:                    "TEXCOORDGENERATION_CHANGED", "TEXTURE_CHANGED",
3711:                    "MORPH_CHANGED", "GEOMETRY_CHANGED", "APPEARANCE_CHANGED",
3712:                    "LIGHT_CHANGED", "BACKGROUND_CHANGED", "CLIP_CHANGED",
3713:                    "FOG_CHANGED", "BOUNDINGLEAF_CHANGED", "SHAPE3D_CHANGED",
3714:                    "TEXT3D_TRANSFORM_CHANGED", "TEXT3D_DATA_CHANGED",
3715:                    "SWITCH_CHANGED", "COND_MET", "BEHAVIOR_ENABLE",
3716:                    "BEHAVIOR_DISABLE", "INSERT_RENDERATOMS",
3717:                    "ORDERED_GROUP_INSERTED", "ORDERED_GROUP_REMOVED",
3718:                    "COLLISION_BOUND_CHANGED", "REGION_BOUND_CHANGED",
3719:                    "MODELCLIP_CHANGED", "BOUNDS_AUTO_COMPUTE_CHANGED",
3720:                    "SOUND_ATTRIB_CHANGED", "AURALATTRIBUTES_CHANGED",
3721:                    "SOUNDSCAPE_CHANGED", "ALTERNATEAPPEARANCE_CHANGED",
3722:                    "RENDER_OFFSCREEN", "RENDER_RETAINED", "RENDER_IMMEDIATE",
3723:                    "SOUND_STATE_CHANGED", "ORIENTEDSHAPE3D_CHANGED",
3724:                    "TEXTURE_UNIT_STATE_CHANGED", "UPDATE_VIEWPLATFORM",
3725:                    "BEHAVIOR_ACTIVATE", "GEOMETRYARRAY_CHANGED",
3726:                    "MEDIA_CONTAINER_CHANGED", "RESIZE_CANVAS",
3727:                    "TOGGLE_CANVAS", "IMAGE_COMPONENT_CHANGED",
3728:                    "SCHEDULING_INTERVAL_CHANGED", "VIEWSPECIFICGROUP_CHANGED",
3729:                    "VIEWSPECIFICGROUP_INIT", "VIEWSPECIFICGROUP_CLEAR",
3730:                    "ORDERED_GROUP_TABLE_CHANGED", "BEHAVIOR_REEVALUATE",
3731:                    "CREATE_OFFSCREENBUFFER",
3732:                    "DESTROY_CTX_AND_OFFSCREENBUFFER",
3733:                    "SHADER_ATTRIBUTE_CHANGED", "SHADER_ATTRIBUTE_SET_CHANGED",
3734:                    "SHADER_APPEARANCE_CHANGED", "ALLOCATE_CANVASID",
3735:                    "FREE_CANVASID", };
3736:
3737:            private String dumpThreads(int threads) {
3738:                StringBuffer strBuf = new StringBuffer();
3739:                strBuf.append("threads:");
3740:                //dump Threads type
3741:                if ((threads & J3dThread.BEHAVIOR_SCHEDULER) != 0) {
3742:                    strBuf.append(" BEHAVIOR_SCHEDULER");
3743:                }
3744:                if ((threads & J3dThread.SOUND_SCHEDULER) != 0) {
3745:                    strBuf.append(" SOUND_SCHEDULER");
3746:                }
3747:                if ((threads & J3dThread.INPUT_DEVICE_SCHEDULER) != 0) {
3748:                    strBuf.append(" INPUT_DEVICE_SCHEDULER");
3749:                }
3750:                if ((threads & J3dThread.RENDER_THREAD) != 0) {
3751:                    strBuf.append(" RENDER_THREAD");
3752:                }
3753:                if ((threads & J3dThread.UPDATE_GEOMETRY) != 0) {
3754:                    strBuf.append(" UPDATE_GEOMETRY");
3755:                }
3756:                if ((threads & J3dThread.UPDATE_RENDER) != 0) {
3757:                    strBuf.append(" UPDATE_RENDER");
3758:                }
3759:                if ((threads & J3dThread.UPDATE_BEHAVIOR) != 0) {
3760:                    strBuf.append(" UPDATE_BEHAVIOR");
3761:                }
3762:                if ((threads & J3dThread.UPDATE_SOUND) != 0) {
3763:                    strBuf.append(" UPDATE_SOUND");
3764:                }
3765:                if ((threads & J3dThread.UPDATE_RENDERING_ATTRIBUTES) != 0) {
3766:                    strBuf.append(" UPDATE_RENDERING_ATTRIBUTES");
3767:                }
3768:                if ((threads & J3dThread.UPDATE_RENDERING_ENVIRONMENT) != 0) {
3769:                    strBuf.append(" UPDATE_RENDERING_ENVIRONMENT");
3770:                }
3771:                if ((threads & J3dThread.UPDATE_TRANSFORM) != 0) {
3772:                    strBuf.append(" UPDATE_TRANSFORM");
3773:                }
3774:
3775:                return strBuf.toString();
3776:            }
3777:
3778:            // Method to log the specified message. Note that the caller
3779:            // should check for isCoreLoggable(FINEST) before calling
3780:            private void dumpMessage(String str, J3dMessage m) {
3781:                StringBuffer strBuf = new StringBuffer();
3782:                strBuf.append(str).append(" ");
3783:                if (m.type >= 0 && m.type < mtype.length) {
3784:                    strBuf.append(mtype[m.type]);
3785:                } else {
3786:                    strBuf.append("<UNKNOWN>");
3787:                }
3788:                strBuf.append("  ").append(dumpThreads(m.threads));
3789:                getCoreLogger().finest(strBuf.toString());
3790:            }
3791:
3792:            int frameCount = 0;
3793:            private int frameCountCutoff = 100;
3794:
3795:            private void manageMemory() {
3796:                if (++frameCount > frameCountCutoff) {
3797:                    FreeListManager.manageLists();
3798:                    frameCount = 0;
3799:                }
3800:            }
3801:
3802:            /**
3803:             * Yields the current thread, by sleeping for a small amount of
3804:             * time.  Unlike <code>Thread.yield()</code>, this method
3805:             * guarantees that the current thread will yield to another thread
3806:             * waiting to run.  It also ensures that the other threads will
3807:             * run for at least a small amount of time before the current
3808:             * thread runs again.
3809:             */
3810:            static final void threadYield() {
3811:                // Note that we can't just use Thread.yield(), since it
3812:                // doesn't guarantee that it will actually yield the thread
3813:                // (and, in fact, it appears to be a no-op under Windows). So
3814:                // we will sleep for 1 msec instead. Since most threads use
3815:                // wait/notify, and only use this when they are waiting for
3816:                // another thread to finish something, this shouldn't be a
3817:                // performance concern.
3818:
3819:                //Thread.yield();
3820:                try {
3821:                    Thread.sleep(1);
3822:                } catch (InterruptedException e) {
3823:                    // Do nothing, since we really don't care how long (or
3824:                    // even whether) we sleep
3825:                }
3826:            }
3827:
3828:            // Return the number of available processors
3829:            private int getNumberOfProcessors() {
3830:                return Runtime.getRuntime().availableProcessors();
3831:            }
3832:
3833:            //
3834:            // The following framework supports code instrumentation. To use it,
3835:            // add code of the following form to areas that you want to enable for
3836:            // timing:
3837:            //
3838:            //     long startTime = System.nanoTime();
3839:            //     sortTransformGroups(tSize, tgs);
3840:            //     long deltaTime = System.nanoTime() - startTime;
3841:            //     VirtualUniverse.mc.recordTime(MasterControl.TimeType.XXXXX, deltaTime);
3842:            //
3843:            // where "XXXXX" is the enum representing the code segment being timed.
3844:            // Additional enums can be defined for new subsystems.
3845:            //
3846:
3847:            static enum TimeType {
3848:                TOTAL_FRAME, RENDER, BEHAVIOR,
3849:                // TRANSFORM_UPDATE,
3850:                // ...
3851:            }
3852:
3853:            private long[] statTimes = new long[TimeType.values().length];
3854:            private int[] statCounts = new int[TimeType.values().length];
3855:            private boolean[] statSeen = new boolean[TimeType.values().length];
3856:            private int frameCycleTick = 0;
3857:            private long frameCycleNumber = 0L;
3858:
3859:            // Method to record times -- should not be called unless the stats logger
3860:            // level is set to INFO or lower
3861:            synchronized void recordTime(TimeType type, long deltaTime) {
3862:                int idx = type.ordinal();
3863:                statTimes[idx] += deltaTime;
3864:                statCounts[idx]++;
3865:                statSeen[idx] = true;
3866:            }
3867:
3868:            // Method to record times -- this is not called unless the stats logger
3869:            // level is set to INFO or lower
3870:            private synchronized void logTimes() {
3871:                ++frameCycleNumber;
3872:                if (++frameCycleTick >= 10) {
3873:                    StringBuffer strBuf = new StringBuffer();
3874:                    strBuf.append(
3875:                            "----------------------------------------------\n")
3876:                            .append("    Frame Number = ").append(
3877:                                    frameCycleNumber).append("\n");
3878:                    for (int i = 0; i < statTimes.length; i++) {
3879:                        if (statSeen[i]) {
3880:                            strBuf.append("    ");
3881:                            if (statCounts[i] > 0) {
3882:                                strBuf
3883:                                        .append(TimeType.values()[i])
3884:                                        .append(" [")
3885:                                        .append(statCounts[i])
3886:                                        .append("] = ")
3887:                                        .append(
3888:                                                (double) statTimes[i]
3889:                                                        / 1000000.0
3890:                                                        / (double) statCounts[i])
3891:                                        .append(" msec per call\n");
3892:                                statTimes[i] = 0L;
3893:                                statCounts[i] = 0;
3894:                            } else {
3895:                                assert statTimes[i] == 0L;
3896:                                strBuf.append(TimeType.values()[i]).append(
3897:                                        " [0] = 0.0 msec\n");
3898:                            }
3899:                        }
3900:                    }
3901:                    getStatsLogger().info(strBuf.toString());
3902:                    frameCycleTick = 0;
3903:                }
3904:            }
3905:
3906:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.