1 /*
2 * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
161 // bad thing. It might have happened during shutdown,
162 // perhaps? Or somebody is poking the FX thread and
163 // asking it to interrupt. Either way, it means
164 // that we have not yet completed rendering some
165 // scenes and we're about to make a mess of things.
166 // Best thing to do is to retry.
167 }
168 }
169 }
170
171 /**
172 * Gets whether there are any dirty scenes that need to be rendered. If
173 * true, then a subsequent pulse event and renderAll call is required.
174 *
175 * @return Whether there are any dirty scenes that need to be rendered.
176 */
177 final boolean hasDirty() {
178 return hasDirty;
179 }
180
181 /**
182 * Adds a dirty scene to the PaintCollector for subsequent processing.
183 * This method simply makes the PaintCollector aware of this new
184 * scene and ensure it gets processed on the next call to renderAll.
185 *
186 * The next QuantumToolkit Glass timer generated pulse or PaintCollector
187 * rendering vsync hinted pulse will process these dirty scenes.
188 *
189 * <p>This method must only be called on the FX Thread</p>
190 *
191 * @param scene The scene which is dirty. This must not be null.
192 */
193 final void addDirtyScene(GlassScene scene) {
194 // Check that we are on the expected thread.
195 assert Thread.currentThread() == QuantumToolkit.getFxUserThread();
196 // Scene must not be null (using assert for performance)
197 assert scene != null;
198
199 if (QuantumToolkit.verbose) {
200 System.err.println("PC.addDirtyScene: " + System.nanoTime() + scene);
201 }
202
203 // Because dirtyScenes is ever only accessed from the FX Thread,
204 // we don't need any form of concurrent access here. Note also
205 // that doing a contains() call here is probably faster than using
206 // a HashSet because we are dealing with such a small number of
207 // scenes that simple iteration is likely to be much faster
208 if (!dirtyScenes.contains(scene)) {
209 dirtyScenes.add(scene);
210 // Now that we know we have added a scene to dirtyScenes,
211 // we should ensure hasDirty is true.
212 hasDirty = true;
213 }
214 }
215
216 /**
217 * Removes a scene from the dirtyScene list. If the given scene
218 * was previously added with a call to addDirtyScene, it will
219 * be removed. Potentially this means that after this call the
220 * PaintCollector will no longer have any dirty scenes and will
221 * no longer require a repaint.
222 *
223 * <p>This method is typically called when a scene is removed
224 * from a stage, or when visible becomes false.
225 * </p>
226 *
227 * <p>This method must only be called on the FX Thread</p>
228 *
229 * @param scene The scene which is no longer dirty. Must not be null.
230 */
231 final void removeDirtyScene(GlassScene scene) {
232 // Ensure we're called only from the FX thread
233 assert Thread.currentThread() == QuantumToolkit.getFxUserThread();
234 assert scene != null;
235
236 // Need to convert to use JavaFX Logging instead.
237 if (QuantumToolkit.verbose) {
238 System.err.println("PC.removeDirtyScene: " + scene);
239 }
240
241 // Remove the scene
242 dirtyScenes.remove(scene);
243 // Update hasDirty
244 hasDirty = !dirtyScenes.isEmpty();
245 }
246
247 /**
248 * Gets the CompletionListener which must be notified when a
249 * GlassScene has completed rendering.
250 *
251 * @return The CompletionListener. Will never be null.
252 */
253 final CompletionListener getRendered() {
254 return this;
255 }
256
257 /**
258 * This object is a CompletionListener is registered with every GlassScene,
259 * such that when the repaint has completed, this method is called.
260 * This method will decrement the count on the allWorkCompletedLatch.
261 */
262 @Override public void done(RenderJob job) {
263 // It would be better to have an assertive check that
264 // this call is being made on the render thread, rather
344 }
345
346 // Since hasDirty can only be set to true from the FX Thread,
347 // we can do just a simple boolean check here. If we don't
348 // have any dirty scenes to process, then we are done.
349 if (!hasDirty) {
350 return;
351 }
352
353 // Because hasDirty is tied to dirtyScenes, it should
354 // not be possible that we reach this point if dirtyScenes
355 // is empty (since hasDirty was true)
356 assert !dirtyScenes.isEmpty();
357
358 // Sort the dirty scenes based on whether they are
359 // synchronous or not. If they are not synchronous,
360 // then we want to process them first.
361 Collections.sort(dirtyScenes, DIRTY_SCENE_SORTER);
362
363 // Reset the fields
364 hasDirty = false;
365 needsHint = false;
366
367 // If pulse logging is enabled, then we must call renderStart
368 // BEFORE we actually call repaint on any of the dirty scenes.
369 if (PULSE_LOGGING_ENABLED) {
370 PulseLogger.renderStart();
371 }
372
373 // This part needs to be handled a bit differently depending on whether our platform has a native
374 // window manager or not.
375 // So, check to see if we do (Note: how we determine this need to be improved, this should
376 // eventually call down into platform-specific glass code and not rely on
377 // a system property, but we will use this for now)
378 if (!Application.GetApplication().hasWindowManager()) {
379 // No native window manager. We call repaint on every scene (to make sure it gets recopied
380 // to the screen) but we may be able to skip some steps in the repaint.
381
382 // Obtain a z-ordered window list from glass. For platforms without a native window manager,
383 // we need to recopy the all of the window contents to the screen on every frame.
384 final List<com.sun.glass.ui.Window> glassWindowList = com.sun.glass.ui.Window.getWindows();
|
1 /*
2 * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
161 // bad thing. It might have happened during shutdown,
162 // perhaps? Or somebody is poking the FX thread and
163 // asking it to interrupt. Either way, it means
164 // that we have not yet completed rendering some
165 // scenes and we're about to make a mess of things.
166 // Best thing to do is to retry.
167 }
168 }
169 }
170
171 /**
172 * Gets whether there are any dirty scenes that need to be rendered. If
173 * true, then a subsequent pulse event and renderAll call is required.
174 *
175 * @return Whether there are any dirty scenes that need to be rendered.
176 */
177 final boolean hasDirty() {
178 return hasDirty;
179 }
180
181 final void setDirty(boolean value) {
182 hasDirty = value;
183 if (hasDirty) {
184 QuantumToolkit.getToolkit().requestNextPulse();
185 }
186 }
187
188 /**
189 * Adds a dirty scene to the PaintCollector for subsequent processing.
190 * This method simply makes the PaintCollector aware of this new
191 * scene and ensure it gets processed on the next call to renderAll.
192 *
193 * The next QuantumToolkit Glass timer generated pulse or PaintCollector
194 * rendering vsync hinted pulse will process these dirty scenes.
195 *
196 * <p>This method must only be called on the FX Thread</p>
197 *
198 * @param scene The scene which is dirty. This must not be null.
199 */
200 final void addDirtyScene(GlassScene scene) {
201 // Check that we are on the expected thread.
202 assert Thread.currentThread() == QuantumToolkit.getFxUserThread();
203 // Scene must not be null (using assert for performance)
204 assert scene != null;
205
206 if (QuantumToolkit.verbose) {
207 System.err.println("PC.addDirtyScene: " + System.nanoTime() + scene);
208 }
209
210 // Because dirtyScenes is ever only accessed from the FX Thread,
211 // we don't need any form of concurrent access here. Note also
212 // that doing a contains() call here is probably faster than using
213 // a HashSet because we are dealing with such a small number of
214 // scenes that simple iteration is likely to be much faster
215 if (!dirtyScenes.contains(scene)) {
216 dirtyScenes.add(scene);
217 // Now that we know we have added a scene to dirtyScenes,
218 // we should ensure hasDirty is true.
219 setDirty(true);
220 }
221 }
222
223 /**
224 * Removes a scene from the dirtyScene list. If the given scene
225 * was previously added with a call to addDirtyScene, it will
226 * be removed. Potentially this means that after this call the
227 * PaintCollector will no longer have any dirty scenes and will
228 * no longer require a repaint.
229 *
230 * <p>This method is typically called when a scene is removed
231 * from a stage, or when visible becomes false.
232 * </p>
233 *
234 * <p>This method must only be called on the FX Thread</p>
235 *
236 * @param scene The scene which is no longer dirty. Must not be null.
237 */
238 final void removeDirtyScene(GlassScene scene) {
239 // Ensure we're called only from the FX thread
240 assert Thread.currentThread() == QuantumToolkit.getFxUserThread();
241 assert scene != null;
242
243 // Need to convert to use JavaFX Logging instead.
244 if (QuantumToolkit.verbose) {
245 System.err.println("PC.removeDirtyScene: " + scene);
246 }
247
248 // Remove the scene
249 dirtyScenes.remove(scene);
250 // Update hasDirty
251 setDirty(!dirtyScenes.isEmpty());
252 }
253
254 /**
255 * Gets the CompletionListener which must be notified when a
256 * GlassScene has completed rendering.
257 *
258 * @return The CompletionListener. Will never be null.
259 */
260 final CompletionListener getRendered() {
261 return this;
262 }
263
264 /**
265 * This object is a CompletionListener is registered with every GlassScene,
266 * such that when the repaint has completed, this method is called.
267 * This method will decrement the count on the allWorkCompletedLatch.
268 */
269 @Override public void done(RenderJob job) {
270 // It would be better to have an assertive check that
271 // this call is being made on the render thread, rather
351 }
352
353 // Since hasDirty can only be set to true from the FX Thread,
354 // we can do just a simple boolean check here. If we don't
355 // have any dirty scenes to process, then we are done.
356 if (!hasDirty) {
357 return;
358 }
359
360 // Because hasDirty is tied to dirtyScenes, it should
361 // not be possible that we reach this point if dirtyScenes
362 // is empty (since hasDirty was true)
363 assert !dirtyScenes.isEmpty();
364
365 // Sort the dirty scenes based on whether they are
366 // synchronous or not. If they are not synchronous,
367 // then we want to process them first.
368 Collections.sort(dirtyScenes, DIRTY_SCENE_SORTER);
369
370 // Reset the fields
371 setDirty(false);
372 needsHint = false;
373
374 // If pulse logging is enabled, then we must call renderStart
375 // BEFORE we actually call repaint on any of the dirty scenes.
376 if (PULSE_LOGGING_ENABLED) {
377 PulseLogger.renderStart();
378 }
379
380 // This part needs to be handled a bit differently depending on whether our platform has a native
381 // window manager or not.
382 // So, check to see if we do (Note: how we determine this need to be improved, this should
383 // eventually call down into platform-specific glass code and not rely on
384 // a system property, but we will use this for now)
385 if (!Application.GetApplication().hasWindowManager()) {
386 // No native window manager. We call repaint on every scene (to make sure it gets recopied
387 // to the screen) but we may be able to skip some steps in the repaint.
388
389 // Obtain a z-ordered window list from glass. For platforms without a native window manager,
390 // we need to recopy the all of the window contents to the screen on every frame.
391 final List<com.sun.glass.ui.Window> glassWindowList = com.sun.glass.ui.Window.getWindows();
|