Path: blob/master/src/java.desktop/macosx/classes/sun/java2d/metal/MTLRenderQueue.java
41159 views
/*1* Copyright (c) 2007, 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.metal;2627import sun.awt.util.ThreadGroupUtils;28import sun.java2d.pipe.RenderBuffer;29import sun.java2d.pipe.RenderQueue;3031import java.security.AccessController;32import java.security.PrivilegedAction;3334import static sun.java2d.pipe.BufferedOpCodes.DISPOSE_CONFIG;35import static sun.java2d.pipe.BufferedOpCodes.SYNC;3637/**38* MTL-specific implementation of RenderQueue. This class provides a39* single (daemon) thread that is responsible for periodically flushing40* the queue, thus ensuring that only one thread communicates with the native41* OpenGL libraries for the entire process.42*/43public class MTLRenderQueue extends RenderQueue {4445private static MTLRenderQueue theInstance;46private final QueueFlusher flusher;4748@SuppressWarnings("removal")49private MTLRenderQueue() {50/*51* The thread must be a member of a thread group52* which will not get GCed before VM exit.53*/54flusher = AccessController.doPrivileged((PrivilegedAction<QueueFlusher>) QueueFlusher::new);55}5657/**58* Returns the single MTLRenderQueue instance. If it has not yet been59* initialized, this method will first construct the single instance60* before returning it.61*/62public static synchronized MTLRenderQueue getInstance() {63if (theInstance == null) {64theInstance = new MTLRenderQueue();65}66return theInstance;67}6869/**70* Flushes the single MTLRenderQueue instance synchronously. If an71* MTLRenderQueue has not yet been instantiated, this method is a no-op.72* This method is useful in the case of Toolkit.sync(), in which we want73* to flush the MTL pipeline, but only if the MTL pipeline is currently74* enabled. Since this class has few external dependencies, callers need75* not be concerned that calling this method will trigger initialization76* of the MTL pipeline and related classes.77*/78public static void sync() {79if (theInstance != null) {80theInstance.lock();81try {82theInstance.ensureCapacity(4);83theInstance.getBuffer().putInt(SYNC);84theInstance.flushNow();85} finally {86theInstance.unlock();87}88}89}9091/**92* Disposes the native memory associated with the given native93* graphics config info pointer on the single queue flushing thread.94*/95public static void disposeGraphicsConfig(long pConfigInfo) {96MTLRenderQueue rq = getInstance();97rq.lock();98try {99// make sure we make the context associated with the given100// GraphicsConfig current before disposing the native resources101MTLContext.setScratchSurface(pConfigInfo);102103RenderBuffer buf = rq.getBuffer();104rq.ensureCapacityAndAlignment(12, 4);105buf.putInt(DISPOSE_CONFIG);106buf.putLong(pConfigInfo);107108// this call is expected to complete synchronously, so flush now109rq.flushNow();110} finally {111rq.unlock();112}113}114115/**116* Returns true if the current thread is the MTL QueueFlusher thread.117*/118public static boolean isQueueFlusherThread() {119return (Thread.currentThread() == getInstance().flusher.thread);120}121122123@Override124public void flushNow() {125// assert lock.isHeldByCurrentThread();126try {127flusher.flushNow();128} catch (Exception e) {129System.err.println("exception in flushNow:");130e.printStackTrace();131}132}133134public void flushAndInvokeNow(Runnable r) {135// assert lock.isHeldByCurrentThread();136try {137flusher.flushAndInvokeNow(r);138} catch (Exception e) {139System.err.println("exception in flushAndInvokeNow:");140e.printStackTrace();141}142}143144private native void flushBuffer(long buf, int limit);145146private void flushBuffer() {147// assert lock.isHeldByCurrentThread();148int limit = buf.position();149if (limit > 0) {150// process the queue151flushBuffer(buf.getAddress(), limit);152}153// reset the buffer position154buf.clear();155// clear the set of references, since we no longer need them156refSet.clear();157}158159private class QueueFlusher implements Runnable {160private boolean needsFlush;161private Runnable task;162private Error error;163private final Thread thread;164165public QueueFlusher() {166String name = "Java2D Queue Flusher";167thread = new Thread(ThreadGroupUtils.getRootThreadGroup(),168this, name, 0, false);169thread.setDaemon(true);170thread.setPriority(Thread.MAX_PRIORITY);171thread.start();172}173174public synchronized void flushNow() {175// wake up the flusher176needsFlush = true;177notify();178179// wait for flush to complete180while (needsFlush) {181try {182wait();183} catch (InterruptedException e) {184}185}186187// re-throw any error that may have occurred during the flush188if (error != null) {189throw error;190}191}192193public synchronized void flushAndInvokeNow(Runnable task) {194this.task = task;195flushNow();196}197198public synchronized void run() {199boolean timedOut = false;200while (true) {201while (!needsFlush) {202try {203timedOut = false;204/*205* Wait until we're woken up with a flushNow() call,206* or the timeout period elapses (so that we can207* flush the queue periodically).208*/209wait(100);210/*211* We will automatically flush the queue if the212* following conditions apply:213* - the wait() timed out214* - we can lock the queue (without blocking)215* - there is something in the queue to flush216* Otherwise, just continue (we'll flush eventually).217*/218if (!needsFlush && (timedOut = tryLock())) {219if (buf.position() > 0) {220needsFlush = true;221} else {222unlock();223}224}225} catch (InterruptedException e) {226}227}228try {229// reset the throwable state230error = null;231// flush the buffer now232flushBuffer();233// if there's a task, invoke that now as well234if (task != null) {235task.run();236}237} catch (Error e) {238error = e;239} catch (Exception x) {240System.err.println("exception in QueueFlusher:");241x.printStackTrace();242} finally {243if (timedOut) {244unlock();245}246task = null;247// allow the waiting thread to continue248needsFlush = false;249notify();250}251}252}253}254}255256257