JBR-8287 Vulkan: enable hw accelerated VolatileImage

Moved robot pixel grabber into windows surface data
Created offscreen surface data
This commit is contained in:
Alexey Ushakov
2025-02-11 23:12:28 +01:00
committed by jbrbot
parent 23b5e22d79
commit a7f92645fb
5 changed files with 212 additions and 110 deletions

View File

@@ -35,6 +35,7 @@ public class VKInstance {
private static final PlatformLogger log = PlatformLogger.getLogger("sun.java2d.vulkan.VKInstance");
private static Boolean initialized;
private static Boolean sdAccelerated;
private static native boolean initNative(long nativePtr, boolean verbose, int deviceNumber);
@@ -54,10 +55,15 @@ public class VKInstance {
final int deviceNumber = parsedDeviceNumber;
final boolean verbose = "True".equals(vulkanOption);
System.loadLibrary("awt");
String sdOption = AccessController.doPrivileged(
(PrivilegedAction<String>) () -> System.getProperty("sun.java2d.vulkan.accelsd", ""));
initialized = initNative(nativePtr, verbose, deviceNumber);
sdAccelerated = initialized && "true".equalsIgnoreCase(sdOption);
} else initialized = false;
if (log.isLoggable(PlatformLogger.Level.FINE)) {
log.fine("Vulkan rendering enabled: " + (initialized ? "YES" : "NO"));
log.fine("Vulkan accelerated surface data enabled: " + (sdAccelerated ? "YES" : "NO"));
}
}
@@ -65,4 +71,9 @@ public class VKInstance {
if (initialized == null) throw new RuntimeException("Vulkan not initialized");
return initialized;
}
public static boolean isSurfaceDataAccelerated() {
if (initialized == null) throw new RuntimeException("Vulkan not initialized");
return sdAccelerated;
}
}

View File

@@ -559,8 +559,8 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
VKSDOps* src = NEXT_SURFACE(b);
VKSDOps* dst = NEXT_SURFACE(b);
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
"VKRenderQueue_flushBuffer: SET_SURFACES");
J2dRlsTraceLn2(J2D_TRACE_VERBOSE,
"VKRenderQueue_flushBuffer: SET_SURFACES src=%p dst=%p", src, dst);
context.surface = dst;
}
break;

View File

