JBR-8439 Vulkan: Cleanup Surface->Surface blit

This commit is contained in:
Nikita Gubarkov
2025-03-13 14:34:40 +01:00
committed by Vitaly Provodin
parent dc7910aa44
commit ce8e850cac
6 changed files with 116 additions and 273 deletions

View File

@@ -72,16 +72,6 @@ final class VKBlitLoops {
new VKSurfaceToSwBlit(VKFormat.B8G8R8A8_UNORM, TRANSLUCENT); // TODO this is a placeholder.
GraphicsPrimitive[] primitiveArray = {
// surface->surface ops
new VKSurfaceToSurfaceBlit(),
new VKSurfaceToSurfaceScale(),
new VKSurfaceToSurfaceTransform(),
// render-to-texture surface->surface ops
new VKRTTSurfaceToSurfaceBlit(),
new VKRTTSurfaceToSurfaceScale(),
new VKRTTSurfaceToSurfaceTransform(),
// sw->surface ops
blitIntArgbPreToSurface,
new VKSwToSurfaceBlit(SurfaceType.IntRgb,
@@ -128,11 +118,6 @@ final class VKBlitLoops {
new VKGeneralTransformedBlit(transformBlitIntArgbPreToSurface),
// texture->surface ops
new VKTextureToSurfaceBlit(),
new VKTextureToSurfaceScale(),
new VKTextureToSurfaceTransform(),
// sw->texture ops
blitIntArgbPreToTexture,
new VKSwToTextureBlit(SurfaceType.IntRgb,
@@ -150,6 +135,13 @@ final class VKBlitLoops {
List<GraphicsPrimitive> primitives = new ArrayList<>();
Collections.addAll(primitives, primitiveArray);
// Surface->Surface
primitives.add(new VKSurfaceToSurfaceBlit(CompositeType.AnyAlpha));
primitives.add(new VKSurfaceToSurfaceBlit(CompositeType.Xor));
primitives.add(new VKSurfaceToSurfaceScale(CompositeType.AnyAlpha));
primitives.add(new VKSurfaceToSurfaceScale(CompositeType.Xor));
primitives.add(new VKSurfaceToSurfaceTransform(CompositeType.AnyAlpha));
primitives.add(new VKSurfaceToSurfaceTransform(CompositeType.Xor));
// Surface->Sw
for (VKFormat format : VKFormat.values()) {
primitives.add(new VKSurfaceToSwBlit(format, OPAQUE));
@@ -168,8 +160,6 @@ final class VKBlitLoops {
*/
@Native private static final int OFFSET_SRCTYPE = 16;
@Native private static final int OFFSET_HINT = 8;
@Native private static final int OFFSET_TEXTURE = 3;
@Native private static final int OFFSET_RTT = 2;
@Native private static final int OFFSET_XFORM = 1;
@Native private static final int OFFSET_ISOBLIT = 0;
@@ -177,15 +167,10 @@ final class VKBlitLoops {
* Packs the given parameters into a single int value in order to save
* space on the rendering queue.
*/
private static int createPackedParams(boolean isoblit, boolean texture,
boolean rtt, boolean xform,
int hint, int srctype)
{
private static int createPackedParams(boolean isoblit, boolean xform, int hint, int srctype) {
return
((srctype << OFFSET_SRCTYPE) |
(hint << OFFSET_HINT ) |
((texture ? 1 : 0) << OFFSET_TEXTURE) |
((rtt ? 1 : 0) << OFFSET_RTT ) |
((xform ? 1 : 0) << OFFSET_XFORM ) |
((isoblit ? 1 : 0) << OFFSET_ISOBLIT));
}
@@ -249,9 +234,7 @@ final class VKBlitLoops {
ctxflags);
}
int packedParams = createPackedParams(false, texture,
false /*unused*/, xform != null,
hint, srctype);
int packedParams = createPackedParams(false, xform != null, hint, srctype);
enqueueBlit(rq, srcData, dstData,
packedParams,
sx1, sy1, sx2, sy2,
@@ -278,9 +261,7 @@ final class VKBlitLoops {
int sx1, int sy1,
int sx2, int sy2,
double dx1, double dy1,
double dx2, double dy2,
boolean texture)
{
double dx2, double dy2) {
int ctxflags = 0;
if (srcData.getTransparency() == Transparency.OPAQUE) {
ctxflags |= VKContext.SRC_IS_OPAQUE;
@@ -320,9 +301,7 @@ final class VKBlitLoops {
VKBufImgOps.enableBufImgOp(rq, vkSrc, srcImg, biop);
}
int packedParams = createPackedParams(true, texture,
false /*unused*/, xform != null,
hint, 0 /*unused*/);
int packedParams = createPackedParams(true, xform != null, hint, 0 /*unused*/);
enqueueBlit(rq, srcData, dstData,
packedParams,
sx1, sy1, sx2, sy2,
@@ -343,12 +322,10 @@ final class VKBlitLoops {
}
}
class VKSurfaceToSurfaceBlit extends Blit {
final class VKSurfaceToSurfaceBlit extends Blit {
VKSurfaceToSurfaceBlit() {
super(VKSurfaceData.VKSurface,
CompositeType.AnyAlpha,
VKSurfaceData.VKSurface);
VKSurfaceToSurfaceBlit(CompositeType compositeType) {
super(VKSurfaceData.VKSurface, compositeType, VKSurfaceData.VKSurface);
}
public void Blit(SurfaceData src, SurfaceData dst,
@@ -360,17 +337,14 @@ class VKSurfaceToSurfaceBlit extends Blit {
comp, clip, null,
AffineTransformOp.TYPE_NEAREST_NEIGHBOR,
sx, sy, sx+w, sy+h,
dx, dy, dx+w, dy+h,
false);
dx, dy, dx+w, dy+h);
}
}
class VKSurfaceToSurfaceScale extends ScaledBlit {
final class VKSurfaceToSurfaceScale extends ScaledBlit {
VKSurfaceToSurfaceScale() {
super(VKSurfaceData.VKSurface,
CompositeType.AnyAlpha,
VKSurfaceData.VKSurface);
VKSurfaceToSurfaceScale(CompositeType compositeType) {
super(VKSurfaceData.VKSurface, compositeType, VKSurfaceData.VKSurface);
}
public void Scale(SurfaceData src, SurfaceData dst,
@@ -385,17 +359,14 @@ class VKSurfaceToSurfaceScale extends ScaledBlit {
comp, clip, null,
AffineTransformOp.TYPE_NEAREST_NEIGHBOR,
sx1, sy1, sx2, sy2,
dx1, dy1, dx2, dy2,
false);
dx1, dy1, dx2, dy2);
}
}
class VKSurfaceToSurfaceTransform extends TransformBlit {
final class VKSurfaceToSurfaceTransform extends TransformBlit {
VKSurfaceToSurfaceTransform() {
super(VKSurfaceData.VKSurface,
CompositeType.AnyAlpha,
VKSurfaceData.VKSurface);
VKSurfaceToSurfaceTransform(CompositeType compositeType) {
super(VKSurfaceData.VKSurface, compositeType, VKSurfaceData.VKSurface);
}
public void Transform(SurfaceData src, SurfaceData dst,
@@ -408,77 +379,7 @@ class VKSurfaceToSurfaceTransform extends TransformBlit {
null, null,
comp, clip, at, hint,
sx, sy, sx+w, sy+h,
dx, dy, dx+w, dy+h,
false);
}
}
class VKRTTSurfaceToSurfaceBlit extends Blit {
VKRTTSurfaceToSurfaceBlit() {
super(VKSurfaceData.VKSurfaceRTT,
CompositeType.AnyAlpha,
VKSurfaceData.VKSurface);
}
public void Blit(SurfaceData src, SurfaceData dst,
Composite comp, Region clip,
int sx, int sy, int dx, int dy, int w, int h)
{
VKBlitLoops.IsoBlit(src, dst,
null, null,
comp, clip, null,
AffineTransformOp.TYPE_NEAREST_NEIGHBOR,
sx, sy, sx+w, sy+h,
dx, dy, dx+w, dy+h,
true);
}
}
class VKRTTSurfaceToSurfaceScale extends ScaledBlit {
VKRTTSurfaceToSurfaceScale() {
super(VKSurfaceData.VKSurfaceRTT,
CompositeType.AnyAlpha,
VKSurfaceData.VKSurface);
}
public void Scale(SurfaceData src, SurfaceData dst,
Composite comp, Region clip,
int sx1, int sy1,
int sx2, int sy2,
double dx1, double dy1,
double dx2, double dy2)
{
VKBlitLoops.IsoBlit(src, dst,
null, null,
comp, clip, null,
AffineTransformOp.TYPE_NEAREST_NEIGHBOR,
sx1, sy1, sx2, sy2,
dx1, dy1, dx2, dy2,
true);
}
}
class VKRTTSurfaceToSurfaceTransform extends TransformBlit {
VKRTTSurfaceToSurfaceTransform() {
super(VKSurfaceData.VKSurfaceRTT,
CompositeType.AnyAlpha,
VKSurfaceData.VKSurface);
}
public void Transform(SurfaceData src, SurfaceData dst,
Composite comp, Region clip,
AffineTransform at, int hint,
int sx, int sy, int dx, int dy, int w, int h)
{
VKBlitLoops.IsoBlit(src, dst,
null, null,
comp, clip, at, hint,
sx, sy, sx+w, sy+h,
dx, dy, dx+w, dy+h,
true);
dx, dy, dx+w, dy+h);
}
}
@@ -683,76 +584,6 @@ class VKSwToTextureBlit extends Blit {
}
}
class VKTextureToSurfaceBlit extends Blit {
VKTextureToSurfaceBlit() {
super(VKSurfaceData.VKTexture,
CompositeType.AnyAlpha,
VKSurfaceData.VKSurface);
}
public void Blit(SurfaceData src, SurfaceData dst,
Composite comp, Region clip,
int sx, int sy, int dx, int dy, int w, int h)
{
VKBlitLoops.IsoBlit(src, dst,
null, null,
comp, clip, null,
AffineTransformOp.TYPE_NEAREST_NEIGHBOR,
sx, sy, sx+w, sy+h,
dx, dy, dx+w, dy+h,
true);
}
}
class VKTextureToSurfaceScale extends ScaledBlit {
VKTextureToSurfaceScale() {
super(VKSurfaceData.VKTexture,
CompositeType.AnyAlpha,
VKSurfaceData.VKSurface);
}
public void Scale(SurfaceData src, SurfaceData dst,
Composite comp, Region clip,
int sx1, int sy1,
int sx2, int sy2,
double dx1, double dy1,
double dx2, double dy2)
{
VKBlitLoops.IsoBlit(src, dst,
null, null,
comp, clip, null,
AffineTransformOp.TYPE_NEAREST_NEIGHBOR,
sx1, sy1, sx2, sy2,
dx1, dy1, dx2, dy2,
true);
}
}
class VKTextureToSurfaceTransform extends TransformBlit {
VKTextureToSurfaceTransform() {
super(VKSurfaceData.VKTexture,
CompositeType.AnyAlpha,
VKSurfaceData.VKSurface);
}
public void Transform(SurfaceData src, SurfaceData dst,
Composite comp, Region clip,
AffineTransform at, int hint,
int sx, int sy, int dx, int dy,
int w, int h)
{
VKBlitLoops.IsoBlit(src, dst,
null, null,
comp, clip, at, hint,
sx, sy, sx+w, sy+h,
dx, dy, dx+w, dy+h,
true);
}
}
/**
* This general Blit implementation converts any source surface to an
* intermediate IntArgbPre surface, and then uses the more specific
@@ -913,5 +744,3 @@ final class VKAnyCompositeBlit extends Blit {
dy, w, h);
}
}

View File

@@ -45,7 +45,7 @@ class VKBufImgOps extends BufferedBufImgOps {
/**
* This method is called from VKDrawImage.transformImage() only. It
* validates the provided BufferedImageOp to determine whether the op
* is one that can be accelerated by the MTL pipeline. If the operation
* is one that can be accelerated by the Vulkan pipeline. If the operation
* cannot be completed for any reason, this method returns false;
* otherwise, the given BufferedImage is rendered to the destination
* using the provided BufferedImageOp and this method returns true.
@@ -53,65 +53,66 @@ class VKBufImgOps extends BufferedBufImgOps {
static boolean renderImageWithOp(SunGraphics2D sg, BufferedImage img,
BufferedImageOp biop, int x, int y)
{
// Validate the provided BufferedImage (make sure it is one that
// is supported, and that its properties are acceleratable)
if (biop instanceof ConvolveOp) {
if (!isConvolveOpValid((ConvolveOp)biop)) {
return false;
}
} else if (biop instanceof RescaleOp) {
if (!isRescaleOpValid((RescaleOp)biop, img)) {
return false;
}
} else if (biop instanceof LookupOp) {
if (!isLookupOpValid((LookupOp)biop, img)) {
return false;
}
} else {
// No acceleration for other BufferedImageOps (yet)
return false;
}
SurfaceData dstData = sg.surfaceData;
if (!(dstData instanceof VKSurfaceData) ||
(sg.interpolationType == AffineTransformOp.TYPE_BICUBIC) ||
(sg.compositeState > SunGraphics2D.COMP_ALPHA))
{
return false;
}
SurfaceData srcData =
dstData.getSourceSurfaceData(img, SunGraphics2D.TRANSFORM_ISIDENT,
CompositeType.SrcOver, null);
if (!(srcData instanceof VKSurfaceData)) {
// REMIND: this hack tries to ensure that we have a cached texture
srcData =
dstData.getSourceSurfaceData(img, SunGraphics2D.TRANSFORM_ISIDENT,
CompositeType.SrcOver, null);
if (!(srcData instanceof VKSurfaceData)) {
return false;
}
}
// Verify that the source surface is actually a texture and
// that the operation is supported
VKSurfaceData vkSrc = (VKSurfaceData)srcData;
VKGraphicsConfig gc = vkSrc.getGraphicsConfig();
if (vkSrc.getType() != VKSurfaceData.TEXTURE || !gc.isCapPresent(CAPS_EXT_BIOP_SHADER))
{
return false;
}
int sw = img.getWidth();
int sh = img.getHeight();
VKBlitLoops.IsoBlit(srcData, dstData,
img, biop,
sg.composite, sg.getCompClip(),
sg.transform, sg.interpolationType,
0, 0, sw, sh,
x, y, x+sw, y+sh,
true);
return true;
// TODO No acceleration for image ops yet.
return false;
// // Validate the provided BufferedImage (make sure it is one that
// // is supported, and that its properties are acceleratable)
// if (biop instanceof ConvolveOp) {
// if (!isConvolveOpValid((ConvolveOp)biop)) {
// return false;
// }
// } else if (biop instanceof RescaleOp) {
// if (!isRescaleOpValid((RescaleOp)biop, img)) {
// return false;
// }
// } else if (biop instanceof LookupOp) {
// if (!isLookupOpValid((LookupOp)biop, img)) {
// return false;
// }
// } else {
// // No acceleration for other BufferedImageOps (yet)
// return false;
// }
//
// SurfaceData dstData = sg.surfaceData;
// if (!(dstData instanceof VKSurfaceData) ||
// (sg.interpolationType == AffineTransformOp.TYPE_BICUBIC) ||
// (sg.compositeState > SunGraphics2D.COMP_ALPHA))
// {
// return false;
// }
//
// SurfaceData srcData =
// dstData.getSourceSurfaceData(img, SunGraphics2D.TRANSFORM_ISIDENT,
// CompositeType.SrcOver, null);
// if (!(srcData instanceof VKSurfaceData)) {
// // REMIND: this hack tries to ensure that we have a cached texture
// srcData =
// dstData.getSourceSurfaceData(img, SunGraphics2D.TRANSFORM_ISIDENT,
// CompositeType.SrcOver, null);
// if (!(srcData instanceof VKSurfaceData)) {
// return false;
// }
// }
//
// // Verify that the source surface is actually a texture and
// // that the operation is supported
// VKSurfaceData vkSrc = (VKSurfaceData)srcData;
// VKGraphicsConfig gc = vkSrc.getGraphicsConfig();
// if (vkSrc.getType() != VKSurfaceData.TEXTURE || !gc.isCapPresent(CAPS_EXT_BIOP_SHADER))
// {
// return false;
// }
//
// int sw = img.getWidth();
// int sh = img.getHeight();
// VKBlitLoops.IsoBlit(srcData, dstData,
// img, biop,
// sg.composite, sg.getCompClip(),
// sg.transform, sg.interpolationType,
// 0, 0, sw, sh,
// x, y, x+sw, y+sh);
//
// return true;
}
}

View File

@@ -266,14 +266,12 @@ static jboolean clipDestCoords(
}
void VKBlitLoops_IsoBlit(JNIEnv *env, jlong pSrcOps, jboolean xform, jint hint,
jboolean texture, jint sx1, jint sy1, jint sx2,
jint sy2, jdouble dx1, jdouble dy1, jdouble dx2,
jdouble dy2)
jint sx1, jint sy1, jint sx2, jint sy2,
jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
{
J2dRlsTraceLn8(J2D_TRACE_VERBOSE, "VKBlitLoops_IsoBlit: (%d %d %d %d) -> (%f %f %f %f) ",
sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2);
J2dRlsTraceLn2(J2D_TRACE_VERBOSE, "VKBlitLoops_IsoBlit: texture=%d xform=%d",
texture, xform)
J2dRlsTraceLn1(J2D_TRACE_VERBOSE, "VKBlitLoops_IsoBlit: xform=%d", xform)
VKSDOps *srcOps = (VKSDOps *)jlong_to_ptr(pSrcOps);
@@ -349,7 +347,7 @@ void VKBlitLoops_IsoBlit(JNIEnv *env, jlong pSrcOps, jboolean xform, jint hint,
void VKBlitLoops_Blit(JNIEnv *env,
jlong pSrcOps, jboolean xform, jint hint,
jint srctype, jboolean texture,
jint srctype,
jint sx1, jint sy1,
jint sx2, jint sy2,
jdouble dx1, jdouble dy1,
@@ -357,8 +355,7 @@ void VKBlitLoops_Blit(JNIEnv *env,
{
J2dRlsTraceLn8(J2D_TRACE_VERBOSE, "VKRenderQueue_flushBuffer: BLIT_Blit (%d %d %d %d) -> (%f %f %f %f) ",
sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2)
J2dRlsTraceLn3(J2D_TRACE_VERBOSE, "VKRenderQueue_flushBuffer: BLIT_Blit texture=%d xform=%d srctype=%d",
texture, xform, srctype)
J2dRlsTraceLn2(J2D_TRACE_VERBOSE, "VKRenderQueue_flushBuffer: BLIT_Blit xform=%d srctype=%d", xform, srctype)
SurfaceDataOps *srcOps = (SurfaceDataOps *)jlong_to_ptr(pSrcOps);

View File

@@ -34,7 +34,6 @@
void VKBlitLoops_IsoBlit(JNIEnv *env,
jlong pSrcOps,
jboolean xform, jint hint,
jboolean texture,
jint sx1, jint sy1,
jint sx2, jint sy2,
jdouble dx1, jdouble dy1,
@@ -43,7 +42,7 @@ void VKBlitLoops_IsoBlit(JNIEnv *env,
void VKBlitLoops_Blit(JNIEnv *env,
jlong pSrcOps,
jboolean xform, jint hint,
jint srctype, jboolean texture,
jint srctype,
jint sx1, jint sy1,
jint sx2, jint sy2,
jdouble dx1, jdouble dy1,

View File

@@ -338,10 +338,6 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
jlong pSrc = NEXT_LONG(b);
jlong pDst = NEXT_LONG(b);
jint hint = EXTRACT_BYTE(packedParams, OFFSET_HINT);
jboolean texture = EXTRACT_BOOLEAN(packedParams,
OFFSET_TEXTURE);
jboolean rtt = EXTRACT_BOOLEAN(packedParams,
OFFSET_RTT);
jboolean xform = EXTRACT_BOOLEAN(packedParams,
OFFSET_XFORM);
jboolean isoblit = EXTRACT_BOOLEAN(packedParams,
@@ -351,13 +347,13 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
VKRenderer_GetContext()->surface = dstOps;
if (isoblit) {
VKBlitLoops_IsoBlit(env, pSrc,
xform, hint, texture,
xform, hint,
sx1, sy1, sx2, sy2,
dx1, dy1, dx2, dy2);
} else {
jint srctype = EXTRACT_BYTE(packedParams, OFFSET_SRCTYPE);
VKBlitLoops_Blit(env, pSrc,
xform, hint, srctype, texture,
xform, hint, srctype,
sx1, sy1, sx2, sy2,
dx1, dy1, dx2, dy2);
}
@@ -365,8 +361,7 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
J2dRlsTraceLn2(J2D_TRACE_VERBOSE, "VKRenderQueue_flushBuffer: BLIT %p -> %p ", pSrc, pDst)
J2dRlsTraceLn8(J2D_TRACE_VERBOSE, "VKRenderQueue_flushBuffer: BLIT (%d %d %d %d) -> (%f %f %f %f) ",
sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2)
J2dRlsTraceLn4(J2D_TRACE_VERBOSE, "VKRenderQueue_flushBuffer: BLIT texture=%d rtt=%d xform=%d isoblit=%d",
texture, rtt, xform, isoblit)
J2dRlsTraceLn2(J2D_TRACE_VERBOSE, "VKRenderQueue_flushBuffer: BLIT xform=%d isoblit=%d", xform, isoblit)
}
break;

View File

@@ -240,6 +240,28 @@ public class VulkanBlitTest {
testSurfaceToSwBlit(bi, image, prefix + "4BYTE_ABGR, ", hasAlpha);
bi = new BufferedImage(W, H, BufferedImage.TYPE_4BYTE_ABGR_PRE);
testSurfaceToSwBlit(bi, image, prefix + "4BYTE_ABGR_PRE, ", hasAlpha);
// Blit into another Vulkan image.
hasAlpha = false; // TODO our blit currently ignores alpha, remove when fixed.
SUPPRESS_ALPHA_VALIDATION = true; // TODO same.
VolatileImage anotherImage = config.createCompatibleVolatileImage(W, H, transparency);
if (anotherImage.validate(config) == VolatileImage.IMAGE_INCOMPATIBLE) {
throw new Error("Image validation failed");
}
{
Graphics2D g = anotherImage.createGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
}
if (anotherImage.contentsLost()) throw new Error("Image contents lost");
// Take a snapshot (blit into Sw) and validate.
bi = anotherImage.getSnapshot();
ImageIO.write(bi, "PNG", new File(prefix + "another-snapshot.png"));
try {
validate(bi, hasAlpha);
} catch (Throwable t) {
throw new Error(prefix + "another-snapshot", t);
}
}
public static void main(String[] args) throws IOException {