提交 3d1817a9 编写于 作者: S serb

8059942: Default implementation of DrawImage.renderImageXform() should be improved for d3d/ogl

Reviewed-by: flar, prr
上级 e25021c4
......@@ -364,8 +364,53 @@ public class DrawImage implements DrawImagePipe
int sx1, int sy1, int sx2, int sy2,
Color bgColor)
{
final AffineTransform itx;
try {
itx = tx.createInverse();
} catch (final NoninvertibleTransformException ignored) {
// Non-invertible transform means no output
return;
}
/*
* Find the maximum bounds on the destination that will be
* affected by the transformed source. First, transform all
* four corners of the source and then min and max the resulting
* destination coordinates of the transformed corners.
* Note that tx already has the offset to sx1,sy1 accounted
* for so we use the box (0, 0, sx2-sx1, sy2-sy1) as the
* source coordinates.
*/
final double[] coords = new double[8];
/* corner: UL UR LL LR */
/* index: 0 1 2 3 4 5 6 7 */
/* coord: (0, 0), (w, 0), (0, h), (w, h) */
coords[2] = coords[6] = sx2 - sx1;
coords[5] = coords[7] = sy2 - sy1;
tx.transform(coords, 0, coords, 0, 4);
double ddx1, ddy1, ddx2, ddy2;
ddx1 = ddx2 = coords[0];
ddy1 = ddy2 = coords[1];
for (int i = 2; i < coords.length; i += 2) {
double d = coords[i];
if (ddx1 > d) ddx1 = d;
else if (ddx2 < d) ddx2 = d;
d = coords[i+1];
if (ddy1 > d) ddy1 = d;
else if (ddy2 < d) ddy2 = d;
}
Region clip = sg.getCompClip();
SurfaceData dstData = sg.surfaceData;
final int dx1 = Math.max((int) Math.floor(ddx1), clip.lox);
final int dy1 = Math.max((int) Math.floor(ddy1), clip.loy);
final int dx2 = Math.min((int) Math.ceil(ddx2), clip.hix);
final int dy2 = Math.min((int) Math.ceil(ddy2), clip.hiy);
if (dx2 <= dx1 || dy2 <= dy1) {
// empty destination means no output
return;
}
final SurfaceData dstData = sg.surfaceData;
SurfaceData srcData = dstData.getSourceSurfaceData(img,
SunGraphics2D.TRANSFORM_GENERIC,
sg.imageComp,
......@@ -429,56 +474,13 @@ public class DrawImage implements DrawImagePipe
// assert(helper != null);
}
AffineTransform itx;
try {
itx = tx.createInverse();
} catch (NoninvertibleTransformException e) {
// Non-invertible transform means no output
return;
}
/*
* Find the maximum bounds on the destination that will be
* affected by the transformed source. First, transform all
* four corners of the source and then min and max the resulting
* destination coordinates of the transformed corners.
* Note that tx already has the offset to sx1,sy1 accounted
* for so we use the box (0, 0, sx2-sx1, sy2-sy1) as the
* source coordinates.
*/
double coords[] = new double[8];
/* corner: UL UR LL LR */
/* index: 0 1 2 3 4 5 6 7 */
/* coord: (0, 0), (w, 0), (0, h), (w, h) */
coords[2] = coords[6] = sx2 - sx1;
coords[5] = coords[7] = sy2 - sy1;
tx.transform(coords, 0, coords, 0, 4);
double ddx1, ddy1, ddx2, ddy2;
ddx1 = ddx2 = coords[0];
ddy1 = ddy2 = coords[1];
for (int i = 2; i < coords.length; i += 2) {
double d = coords[i];
if (ddx1 > d) ddx1 = d;
else if (ddx2 < d) ddx2 = d;
d = coords[i+1];
if (ddy1 > d) ddy1 = d;
else if (ddy2 < d) ddy2 = d;
}
int dx1 = (int) Math.floor(ddx1);
int dy1 = (int) Math.floor(ddy1);
int dx2 = (int) Math.ceil(ddx2);
int dy2 = (int) Math.ceil(ddy2);
SurfaceType dstType = dstData.getSurfaceType();
MaskBlit maskblit;
Blit blit;
if (sg.compositeState <= SunGraphics2D.COMP_ALPHA) {
/* NOTE: We either have, or we can make,
* a MaskBlit for any alpha composite type
*/
maskblit = MaskBlit.getFromCache(SurfaceType.IntArgbPre,
sg.imageComp,
dstType);
MaskBlit maskblit = MaskBlit.getFromCache(SurfaceType.IntArgbPre,
sg.imageComp, dstType);
/* NOTE: We can only use the native TransformHelper
* func to go directly to the dest if both the helper
......@@ -496,27 +498,19 @@ public class DrawImage implements DrawImagePipe
null, 0, 0);
return;
}
blit = null;
} else {
/* NOTE: We either have, or we can make,
* a Blit for any composite type, even Custom
*/
maskblit = null;
blit = Blit.getFromCache(SurfaceType.IntArgbPre,
sg.imageComp,
dstType);
}
// We need to transform to a temp image and then copy
// just the pieces that are valid data to the dest.
BufferedImage tmpimg = new BufferedImage(dx2-dx1, dy2-dy1,
final int w = dx2 - dx1;
final int h = dy2 - dy1;
BufferedImage tmpimg = new BufferedImage(w, h,
BufferedImage.TYPE_INT_ARGB_PRE);
SurfaceData tmpData = SurfaceData.getPrimarySurfaceData(tmpimg);
SurfaceType tmpType = tmpData.getSurfaceType();
MaskBlit tmpmaskblit =
MaskBlit.getFromCache(SurfaceType.IntArgbPre,
CompositeType.SrcNoEa,
tmpType);
MaskBlit tmpmaskblit = MaskBlit.getFromCache(SurfaceType.IntArgbPre,
CompositeType.SrcNoEa,
tmpType);
/*
* The helper function fills a temporary edges buffer
* for us with the bounding coordinates of each scanline
......@@ -531,7 +525,7 @@ public class DrawImage implements DrawImagePipe
*
* edges thus has to be h*2+2 in length
*/
int edges[] = new int[(dy2-dy1)*2+2];
final int[] edges = new int[h * 2 + 2];
// It is important that edges[0]=edges[1]=0 when we call
// Transform in case it must return early and we would
// not want to render anything on an error condition.
......@@ -539,35 +533,17 @@ public class DrawImage implements DrawImagePipe
AlphaComposite.Src, null,
itx, interpType,
sx1, sy1, sx2, sy2,
0, 0, dx2-dx1, dy2-dy1,
0, 0, w, h,
edges, dx1, dy1);
/*
* Now copy the results, scanline by scanline, into the dest.
* The edges array helps us minimize the work.
final Region region = Region.getInstance(dx1, dy1, dx2, dy2, edges);
clip = clip.getIntersection(region);
/* NOTE: We either have, or we can make,
* a Blit for any composite type, even Custom
*/
int index = 2;
for (int y = edges[0]; y < edges[1]; y++) {
int relx1 = edges[index++];
int relx2 = edges[index++];
if (relx1 >= relx2) {
continue;
}
if (maskblit != null) {
maskblit.MaskBlit(tmpData, dstData,
sg.composite, clip,
relx1, y,
dx1+relx1, dy1+y,
relx2 - relx1, 1,
null, 0, 0);
} else {
blit.Blit(tmpData, dstData,
sg.composite, clip,
relx1, y,
dx1+relx1, dy1+y,
relx2 - relx1, 1);
}
}
final Blit blit = Blit.getFromCache(tmpType, sg.imageComp, dstType);
blit.Blit(tmpData, dstData, sg.composite, clip, 0, 0, dx1, dy1, w, h);
}
// Render an image using only integer translation
......
......@@ -30,6 +30,8 @@ import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.RectangularShape;
import sun.java2d.loops.TransformHelper;
/**
* This class encapsulates a definition of a two dimensional region which
* consists of a number of Y ranges each containing multiple X bands.
......@@ -160,6 +162,15 @@ public class Region {
this.hiy = hiy;
}
private Region(int lox, int loy, int hix, int hiy, int[] bands, int end) {
this.lox = lox;
this.loy = loy;
this.hix = hix;
this.hiy = hiy;
this.bands = bands;
this.endIndex = end;
}
/**
* Returns a Region object covering the pixels which would be
* touched by a fill or clip operation on a Graphics implementation
......@@ -255,6 +266,44 @@ public class Region {
}
}
/**
* Returns a Region object with a rectangle of interest specified by the
* indicated rectangular area in lox, loy, hix, hiy and edges array, which
* is located relative to the rectangular area. Edges array - 0,1 are y
* range, 2N,2N+1 are x ranges, 1 per y range.
*
* @see TransformHelper
*/
static Region getInstance(final int lox, final int loy, final int hix,
final int hiy, final int[] edges) {
final int y1 = edges[0];
final int y2 = edges[1];
if (hiy <= loy || hix <= lox || y2 <= y1) {
return EMPTY_REGION;
}
// rowsNum * (3 + 1 * 2)
final int[] bands = new int[(y2 - y1) * 5];
int end = 0;
int index = 2;
for (int y = y1; y < y2; ++y) {
final int spanlox = Math.max(clipAdd(lox, edges[index++]), lox);
final int spanhix = Math.min(clipAdd(lox, edges[index++]), hix);
if (spanlox < spanhix) {
final int spanloy = Math.max(clipAdd(loy, y), loy);
final int spanhiy = Math.min(clipAdd(spanloy, 1), hiy);
if (spanloy < spanhiy) {
bands[end++] = spanloy;
bands[end++] = spanhiy;
bands[end++] = 1; // 1 span per row
bands[end++] = spanlox;
bands[end++] = spanhix;
}
}
}
return end != 0 ? new Region(lox, loy, hix, hiy, bands, end)
: EMPTY_REGION;
}
/**
* Returns a Region object with a rectangle of interest specified
* by the indicated Rectangle object.
......
/*
* Copyright (c) 2014, 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.
*
* 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.
*/
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferInt;
import java.awt.image.DataBufferShort;
import java.awt.image.VolatileImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import static java.awt.Transparency.TRANSLUCENT;
import static java.awt.image.BufferedImage.TYPE_INT_ARGB;
/**
* @test
* @bug 8059942
* @summary Tests rotated clip when unmanaged image is drawn to VI.
* Results of the blit to compatibleImage are used for comparison.
* @author Sergey Bylokhov
*/
public final class IncorrectUnmanagedImageRotatedClip {
public static void main(final String[] args) throws IOException {
BufferedImage bi = makeUnmanagedBI();
fill(bi);
test(bi);
}
private static void test(final BufferedImage bi) throws IOException {
GraphicsEnvironment ge = GraphicsEnvironment
.getLocalGraphicsEnvironment();
GraphicsConfiguration gc = ge.getDefaultScreenDevice()
.getDefaultConfiguration();
VolatileImage vi = gc.createCompatibleVolatileImage(500, 200,
TRANSLUCENT);
BufferedImage gold = gc.createCompatibleImage(500, 200, TRANSLUCENT);
// draw to compatible Image
draw(bi, gold);
// draw to volatile image
int attempt = 0;
BufferedImage snapshot;
while (true) {
if (++attempt > 10) {
throw new RuntimeException("Too many attempts: " + attempt);
}
vi.validate(gc);
if (vi.validate(gc) != VolatileImage.IMAGE_OK) {
continue;
}
draw(bi, vi);
snapshot = vi.getSnapshot();
if (vi.contentsLost()) {
continue;
}
break;
}
// validate images
for (int x = 0; x < gold.getWidth(); ++x) {
for (int y = 0; y < gold.getHeight(); ++y) {
if (gold.getRGB(x, y) != snapshot.getRGB(x, y)) {
ImageIO.write(gold, "png", new File("gold.png"));
ImageIO.write(snapshot, "png", new File("bi.png"));
throw new RuntimeException("Test failed.");
}
}
}
}
private static void draw(final BufferedImage from,final Image to) {
final Graphics2D g2d = (Graphics2D) to.getGraphics();
g2d.setComposite(AlphaComposite.Src);
g2d.setColor(Color.ORANGE);
g2d.fillRect(0, 0, to.getWidth(null), to.getHeight(null));
g2d.rotate(Math.toRadians(45));
g2d.clip(new Rectangle(41, 42, 43, 44));
g2d.drawImage(from, 50, 50, Color.blue, null);
g2d.dispose();
}
private static BufferedImage makeUnmanagedBI() {
final BufferedImage bi = new BufferedImage(500, 200, TYPE_INT_ARGB);
final DataBuffer db = bi.getRaster().getDataBuffer();
if (db instanceof DataBufferInt) {
((DataBufferInt) db).getData();
} else if (db instanceof DataBufferShort) {
((DataBufferShort) db).getData();
} else if (db instanceof DataBufferByte) {
((DataBufferByte) db).getData();
} else {
try {
bi.setAccelerationPriority(0.0f);
} catch (final Throwable ignored) {
}
}
return bi;
}
private static void fill(final Image image) {
final Graphics2D graphics = (Graphics2D) image.getGraphics();
graphics.setComposite(AlphaComposite.Src);
for (int i = 0; i < image.getHeight(null); ++i) {
graphics.setColor(new Color(i, 0, 0));
graphics.fillRect(0, i, image.getWidth(null), 1);
}
graphics.dispose();
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册