@@ -1,6 +1,6 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, JetBrains s.r.o.. All rights reserved.
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2025, JetBrains s.r.o.. 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
@@ -30,6 +30,7 @@ import java.awt.AlphaComposite;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
@@ -48,46 +49,15 @@ import sun.util.logging.PlatformLogger;
import static sun.java2d.pipe.BufferedOpCodes.FLUSH_BUFFER;
import static sun.java2d.pipe.BufferedOpCodes.CONFIGURE_SURFACE;
public abstract class WLVKSurfaceData extends VKSurfaceData implements WLSurfaceDataExt, WLPixelGrabberExt {
public abstract class WLVKSurfaceData extends VKSurfaceData {
private static final PlatformLogger log = PlatformLogger.getLogger("sun.java2d.vulkan.WLVKSurfaceData");
protected WLComponentPeer peer;
private native void initOps(int backgroundRGB);
private native void assignWlSurface(long surfacePtr);
protected WLVKSurfaceData(WLComponentPeer peer, WLVKGraphicsConfig gc,
SurfaceType sType, ColorModel cm, int type)
{
protected WLVKSurfaceData(WLVKGraphicsConfig gc,
SurfaceType sType, ColorModel cm, int type) {
super(gc, cm, type, 0, 0);
this.peer = peer;
final int backgroundRGB = peer.getBackground() != null
? peer.getBackground().getRGB()
: 0;
initOps(backgroundRGB);
}
private void bufferAttached() {
// Called from the native code when a buffer has just been attached to this surface
// but the surface has not been committed yet.
peer.updateSurfaceSize();
}
@Override
public void assignSurface(long surfacePtr) {
assignWlSurface(surfacePtr);
if (surfacePtr != 0) configure();
}
@Override
public void revalidate(int width, int height, int scale) {
this.width = width;
this.height = height;
this.scale = scale;
configure();
}
private synchronized void configure() {
protected synchronized void configure() {
VKRenderQueue rq = VKRenderQueue.getInstance();
rq.lock();
try {
@@ -104,32 +74,12 @@ public abstract class WLVKSurfaceData extends VKSurfaceData implements WLSurface
}
}
@Override
public synchronized void commit() {
VKRenderQueue rq = VKRenderQueue.getInstance();
rq.lock();
try {
RenderBuffer buf = rq.getBuffer();
rq.ensureCapacityAndAlignment(12, 4);
buf.putInt(FLUSH_BUFFER);
buf.putLong(getNativeOps());
rq.flushNow();
} finally {
rq.unlock();
}
}
@Override
public boolean isOnScreen() {
return false;
}
@Override
public GraphicsConfiguration getDeviceConfiguration() {
return peer.getGraphicsConfiguration();
}
/**
* Creates a SurfaceData object representing surface of on-screen Window.
*/
@@ -138,6 +88,12 @@ public abstract class WLVKSurfaceData extends VKSurfaceData implements WLSurface
return new WLVKWindowSurfaceData(peer, gc);
}
public static WLVKOffScreenSurfaceData createData(WLVKGraphicsConfig gc, int width,
int height, Image image,
ColorModel cm, int type) {
return new WLVKOffScreenSurfaceData(gc, width, height, image, cm, type);
}
public static WLVKGraphicsConfig getGC(WLComponentPeer peer) {
if (peer != null) {
return (WLVKGraphicsConfig) peer.getGraphicsConfiguration();
@@ -150,56 +106,75 @@ public abstract class WLVKSurfaceData extends VKSurfaceData implements WLSurface
return (WLVKGraphicsConfig)gd.getDefaultConfiguration();
}
}
/**
* SurfaceData object representing an off-screen buffer
*/
public static class WLVKOffScreenSurfaceData extends WLVKSurfaceData {
private final Image offscreenImage;
public int getRGBPixelAt(int x, int y) {
Rectangle r = peer.getBufferBounds();
if (x < r.x || x >= r.x + r.width || y < r.y || y >= r.y + r.height) {
throw new ArrayIndexOutOfBoundsException("x,y outside of buffer bounds");
private native void initOps(int width, int height);
public WLVKOffScreenSurfaceData(WLVKGraphicsConfig gc, int width,
int height, Image image,
ColorModel cm, int type) {
super(gc, gc.getSurfaceType(), gc.getColorModel(), RT_TEXTURE);
offscreenImage = image;
this.width = width;
this.height = height;
initOps(width, height);
}
BufferedImage resImg = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
SurfaceData resData = BufImgSurfaceData.createData(resImg);
@Override
public SurfaceData getReplacement() {
return restoreContents(offscreenImage);
}
Blit blit = Blit.getFromCache(getSurfaceType(), CompositeType.SrcNoEa,
resData.getSurfaceType());
blit.Blit(this, resData, AlphaComposite.Src, null,
x, y, 0, 0, 1, 1);
@Override
public GraphicsConfiguration getDeviceConfiguration() {
return null;
}
return resImg.getRGB(0, 0);
@Override
public long getNativeResource(int resType) {
return 0;
}
@Override
public Rectangle getBounds() {
return new Rectangle(width, height);
}
/**
* Returns destination Image associated with this SurfaceData.
*/
@Override
public Object getDestination() {
return offscreenImage;
}
@Override
public BufferedContext getContext() {
return getGraphicsConfig().getContext();
}
}
public int [] getRGBPixelsAt(Rectangle bounds) {
Rectangle r = peer.getBufferBounds();
public static class WLVKWindowSurfaceData extends WLVKSurfaceData
implements WLPixelGrabberExt, WLSurfaceDataExt
{
protected WLComponentPeer peer;
if ((long)bounds.width * (long)bounds.height > Integer.MAX_VALUE) {
throw new IndexOutOfBoundsException("Dimensions (width=" + bounds.width +
" height=" + bounds.height + ") are too large");
}
private native void initOps(int backgroundRGB);
Rectangle b = bounds.intersection(r);
private native void assignWlSurface(long surfacePtr);
if (b.isEmpty()) {
throw new IndexOutOfBoundsException("Requested bounds are outside of surface bounds");
}
BufferedImage resImg = new BufferedImage(b.width, b.height, BufferedImage.TYPE_INT_ARGB);
SurfaceData resData = BufImgSurfaceData.createData(resImg);
Blit blit = Blit.getFromCache(getSurfaceType(), CompositeType.SrcNoEa,
resData.getSurfaceType());
blit.Blit(this, resData, AlphaComposite.Src, null,
b.x, b.y, 0, 0, b.width, b.height);
int [] pixels = new int[b.width * b.height];
resImg.getRGB(0, 0, b.width, b.height, pixels, 0, b.width);
return pixels;
}
public static class WLVKWindowSurfaceData extends WLVKSurfaceData {
public WLVKWindowSurfaceData(WLComponentPeer peer, WLVKGraphicsConfig gc)
{
super(peer, gc, gc.getSurfaceType(), peer.getColorModel(), WINDOW);
super(gc, gc.getSurfaceType(), peer.getColorModel(), WINDOW);
this.peer = peer;
final int backgroundRGB = peer.getBackground() != null
? peer.getBackground().getRGB()
: 0;
initOps(backgroundRGB);
}
public SurfaceData getReplacement() {
@@ -243,5 +218,88 @@ public abstract class WLVKSurfaceData extends VKSurfaceData implements WLSurface
public boolean isOnScreen() {
return true;
}
@Override
public void assignSurface(long surfacePtr) {
assignWlSurface(surfacePtr);
if (surfacePtr != 0) configure();
}
@Override
public void revalidate(int width, int height, int scale) {
this.width = width;
this.height = height;
this.scale = scale;
configure();
}
@Override
public synchronized void commit() {
VKRenderQueue rq = VKRenderQueue.getInstance();
rq.lock();
try {
RenderBuffer buf = rq.getBuffer();
rq.ensureCapacityAndAlignment(12, 4);
buf.putInt(FLUSH_BUFFER);
buf.putLong(getNativeOps());
rq.flushNow();
} finally {
rq.unlock();
}
}
@Override
public GraphicsConfiguration getDeviceConfiguration() {
return peer.getGraphicsConfiguration();
}
private void bufferAttached() {
// Called from the native code when a buffer has just been attached to this surface
// but the surface has not been committed yet.
peer.updateSurfaceSize();
}
public int getRGBPixelAt(int x, int y) {
Rectangle r = peer.getBufferBounds();
if (x < r.x || x >= r.x + r.width || y < r.y || y >= r.y + r.height) {
throw new ArrayIndexOutOfBoundsException("x,y outside of buffer bounds");
}
BufferedImage resImg = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
SurfaceData resData = BufImgSurfaceData.createData(resImg);
Blit blit = Blit.getFromCache(getSurfaceType(), CompositeType.SrcNoEa,
resData.getSurfaceType());
blit.Blit(this, resData, AlphaComposite.Src, null,
x, y, 0, 0, 1, 1);
return resImg.getRGB(0, 0);
}
public int [] getRGBPixelsAt(Rectangle bounds) {
Rectangle r = peer.getBufferBounds();
if ((long)bounds.width * (long)bounds.height > Integer.MAX_VALUE) {
throw new IndexOutOfBoundsException("Dimensions (width=" + bounds.width +
" height=" + bounds.height + ") are too large");
}
Rectangle b = bounds.intersection(r);
if (b.isEmpty()) {
throw new IndexOutOfBoundsException("Requested bounds are outside of surface bounds");
}
BufferedImage resImg = new BufferedImage(b.width, b.height, BufferedImage.TYPE_INT_ARGB);
SurfaceData resData = BufImgSurfaceData.createData(resImg);
Blit blit = Blit.getFromCache(getSurfaceType(), CompositeType.SrcNoEa,
resData.getSurfaceType());
blit.Blit(this, resData, AlphaComposite.Src, null,
b.x, b.y, 0, 0, b.width, b.height);
int [] pixels = new int[b.width * b.height];
resImg.getRGB(0, 0, b.width, b.height, pixels, 0, b.width);
return pixels;
}
}
}

View File

@@ -47,8 +47,9 @@ public class WLVKVolatileSurfaceManager extends VolatileSurfaceManager {
* if the image is not bitmask
*/
int transparency = vImg.getTransparency();
// TODO: enable acceleration
accelerationEnabled = false; // transparency != Transparency.BITMASK;
accelerationEnabled = VKInstance.isSurfaceDataAccelerated() &&
transparency != Transparency.BITMASK;
}
protected boolean isAccelerationEnabled() {
@@ -60,7 +61,6 @@ public class WLVKVolatileSurfaceManager extends VolatileSurfaceManager {
* of an existing window if this is a double buffered GraphicsConfig)
*/
protected SurfaceData initAcceleratedSurface() {
/* TODO
try {
WLVKGraphicsConfig gc =
(WLVKGraphicsConfig)vImg.getGraphicsConfig();
@@ -74,12 +74,10 @@ public class WLVKVolatileSurfaceManager extends VolatileSurfaceManager {
return WLVKSurfaceData.createData(gc,
vImg.getWidth(),
vImg.getHeight(),
cm, vImg, type);
vImg, cm, type);
} catch (NullPointerException | OutOfMemoryError ignored) {
return null;
}
*/
return null;
}
@Override

View File

@@ -35,8 +35,15 @@ static void WLVKSurfaceData_OnResize(VKWinSDOps* surface, VkExtent2D extent) {
JNU_CallMethodByName(env, NULL, surface->vksdOps.sdOps.sdObject, "bufferAttached", "()V");
}
JNIEXPORT void JNICALL Java_sun_java2d_vulkan_WLVKSurfaceData_initOps(JNIEnv *env, jobject vksd, jint backgroundRGB) {
J2dTraceLn1(J2D_TRACE_VERBOSE, "WLVKSurfaceData_initOps(%p)", vksd);
/*
* Class: sun_java2d_vulkan_WLVKSurfaceData_WLVKWindowSurfaceData
* Method: initOps
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_sun_java2d_vulkan_WLVKSurfaceData_00024WLVKWindowSurfaceData_initOps(
JNIEnv *env, jobject vksd, jint backgroundRGB)
{
J2dTraceLn1(J2D_TRACE_VERBOSE, "WLVKWindowsSurfaceData_initOps(%p)", vksd);
VKWinSDOps* sd = (VKWinSDOps*)SurfaceData_InitOps(env, vksd, sizeof(VKWinSDOps));
if (sd == NULL) {
JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed.");
@@ -48,17 +55,44 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_WLVKSurfaceData_initOps(JNIEnv *en
VKSD_ResetSurface(&sd->vksdOps);
}
JNIEXPORT void JNICALL Java_sun_java2d_vulkan_WLVKSurfaceData_assignWlSurface(JNIEnv *env, jobject vksd, jlong wlSurfacePtr) {
J2dRlsTraceLn2(J2D_TRACE_INFO, "WLVKSurfaceData_assignWlSurface(%p): wl_surface=%p", (void*)vksd, wlSurfacePtr);
/*
* Class: sun_java2d_vulkan_WLVKSurfaceData_WLVKOffScreenSurfaceData
* Method: initOps
* Signature: (II)V
*/
JNIEXPORT void JNICALL Java_sun_java2d_vulkan_WLVKSurfaceData_00024WLVKOffScreenSurfaceData_initOps
(JNIEnv *env, jobject vksd, jint width, jint height) {
J2dTraceLn1(J2D_TRACE_VERBOSE, "WLVKOffScreenSurfaceData_initOps(%p)", vksd);
VKSDOps * sd = (VKSDOps*)SurfaceData_InitOps(env, vksd, sizeof(VKSDOps));
if (sd == NULL) {
JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed.");
return;
}
sd->drawableType = VKSD_RT_TEXTURE;
sd->background = VKUtil_DecodeJavaColor(0);
VKSD_ResetSurface(sd);
}
/*
* Class: sun_java2d_vulkan_WLVKSurfaceData_WLVKWindowSurfaceData
* Method: assignWlSurface
* Signature: (J)V
*/
JNIEXPORT void JNICALL Java_sun_java2d_vulkan_WLVKSurfaceData_00024WLVKWindowSurfaceData_assignWlSurface(
JNIEnv *env, jobject vksd, jlong wlSurfacePtr)
{
J2dRlsTraceLn2(J2D_TRACE_INFO, "WLVKWindowsSurfaceData_assignWlSurface(%p): wl_surface=%p",
(void*)vksd, wlSurfacePtr);
VKWinSDOps* sd = (VKWinSDOps*)SurfaceData_GetOps(env, vksd);
if (sd == NULL) {
J2dRlsTraceLn1(J2D_TRACE_ERROR, "WLVKSurfaceData_assignWlSurface(%p): VKWinSDOps is NULL", vksd);
J2dRlsTraceLn1(J2D_TRACE_ERROR,
"WLVKWindowSurfaceData_assignWlSurface(%p): VKWinSDOps is NULL", vksd);
VK_UNHANDLED_ERROR();
}
if (sd->surface != VK_NULL_HANDLE) {
VKSD_ResetSurface(&sd->vksdOps);
J2dRlsTraceLn1(J2D_TRACE_INFO, "WLVKSurfaceData_assignWlSurface(%p): surface reset", vksd);
J2dRlsTraceLn1(J2D_TRACE_INFO,
"WLVKWindowSurfaceData_assignWlSurface(%p): surface reset", vksd);
}
struct wl_surface* wl_surface = (struct wl_surface*)jlong_to_ptr(wlSurfacePtr);
@@ -73,7 +107,8 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_WLVKSurfaceData_assignWlSurface(JN
VK_IF_ERROR(ge->vkCreateWaylandSurfaceKHR(ge->vkInstance, &surfaceCreateInfo, NULL, &sd->surface)) {
VK_UNHANDLED_ERROR();
}
J2dRlsTraceLn1(J2D_TRACE_INFO, "WLVKSurfaceData_assignWlSurface(%p): surface created", vksd);
J2dRlsTraceLn1(J2D_TRACE_INFO,
"WLVKWindowSurfaceData_assignWlSurface(%p): surface created", vksd);
// Swapchain will be created later after CONFIGURE_SURFACE.
}
}