提交 77c85e32 编写于 作者: S serb

8041129: [OGL] surface->sw blit is extremely slow

8017626: [OGL] Translucent VolatileImages don't paint correctly
Reviewed-by: bae, flar
上级 12626b54
/* /*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -71,6 +71,8 @@ class OGLBlitLoops { ...@@ -71,6 +71,8 @@ class OGLBlitLoops {
// surface->sw ops // surface->sw ops
new OGLSurfaceToSwBlit(SurfaceType.IntArgb, new OGLSurfaceToSwBlit(SurfaceType.IntArgb,
OGLSurfaceData.PF_INT_ARGB), OGLSurfaceData.PF_INT_ARGB),
new OGLSurfaceToSwBlit(SurfaceType.IntArgbPre,
OGLSurfaceData.PF_INT_ARGB_PRE),
// sw->surface ops // sw->surface ops
blitIntArgbPreToSurface, blitIntArgbPreToSurface,
...@@ -505,12 +507,12 @@ class OGLRTTSurfaceToSurfaceTransform extends TransformBlit { ...@@ -505,12 +507,12 @@ class OGLRTTSurfaceToSurfaceTransform extends TransformBlit {
} }
} }
class OGLSurfaceToSwBlit extends Blit { final class OGLSurfaceToSwBlit extends Blit {
private int typeval; private final int typeval;
// REMIND: destination will actually be opaque/premultiplied... // destination will actually be ArgbPre or Argb
OGLSurfaceToSwBlit(SurfaceType dstType, int typeval) { OGLSurfaceToSwBlit(final SurfaceType dstType,final int typeval) {
super(OGLSurfaceData.OpenGLSurface, super(OGLSurfaceData.OpenGLSurface,
CompositeType.SrcNoEa, CompositeType.SrcNoEa,
dstType); dstType);
......
/* /*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -34,6 +34,10 @@ ...@@ -34,6 +34,10 @@
#include "OGLSurfaceData.h" #include "OGLSurfaceData.h"
#include "GraphicsPrimitiveMgr.h" #include "GraphicsPrimitiveMgr.h"
#include <stdlib.h> // malloc
#include <string.h> // memcpy
#include "IntArgbPre.h"
extern OGLPixelFormat PixelFormats[]; extern OGLPixelFormat PixelFormats[];
/** /**
...@@ -335,6 +339,9 @@ OGLBlitToSurfaceViaTexture(OGLContext *oglc, SurfaceDataRasInfo *srcInfo, ...@@ -335,6 +339,9 @@ OGLBlitToSurfaceViaTexture(OGLContext *oglc, SurfaceDataRasInfo *srcInfo,
0, 0, sw, sh, 0, 0, sw, sh,
pf->format, pf->type, pf->format, pf->type,
srcInfo->rasBase); srcInfo->rasBase);
j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
} }
// the texture image is "right side up", so we align the // the texture image is "right side up", so we align the
...@@ -696,6 +703,50 @@ OGLBlitLoops_Blit(JNIEnv *env, ...@@ -696,6 +703,50 @@ OGLBlitLoops_Blit(JNIEnv *env,
SurfaceData_InvokeUnlock(env, srcOps, &srcInfo); SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
} }
/**
* This method makes vertical flip of the provided area of Surface and convert
* pixel's data from argbPre to argb format if requested.
*/
void flip(void *pDst, juint w, juint h, jint scanStride, jboolean convert) {
const size_t clippedStride = 4 * w;
void *tempRow = (h > 1 && !convert) ? malloc(clippedStride) : NULL;
juint i = 0;
juint step = 0;
// vertical flip and convert argbpre to argb if necessary
for (; i < h / 2; ++i) {
juint *r1 = PtrAddBytes(pDst, (i * scanStride));
juint *r2 = PtrAddBytes(pDst, (h - i - 1) * scanStride);
if (tempRow) {
// fast path
memcpy(tempRow, r1, clippedStride);
memcpy(r1, r2, clippedStride);
memcpy(r2, tempRow, clippedStride);
} else {
// slow path
for (step = 0; step < w; ++step) {
juint tmp = r1[step];
if (convert) {
LoadIntArgbPreTo1IntArgb(r2, 0, step, r1[step]);
LoadIntArgbPreTo1IntArgb(&tmp, 0, 0, r2[step]);
} else {
r1[step] = r2[step];
r2[step] = tmp;
}
}
}
}
// convert the middle line if necessary
if (convert && h % 2) {
juint *r1 = PtrAddBytes(pDst, (i * scanStride));
for (step = 0; step < w; ++step) {
LoadIntArgbPreTo1IntArgb(r1, 0, step, r1[step]);
}
}
if (tempRow) {
free(tempRow);
}
}
/** /**
* Specialized blit method for copying a native OpenGL "Surface" (pbuffer, * Specialized blit method for copying a native OpenGL "Surface" (pbuffer,
* window, etc.) to a system memory ("Sw") surface. * window, etc.) to a system memory ("Sw") surface.
...@@ -758,7 +809,9 @@ OGLBlitLoops_SurfaceToSwBlit(JNIEnv *env, OGLContext *oglc, ...@@ -758,7 +809,9 @@ OGLBlitLoops_SurfaceToSwBlit(JNIEnv *env, OGLContext *oglc,
width = srcInfo.bounds.x2 - srcInfo.bounds.x1; width = srcInfo.bounds.x2 - srcInfo.bounds.x1;
height = srcInfo.bounds.y2 - srcInfo.bounds.y1; height = srcInfo.bounds.y2 - srcInfo.bounds.y1;
j2d_glPixelStorei(GL_PACK_SKIP_PIXELS, dstx); pDst = PtrAddBytes(pDst, dstx * dstInfo.pixelStride);
pDst = PtrAddBytes(pDst, dsty * dstInfo.scanStride);
j2d_glPixelStorei(GL_PACK_ROW_LENGTH, j2d_glPixelStorei(GL_PACK_ROW_LENGTH,
dstInfo.scanStride / dstInfo.pixelStride); dstInfo.scanStride / dstInfo.pixelStride);
j2d_glPixelStorei(GL_PACK_ALIGNMENT, pf.alignment); j2d_glPixelStorei(GL_PACK_ALIGNMENT, pf.alignment);
...@@ -779,27 +832,20 @@ OGLBlitLoops_SurfaceToSwBlit(JNIEnv *env, OGLContext *oglc, ...@@ -779,27 +832,20 @@ OGLBlitLoops_SurfaceToSwBlit(JNIEnv *env, OGLContext *oglc,
// this accounts for lower-left origin of the source region // this accounts for lower-left origin of the source region
srcx = srcOps->xOffset + srcx; srcx = srcOps->xOffset + srcx;
srcy = srcOps->yOffset + srcOps->height - (srcy + 1); srcy = srcOps->yOffset + srcOps->height - srcy - height;
// we must read one scanline at a time because there is no way // Note that glReadPixels() is extremely slow!
// to read starting at the top-left corner of the source region // So we call it only once and flip the image using memcpy.
while (height > 0) { j2d_glReadPixels(srcx, srcy, width, height,
j2d_glPixelStorei(GL_PACK_SKIP_ROWS, dsty); pf.format, pf.type, pDst);
j2d_glReadPixels(srcx, srcy, width, 1, // It was checked above that width and height are positive.
pf.format, pf.type, pDst); flip(pDst, (juint) width, (juint) height, dstInfo.scanStride,
srcy--; !pf.isPremult && !srcOps->isOpaque);
dsty++;
height--;
}
#ifdef MACOSX #ifdef MACOSX
if (srcOps->isOpaque) { if (srcOps->isOpaque) {
j2d_glPixelTransferf(GL_ALPHA_BIAS, 0.0); j2d_glPixelTransferf(GL_ALPHA_BIAS, 0.0);
} }
#endif #endif
j2d_glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
j2d_glPixelStorei(GL_PACK_SKIP_ROWS, 0);
j2d_glPixelStorei(GL_PACK_ROW_LENGTH, 0); j2d_glPixelStorei(GL_PACK_ROW_LENGTH, 0);
j2d_glPixelStorei(GL_PACK_ALIGNMENT, 4); j2d_glPixelStorei(GL_PACK_ALIGNMENT, 4);
} }
......
/*
* 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.image.BufferedImage;
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_4BYTE_ABGR;
import static java.awt.image.BufferedImage.TYPE_4BYTE_ABGR_PRE;
import static java.awt.image.BufferedImage.TYPE_INT_ARGB;
import static java.awt.image.BufferedImage.TYPE_INT_ARGB_PRE;
/**
* @test
* @bug 8017626
* @summary Tests drawing transparent volatile image to transparent BI.
* Results of the blit compatibleImage to transparent BI used for
* comparison.
* @author Sergey Bylokhov
*/
public final class IncorrectAlphaSurface2SW {
private static final int[] SCALES = {1, 2, 4, 8};
private static final int[] SIZES = {1, 2, 3, 127, 128, 254, 255, 256};
private static final int[] dstTypes = {TYPE_INT_ARGB, TYPE_INT_ARGB_PRE,
TYPE_4BYTE_ABGR, TYPE_4BYTE_ABGR_PRE};
private static final int[] srcTypes = {TRANSLUCENT};
public static void main(final String[] args) throws IOException {
GraphicsEnvironment ge = GraphicsEnvironment
.getLocalGraphicsEnvironment();
GraphicsConfiguration gc = ge.getDefaultScreenDevice()
.getDefaultConfiguration();
BufferedImage destVI;
BufferedImage destBI;
BufferedImage sourceBI;
VolatileImage sourceVI;
for (final int s : SIZES) {
for (final int srcType : srcTypes) {
for (final int dstType : dstTypes) {
for (final int scale : SCALES) {
int sw = s * scale;
destVI = new BufferedImage(sw, sw, dstType);
destBI = new BufferedImage(sw, sw, dstType);
sourceBI = gc.createCompatibleImage(sw, sw, srcType);
sourceVI = gc.createCompatibleVolatileImage(s, s, srcType);
// draw to dest BI using compatible image
fill(sourceBI, s);
Graphics2D big = destBI.createGraphics();
big.setComposite(AlphaComposite.Src);
big.drawImage(sourceBI, 0, 0, sw, sw, null);
big.dispose();
// draw to dest BI using compatible image
fill(sourceVI, s);
drawVItoBI(gc, destVI, sourceVI);
validate(destVI, destBI);
sourceVI.flush();
}
}
}
}
System.out.println("Test PASSED");
}
private static void drawVItoBI(GraphicsConfiguration gc,
BufferedImage bi, VolatileImage vi) {
while (true) {
vi.validate(gc);
fill(vi, vi.getHeight());
if (vi.validate(gc) != VolatileImage.IMAGE_OK) {
try {
Thread.sleep(100);
} catch (final InterruptedException ignored) {
}
continue;
}
Graphics2D big = bi.createGraphics();
big.setComposite(AlphaComposite.Src);
big.drawImage(vi, 0, 0, bi.getWidth(), bi.getHeight(), null);
big.dispose();
if (vi.contentsLost()) {
try {
Thread.sleep(100);
} catch (final InterruptedException ignored) {
}
continue;
}
break;
}
}
private static void validate(BufferedImage bi, BufferedImage gold)
throws IOException {
for (int x = 0; x < bi.getWidth(); ++x) {
for (int y = 0; y < bi.getHeight(); ++y) {
if (gold.getRGB(x, y) != bi.getRGB(x, y)) {
System.err.println("Expected color = " + gold.getRGB(x, y));
System.err.println("Actual color = " + bi.getRGB(x, y));
ImageIO.write(gold, "png", new File("gold.png"));
ImageIO.write(bi, "png", new File("bi.png"));
throw new RuntimeException("Test failed.");
}
}
}
}
/**
* Fills the whole image using different alpha for each row.
*
* @param image to fill
*/
private static void fill(final Image image, final int size) {
Graphics2D graphics = (Graphics2D) image.getGraphics();
graphics.setComposite(AlphaComposite.Src);
graphics.setColor(Color.GREEN);
graphics.fillRect(0, 0, image.getWidth(null), image.getHeight(null));
int row = image.getHeight(null) / size;
for (int i = 0; i < size; ++i) {
graphics.setColor(new Color(23, 127, 189, i));
graphics.fillRect(0, i * row, image.getWidth(null), row);
}
graphics.dispose();
}
}
/*
* 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.BufferedImage;
import java.awt.image.VolatileImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
/**
* @test
* @bug 8041129
* @summary Destination offset should be correct in case of Surface->SW blit.
* Destination outside of the drawing area should be untouched.
* @author Sergey Bylokhov
*/
public final class IncorrectDestinationOffset {
private static final int SIZE = 128;
private static final double[] SCALES = {0.25, 0.5, 1, 1.5, 2.0, 4};
public static void main(final String[] args) throws IOException {
GraphicsEnvironment ge = GraphicsEnvironment
.getLocalGraphicsEnvironment();
GraphicsConfiguration gc = ge.getDefaultScreenDevice()
.getDefaultConfiguration();
VolatileImage vi = gc.createCompatibleVolatileImage(SIZE, SIZE);
BufferedImage bi = new BufferedImage(SIZE, SIZE,
BufferedImage.TYPE_INT_ARGB);
for (double scale : SCALES) {
while (true) {
// initialize Volatile Image
vi.validate(gc);
Graphics2D g2d = vi.createGraphics();
g2d.setColor(Color.green);
g2d.fillRect(0, 0, SIZE, SIZE);
g2d.dispose();
if (vi.validate(gc) != VolatileImage.IMAGE_OK) {
try {
Thread.sleep(100);
} catch (InterruptedException ignored) {
}
continue;
}
// Draw the VolatileImage to BI with scale and offsets
Graphics2D g = bi.createGraphics();
g.setComposite(AlphaComposite.Src);
g.setColor(Color.RED);
g.fillRect(0, 0, SIZE / 2, SIZE / 2);
g.setColor(Color.BLUE);
g.fillRect(SIZE / 2, 0, SIZE / 2, SIZE / 2);
g.setColor(Color.ORANGE);
g.fillRect(0, SIZE / 2, SIZE / 2, SIZE / 2);
g.setColor(Color.MAGENTA);
g.fillRect(SIZE / 2, SIZE / 2, SIZE / 2, SIZE / 2);
int point2draw = (int) (100 * scale);
int size2draw = (int) (SIZE * scale);
g.drawImage(vi, point2draw, point2draw, size2draw, size2draw,
null);
g.dispose();
if (vi.contentsLost()) {
try {
Thread.sleep(100);
} catch (InterruptedException ignored) {
}
continue;
}
validate(bi, point2draw, size2draw);
break;
}
}
}
private static void validate(BufferedImage bi, int point2draw,
int size2draw)
throws IOException {
for (int x = 0; x < SIZE; ++x) {
for (int y = 0; y < SIZE; ++y) {
if (isInsideGreenArea(point2draw, size2draw, x, y)) {
if (bi.getRGB(x, y) != Color.green.getRGB()) {
ImageIO.write(bi, "png", new File("image.png"));
throw new RuntimeException("Test failed.");
}
} else {
if (isRedArea(x, y)) {
if (bi.getRGB(x, y) != Color.red.getRGB()) {
ImageIO.write(bi, "png", new File("image.png"));
throw new RuntimeException("Test failed.");
}
}
if (isBlueArea(x, y)) {
if (bi.getRGB(x, y) != Color.blue.getRGB()) {
ImageIO.write(bi, "png", new File("image.png"));
throw new RuntimeException("Test failed.");
}
}
if (isOrangeArea(x, y)) {
if (bi.getRGB(x, y) != Color.orange.getRGB()) {
ImageIO.write(bi, "png", new File("image.png"));
throw new RuntimeException("Test failed.");
}
}
if (isMagentaArea(x, y)) {
if (bi.getRGB(x, y) != Color.magenta.getRGB()) {
ImageIO.write(bi, "png", new File("image.png"));
throw new RuntimeException("Test failed.");
}
}
}
}
}
}
private static boolean isRedArea(int x, int y) {
return x < SIZE / 2 && y < SIZE / 2;
}
private static boolean isBlueArea(int x, int y) {
return x >= SIZE / 2 && y < SIZE / 2;
}
private static boolean isOrangeArea(int x, int y) {
return x < SIZE / 2 && y >= SIZE / 2;
}
private static boolean isMagentaArea(int x, int y) {
return x >= SIZE / 2 && y >= SIZE / 2;
}
private static boolean isInsideGreenArea(int point2draw, int size2draw,
int x, int y) {
return x >= point2draw && x < point2draw + size2draw && y >=
point2draw && y < point2draw + size2draw;
}
}
/*
* 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.image.BufferedImage;
import java.awt.image.VolatileImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
/**
* @test
* @bug 8041129
* @summary Tests asymmetric source offsets.
* @author Sergey Bylokhov
*/
public final class IncorrectSourceOffset {
public static void main(final String[] args) throws IOException {
GraphicsEnvironment ge = GraphicsEnvironment
.getLocalGraphicsEnvironment();
GraphicsConfiguration gc = ge.getDefaultScreenDevice()
.getDefaultConfiguration();
VolatileImage vi = gc.createCompatibleVolatileImage(511, 255);
BufferedImage bi = new BufferedImage(511, 255,
BufferedImage.TYPE_INT_ARGB);
BufferedImage gold = new BufferedImage(511, 255,
BufferedImage.TYPE_INT_ARGB);
fill(gold);
while (true) {
vi.validate(gc);
fill(vi);
if (vi.validate(gc) != VolatileImage.IMAGE_OK) {
try {
Thread.sleep(100);
} catch (final InterruptedException ignored) {
}
continue;
}
Graphics2D big = bi.createGraphics();
big.drawImage(vi, 7, 11, 127, 111, 7, 11, 127, 111, null);
big.dispose();
if (vi.contentsLost()) {
try {
Thread.sleep(100);
} catch (final InterruptedException ignored) {
}
continue;
}
break;
}
for (int x = 7; x < 127; ++x) {
for (int y = 11; y < 111; ++y) {
if (gold.getRGB(x, y) != bi.getRGB(x, y)) {
ImageIO.write(gold, "png", new File("gold.png"));
ImageIO.write(bi, "png", new File("bi.png"));
throw new RuntimeException("Test failed.");
}
}
}
}
private static void fill(Image image) {
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.
先完成此消息的编辑!
想要评论请 注册