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 
BufferedMaskBlit(RenderQueue rq, SurfaceType srcType, CompositeType compType, SurfaceType dstType)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
MaskBlit(SurfaceData src, SurfaceData dst, Composite comp, Region clip, int srcx, int srcy, int dstx, int dsty, int width, int height, byte[] mask, int maskoff, int maskscan)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 
enqueueTile(long buf, int bpos, SurfaceData srcData, long pSrcOps, int srcType, byte[] mask, int masklen, int maskoff, int maskscan, int srcx, int srcy, int dstx, int dsty, int width, int height)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      */
validateContext(SurfaceData dstData, Composite comp, Region clip)161     protected abstract void validateContext(SurfaceData dstData,
162                                             Composite comp, Region clip);
163 }
164