Path: blob/master/src/java.desktop/share/classes/sun/java2d/opengl/OGLRenderQueue.java
41159 views
/*1* Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.java2d.opengl;2627import sun.awt.util.ThreadGroupUtils;28import sun.java2d.pipe.RenderBuffer;29import sun.java2d.pipe.RenderQueue;3031import static sun.java2d.pipe.BufferedOpCodes.*;32import java.security.AccessController;33import java.security.PrivilegedAction;3435/**36* OGL-specific implementation of RenderQueue. This class provides a37* single (daemon) thread that is responsible for periodically flushing38* the queue, thus ensuring that only one thread communicates with the native39* OpenGL libraries for the entire process.40*/41public class OGLRenderQueue extends RenderQueue {4243private static OGLRenderQueue theInstance;44private final QueueFlusher flusher;4546@SuppressWarnings("removal")47private OGLRenderQueue() {48/*49* The thread must be a member of a thread group50* which will not get GCed before VM exit.51*/52flusher = AccessController.doPrivileged((PrivilegedAction<QueueFlusher>) QueueFlusher::new);53}5455/**56* Returns the single OGLRenderQueue instance. If it has not yet been57* initialized, this method will first construct the single instance58* before returning it.59*/60public static synchronized OGLRenderQueue getInstance() {61if (theInstance == null) {62theInstance = new OGLRenderQueue();63}64return theInstance;65}6667/**68* Flushes the single OGLRenderQueue instance synchronously. If an69* OGLRenderQueue has not yet been instantiated, this method is a no-op.70* This method is useful in the case of Toolkit.sync(), in which we want71* to flush the OGL pipeline, but only if the OGL pipeline is currently72* enabled. Since this class has few external dependencies, callers need73* not be concerned that calling this method will trigger initialization74* of the OGL pipeline and related classes.75*/76public static void sync() {77if (theInstance != null) {78theInstance.lock();79try {80theInstance.ensureCapacity(4);81theInstance.getBuffer().putInt(SYNC);82theInstance.flushNow();83} finally {84theInstance.unlock();85}86}87}8889/**90* Disposes the native memory associated with the given native91* graphics config info pointer on the single queue flushing thread.92*/93public static void disposeGraphicsConfig(long pConfigInfo) {94OGLRenderQueue rq = getInstance();95rq.lock();96try {97// make sure we make the context associated with the given98// GraphicsConfig current before disposing the native resources99OGLContext.setScratchSurface(pConfigInfo);100101RenderBuffer buf = rq.getBuffer();102rq.ensureCapacityAndAlignment(12, 4);103buf.putInt(DISPOSE_CONFIG);104buf.putLong(pConfigInfo);105106// this call is expected to complete synchronously, so flush now107rq.flushNow();108} finally {109rq.unlock();110}111}112113/**114* Returns true if the current thread is the OGL QueueFlusher thread.115*/116public static boolean isQueueFlusherThread() {117return (Thread.currentThread() == getInstance().flusher.thread);118}119120public void flushNow() {121// assert lock.isHeldByCurrentThread();122try {123flusher.flushNow();124} catch (Exception e) {125System.err.println("exception in flushNow:");126e.printStackTrace();127}128}129130public void flushAndInvokeNow(Runnable r) {131// assert lock.isHeldByCurrentThread();132try {133flusher.flushAndInvokeNow(r);134} catch (Exception e) {135System.err.println("exception in flushAndInvokeNow:");136e.printStackTrace();137}138}139140private native void flushBuffer(long buf, int limit);141142private void flushBuffer() {143// assert lock.isHeldByCurrentThread();144int limit = buf.position();145if (limit > 0) {146// process the queue147flushBuffer(buf.getAddress(), limit);148}149// reset the buffer position150buf.clear();151// clear the set of references, since we no longer need them152refSet.clear();153}154155private class QueueFlusher implements Runnable {156private boolean needsFlush;157private Runnable task;158private Error error;159private final Thread thread;160161public QueueFlusher() {162String name = "Java2D Queue Flusher";163thread = new Thread(ThreadGroupUtils.getRootThreadGroup(),164this, name, 0, false);165thread.setDaemon(true);166thread.setPriority(Thread.MAX_PRIORITY);167thread.start();168}169170public synchronized void flushNow() {171// wake up the flusher172needsFlush = true;173notify();174175// wait for flush to complete176while (needsFlush) {177try {178wait();179} catch (InterruptedException e) {180}181}182183// re-throw any error that may have occurred during the flush184if (error != null) {185throw error;186}187}188189public synchronized void flushAndInvokeNow(Runnable task) {190this.task = task;191flushNow();192}193194public synchronized void run() {195boolean timedOut = false;196while (true) {197while (!needsFlush) {198try {199timedOut = false;200/*201* Wait until we're woken up with a flushNow() call,202* or the timeout period elapses (so that we can203* flush the queue periodically).204*/205wait(100);206/*207* We will automatically flush the queue if the208* following conditions apply:209* - the wait() timed out210* - we can lock the queue (without blocking)211* - there is something in the queue to flush212* Otherwise, just continue (we'll flush eventually).213*/214if (!needsFlush && (timedOut = tryLock())) {215if (buf.position() > 0) {216needsFlush = true;217} else {218unlock();219}220}221} catch (InterruptedException e) {222}223}224try {225// reset the throwable state226error = null;227// flush the buffer now228flushBuffer();229// if there's a task, invoke that now as well230if (task != null) {231task.run();232}233} catch (Error e) {234error = e;235} catch (Exception x) {236System.err.println("exception in QueueFlusher:");237x.printStackTrace();238} finally {239if (timedOut) {240unlock();241}242task = null;243// allow the waiting thread to continue244needsFlush = false;245notify();246}247}248}249}250}251252253