--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/macosx/classes/sun/java2d/metal/MetalRenderQueue.java Wed Feb 20 17:00:40 2019 +0530
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2019, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.java2d.metal;
+
+import sun.awt.util.ThreadGroupUtils;
+import sun.java2d.pipe.RenderBuffer;
+import sun.java2d.pipe.RenderQueue;
+
+import static sun.java2d.pipe.BufferedOpCodes.*;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * OGL-specific implementation of RenderQueue. This class provides a
+ * single (daemon) thread that is responsible for periodically flushing
+ * the queue, thus ensuring that only one thread communicates with the native
+ * OpenGL libraries for the entire process.
+ */
+public class MetalRenderQueue extends RenderQueue {
+
+ private static MetalRenderQueue theInstance;
+ private final QueueFlusher flusher;
+
+ private MetalRenderQueue() {
+ /*
+ * The thread must be a member of a thread group
+ * which will not get GCed before VM exit.
+ */
+ flusher = AccessController.doPrivileged((PrivilegedAction<QueueFlusher>) QueueFlusher::new);
+ }
+
+ /**
+ * Returns the single OGLRenderQueue instance. If it has not yet been
+ * initialized, this method will first construct the single instance
+ * before returning it.
+ */
+ public static synchronized MetalRenderQueue getInstance() {
+ if (theInstance == null) {
+ theInstance = new MetalRenderQueue();
+ }
+ return theInstance;
+ }
+
+ /**
+ * Flushes the single OGLRenderQueue instance synchronously. If an
+ * OGLRenderQueue has not yet been instantiated, this method is a no-op.
+ * This method is useful in the case of Toolkit.sync(), in which we want
+ * to flush the OGL pipeline, but only if the OGL pipeline is currently
+ * enabled. Since this class has few external dependencies, callers need
+ * not be concerned that calling this method will trigger initialization
+ * of the OGL pipeline and related classes.
+ */
+ public static void sync() {
+ if (theInstance != null) {
+ theInstance.lock();
+ try {
+ theInstance.ensureCapacity(4);
+ theInstance.getBuffer().putInt(SYNC);
+ theInstance.flushNow();
+ } finally {
+ theInstance.unlock();
+ }
+ }
+ }
+
+ /**
+ * Disposes the native memory associated with the given native
+ * graphics config info pointer on the single queue flushing thread.
+ */
+ public static void disposeGraphicsConfig(long pConfigInfo) {
+ MetalRenderQueue rq = getInstance();
+ rq.lock();
+ try {
+ // make sure we make the context associated with the given
+ // GraphicsConfig current before disposing the native resources
+ MetalContext.setScratchSurface(pConfigInfo);
+
+ RenderBuffer buf = rq.getBuffer();
+ rq.ensureCapacityAndAlignment(12, 4);
+ buf.putInt(DISPOSE_CONFIG);
+ buf.putLong(pConfigInfo);
+
+ // this call is expected to complete synchronously, so flush now
+ rq.flushNow();
+ } finally {
+ rq.unlock();
+ }
+ }
+
+ /**
+ * Returns true if the current thread is the OGL QueueFlusher thread.
+ */
+ public static boolean isQueueFlusherThread() {
+ return (Thread.currentThread() == getInstance().flusher.thread);
+ }
+
+ public void flushNow() {
+ // assert lock.isHeldByCurrentThread();
+ try {
+ flusher.flushNow();
+ } catch (Exception e) {
+ System.err.println("exception in flushNow:");
+ e.printStackTrace();
+ }
+ }
+
+ public void flushAndInvokeNow(Runnable r) {
+ // assert lock.isHeldByCurrentThread();
+ try {
+ flusher.flushAndInvokeNow(r);
+ } catch (Exception e) {
+ System.err.println("exception in flushAndInvokeNow:");
+ e.printStackTrace();
+ }
+ }
+
+ private native long flushBuffer(long buf, int limit);
+
+ private void flushBuffer() {
+
+ // assert lock.isHeldByCurrentThread();
+ int limit = buf.position();
+ if (limit > 0) {
+ System.out.println("FlushBuffer ---------- invoking RQ native flushBuffer");
+
+ // process the queue
+ flushBuffer(buf.getAddress(), limit);
+ }
+ // reset the buffer position
+ buf.clear();
+ // clear the set of references, since we no longer need them
+ refSet.clear();
+ }
+
+ private class QueueFlusher implements Runnable {
+ private boolean needsFlush;
+ private Runnable task;
+ private Error error;
+ private final Thread thread;
+
+ public QueueFlusher() {
+ String name = "Java2D Queue Flusher";
+ thread = new Thread(ThreadGroupUtils.getRootThreadGroup(),
+ this, name, 0, false);
+ thread.setDaemon(true);
+ thread.setPriority(Thread.MAX_PRIORITY);
+ thread.start();
+ }
+
+ public synchronized void flushNow() {
+ // wake up the flusher
+ needsFlush = true;
+ System.out.println("****** QueueFlusher : about to notify flusher thread");
+ notify();
+
+ // wait for flush to complete
+ while (needsFlush) {
+ try {
+
+ System.out.println("****** QueueFlusher : waiting for flush to complete");
+ wait();
+ } catch (InterruptedException e) {
+ }
+ }
+
+ // re-throw any error that may have occurred during the flush
+ if (error != null) {
+ throw error;
+ }
+ }
+
+ public synchronized void flushAndInvokeNow(Runnable task) {
+ this.task = task;
+ flushNow();
+ }
+
+ public synchronized void run() {
+ boolean timedOut = false;
+ while (true) {
+ while (!needsFlush) {
+ try {
+ timedOut = false;
+ /*
+ * Wait until we're woken up with a flushNow() call,
+ * or the timeout period elapses (so that we can
+ * flush the queue periodically).
+ */
+ wait(100);
+ /*
+ * We will automatically flush the queue if the
+ * following conditions apply:
+ * - the wait() timed out
+ * - we can lock the queue (without blocking)
+ * - there is something in the queue to flush
+ * Otherwise, just continue (we'll flush eventually).
+ */
+ if (!needsFlush && (timedOut = tryLock())) {
+ if (buf.position() > 0) {
+ needsFlush = true;
+ } else {
+ unlock();
+ }
+ }
+ } catch (InterruptedException e) {
+ }
+ }
+ try {
+ // reset the throwable state
+ error = null;
+ // flush the buffer now
+
+ System.out.println("Thread invoking flushBuffer -------------- ");
+ flushBuffer();
+ // if there's a task, invoke that now as well
+ if (task != null) {
+ task.run();
+ }
+ } catch (Error e) {
+ error = e;
+ } catch (Exception x) {
+ System.err.println("exception in QueueFlusher:");
+ x.printStackTrace();
+ } finally {
+ if (timedOut) {
+ unlock();
+ }
+ task = null;
+ // allow the waiting thread to continue
+ needsFlush = false;
+ notify();
+ }
+ }
+ }
+ }
+}