1 /*
   2  * Copyright (c) 2019, 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
  23  * questions.
  24  */
  25 
  26 package sun.java2d.metal;
  27 
  28 import sun.java2d.pipe.BufferedContext;
  29 import sun.java2d.pipe.RenderBuffer;
  30 import sun.java2d.pipe.RenderQueue;
  31 import sun.java2d.pipe.hw.ContextCapabilities;
  32 
  33 import java.lang.annotation.Native;
  34 
  35 import static sun.java2d.pipe.BufferedOpCodes.*;
  36 
  37 /**
  38  * Note that the RenderQueue lock must be acquired before calling any of
  39  * the methods in this class.
  40  */
  41 public class MTLContext extends BufferedContext {
  42 
  43     private final MTLGraphicsConfig config;
  44 
  45     public MTLContext(RenderQueue rq, MTLGraphicsConfig config) {
  46         super(rq);
  47         this.config = config;
  48     }
  49 
  50     /**
  51      * Convenience method that delegates to setScratchSurface() below.
  52      */
  53     static void setScratchSurface(MTLGraphicsConfig gc) {
  54         setScratchSurface(gc.getNativeConfigInfo());
  55     }
  56 
  57     /**
  58      * Makes the given GraphicsConfig's context current to its associated
  59      * "scratch surface".  Each GraphicsConfig maintains a native context
  60      * (MTLDevice) as well as a native pbuffer
  61      * known as the "scratch surface".  By making the context current to the
  62      * scratch surface, we are assured that we have a current context for
  63      * the relevant GraphicsConfig, and can therefore perform operations
  64      * depending on the capabilities of that GraphicsConfig.
  65      * This method should be used for operations with an MTL texture
  66      * as the destination surface (e.g. a sw->texture blit loop), or in those
  67      * situations where we may not otherwise have a current context (e.g.
  68      * when disposing a texture-based surface).
  69      */
  70     public static void setScratchSurface(long pConfigInfo) {
  71         // assert MTLRenderQueue.getInstance().lock.isHeldByCurrentThread();
  72 
  73         // invalidate the current context
  74         currentContext = null;
  75 
  76         // set the scratch context
  77         MTLRenderQueue rq = MTLRenderQueue.getInstance();
  78         RenderBuffer buf = rq.getBuffer();
  79         rq.ensureCapacityAndAlignment(12, 4);
  80         buf.putInt(SET_SCRATCH_SURFACE);
  81         buf.putLong(pConfigInfo);
  82     }
  83 
  84     /**
  85      * Invalidates the currentContext field to ensure that we properly
  86      * revalidate the MTLContext (make it current, etc.) next time through
  87      * the validate() method.  This is typically invoked from methods
  88      * that affect the current context state (e.g. disposing a context or
  89      * surface).
  90      */
  91     public static void invalidateCurrentContext() {
  92         // assert MTLRenderQueue.getInstance().lock.isHeldByCurrentThread();
  93 
  94         // invalidate the current Java-level context so that we
  95         // revalidate everything the next time around
  96         if (currentContext != null) {
  97             currentContext.invalidateContext();
  98             currentContext = null;
  99         }
 100 
 101         // invalidate the context reference at the native level, and
 102         // then flush the queue so that we have no pending operations
 103         // dependent on the current context
 104         MTLRenderQueue rq = MTLRenderQueue.getInstance();
 105         rq.ensureCapacity(4);
 106         rq.getBuffer().putInt(INVALIDATE_CONTEXT);
 107         rq.flushNow();
 108     }
 109 
 110     public RenderQueue getRenderQueue() {
 111         return MTLRenderQueue.getInstance();
 112     }
 113 
 114     /**
 115      * Returns a string representing adapter id (vendor, renderer, version).
 116      * Must be called on the rendering thread.
 117      *
 118      * @return an id string for the adapter
 119      */
 120     public static final native String getMTLIdString();
 121 
 122     @Override
 123     public void saveState() {
 124         // assert rq.lock.isHeldByCurrentThread();
 125 
 126         // reset all attributes of this and current contexts
 127         invalidateContext();
 128         invalidateCurrentContext();
 129 
 130         setScratchSurface(config);
 131 
 132         // save the state on the native level
 133         rq.ensureCapacity(4);
 134         buf.putInt(SAVE_STATE);
 135         rq.flushNow();
 136     }
 137 
 138     @Override
 139     public void restoreState() {
 140         // assert rq.lock.isHeldByCurrentThread();
 141 
 142         // reset all attributes of this and current contexts
 143         invalidateContext();
 144         invalidateCurrentContext();
 145 
 146         setScratchSurface(config);
 147 
 148         // restore the state on the native level
 149         rq.ensureCapacity(4);
 150         buf.putInt(RESTORE_STATE);
 151         rq.flushNow();
 152     }
 153 
 154     public static class MTLContextCaps extends ContextCapabilities {
 155         /**
 156          * This cap will only be set if the fbobject system property has been
 157          * enabled and we are able to create an FBO with depth buffer.
 158          */
 159         @Native
 160         public static final int CAPS_EXT_FBOBJECT     =
 161                 (CAPS_RT_TEXTURE_ALPHA | CAPS_RT_TEXTURE_OPAQUE);
 162         /** Indicates that the context is doublebuffered. */
 163         @Native
 164         public static final int CAPS_DOUBLEBUFFERED   = (FIRST_PRIVATE_CAP << 0);
 165         /**
 166          * This cap will only be set if the lcdshader system property has been
 167          * enabled and the hardware supports the minimum number of texture units
 168          */
 169         @Native
 170         static final int CAPS_EXT_LCD_SHADER   = (FIRST_PRIVATE_CAP << 1);
 171         /**
 172          * This cap will only be set if the biopshader system property has been
 173          * enabled and the hardware meets our minimum requirements.
 174          */
 175         @Native
 176         static final int CAPS_EXT_BIOP_SHADER  = (FIRST_PRIVATE_CAP << 2);
 177         /**
 178          * This cap will only be set if the gradshader system property has been
 179          * enabled and the hardware meets our minimum requirements.
 180          */
 181         @Native
 182         static final int CAPS_EXT_GRAD_SHADER  = (FIRST_PRIVATE_CAP << 3);
 183         /** Indicates the presence of the GL_ARB_texture_rectangle extension. */
 184         @Native
 185         static final int CAPS_EXT_TEXRECT      = (FIRST_PRIVATE_CAP << 4);
 186         /** Indicates the presence of the GL_NV_texture_barrier extension. */
 187         @Native
 188         static final int CAPS_EXT_TEXBARRIER = (FIRST_PRIVATE_CAP << 5);
 189 
 190 
 191         public MTLContextCaps(int caps, String adapterId) {
 192             super(caps, adapterId);
 193         }
 194 
 195         @Override
 196         public String toString() {
 197             StringBuilder sb = new StringBuilder(super.toString());
 198             if ((caps & CAPS_EXT_FBOBJECT) != 0) {
 199                 sb.append("CAPS_EXT_FBOBJECT|");
 200             }
 201             if ((caps & CAPS_DOUBLEBUFFERED) != 0) {
 202                 sb.append("CAPS_DOUBLEBUFFERED|");
 203             }
 204             if ((caps & CAPS_EXT_LCD_SHADER) != 0) {
 205                 sb.append("CAPS_EXT_LCD_SHADER|");
 206             }
 207             if ((caps & CAPS_EXT_BIOP_SHADER) != 0) {
 208                 sb.append("CAPS_BIOP_SHADER|");
 209             }
 210             if ((caps & CAPS_EXT_GRAD_SHADER) != 0) {
 211                 sb.append("CAPS_EXT_GRAD_SHADER|");
 212             }
 213             if ((caps & CAPS_EXT_TEXRECT) != 0) {
 214                 sb.append("CAPS_EXT_TEXRECT|");
 215             }
 216             if ((caps & CAPS_EXT_TEXBARRIER) != 0) {
 217                 sb.append("CAPS_EXT_TEXBARRIER|");
 218             }
 219             return sb.toString();
 220         }
 221     }
 222 }