View Javadoc
1   /*
2    * Copyright (c) 2007, 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.pipe;
27  
28  import java.awt.AlphaComposite;
29  import java.awt.Composite;
30  import sun.java2d.SurfaceData;
31  import sun.java2d.loops.Blit;
32  import sun.java2d.loops.CompositeType;
33  import sun.java2d.loops.MaskBlit;
34  import sun.java2d.loops.SurfaceType;
35  import static sun.java2d.pipe.BufferedOpCodes.*;
36  
37  /**
38   * The MaskBlit operation is expressed as:
39   *   dst = ((src <MODE> dst) * pathA) + (dst * (1 - pathA))
40   *
41   * The OGL/D3D implementation of the MaskBlit operation differs from the above
42   * equation because it is not possible to perform such a complex operation in
43   * OpenGL/Direct3D (without the use of advanced techniques like fragment
44   * shaders and multitexturing).  Therefore, the BufferedMaskBlit operation
45   * is expressed as:
46   *   dst = (src * pathA) <SrcOver> dst
47   *
48   * This simplified formula is only equivalent to the "true" MaskBlit equation
49   * in the following situations:
50   *   - <MODE> is SrcOver
51   *   - <MODE> is Src, extra alpha == 1.0, and the source surface is opaque
52   *
53   * Therefore, we register BufferedMaskBlit primitives for only the SurfaceType
54   * and CompositeType restrictions mentioned above.  In addition for the Src
55   * case, we must override the composite with a SrcOver (no extra alpha)
56   * instance, so that we set up the OpenGL/Direct3D blending mode to match the
57   * BufferedMaskBlit equation.
58   */
59  public abstract class BufferedMaskBlit extends MaskBlit {
60  
61      private static final int ST_INT_ARGB     = 0;
62      private static final int ST_INT_ARGB_PRE = 1;
63      private static final int ST_INT_RGB      = 2;
64      private static final int ST_INT_BGR      = 3;
65  
66      private final RenderQueue rq;
67      private final int srcTypeVal;
68      private Blit blitop;
69  
70      protected BufferedMaskBlit(RenderQueue rq,
71                                 SurfaceType srcType,
72                                 CompositeType compType,
73                                 SurfaceType dstType)
74      {
75          super(srcType, compType, dstType);
76          this.rq = rq;
77          if (srcType == SurfaceType.IntArgb) {
78              this.srcTypeVal = ST_INT_ARGB;
79          } else if (srcType == SurfaceType.IntArgbPre) {
80              this.srcTypeVal = ST_INT_ARGB_PRE;
81          } else if (srcType == SurfaceType.IntRgb) {
82              this.srcTypeVal = ST_INT_RGB;
83          } else if (srcType == SurfaceType.IntBgr) {
84              this.srcTypeVal = ST_INT_BGR;
85          } else {
86              throw new InternalError("unrecognized source surface type");
87          }
88      }
89  
90      @Override
91      public void MaskBlit(SurfaceData src, SurfaceData dst,
92                           Composite comp, Region clip,
93                           int srcx, int srcy,
94                           int dstx, int dsty,
95                           int width, int height,
96                           byte[] mask, int maskoff, int maskscan)
97      {
98          if (width <= 0 || height <= 0) {
99              return;
100         }
101 
102         if (mask == null) {
103             // no mask involved; delegate to regular blit loop
104             if (blitop == null) {
105                 blitop = Blit.getFromCache(src.getSurfaceType(),
106                                            CompositeType.AnyAlpha,
107                                            this.getDestType());
108             }
109             blitop.Blit(src, dst,
110                         comp, clip,
111                         srcx, srcy, dstx, dsty,
112                         width, height);
113             return;
114         }
115 
116         AlphaComposite acomp = (AlphaComposite)comp;
117         if (acomp.getRule() != AlphaComposite.SRC_OVER) {
118             comp = AlphaComposite.SrcOver;
119         }
120 
121         rq.lock();
122         try {
123             validateContext(dst, comp, clip);
124 
125             RenderBuffer buf = rq.getBuffer();
126             int totalBytesRequired = 20 + (width * height * 4);
127 
128             /*
129              * REMIND: we should fix this so that it works with tiles that
130              *         are larger than the entire buffer, but the native
131              *         OGL/D3DMaskBlit isn't even prepared for tiles larger
132              *         than 32x32 pixels, so there's no urgency here...
133              */
134             rq.ensureCapacity(totalBytesRequired);
135 
136             // enqueue parameters and tile pixels
137             int newpos = enqueueTile(buf.getAddress(), buf.position(),
138                                      src, src.getNativeOps(), srcTypeVal,
139                                      mask, mask.length, maskoff, maskscan,
140                                      srcx, srcy, dstx, dsty,
141                                      width, height);
142 
143             buf.position(newpos);
144         } finally {
145             rq.unlock();
146         }
147     }
148 
149     private native int enqueueTile(long buf, int bpos,
150                                    SurfaceData srcData,
151                                    long pSrcOps, int srcType,
152                                    byte[] mask, int masklen,
153                                    int maskoff, int maskscan,
154                                    int srcx, int srcy, int dstx, int dsty,
155                                    int width, int height);
156 
157     /**
158      * Validates the context state using the given destination surface
159      * and composite/clip values.
160      */
161     protected abstract void validateContext(SurfaceData dstData,
162                                             Composite comp, Region clip);
163 }