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