JBR-5645 Provide basic classes for Vulkan rendering pipeline

Implemented shared classes for cross-platform vulkan implementation and some support for wayland toolkit

(cherry picked from commit 9ea3d2d0b1)
This commit is contained in:
Alexey Ushakov
2022-11-11 21:12:43 +01:00
committed by jbrbot
parent 63eebf838d
commit 19aa4d38ce
36 changed files with 4528 additions and 226 deletions

View File

@@ -63,6 +63,7 @@ ifeq ($(call isTargetOs, macosx), true)
sun/awt/wl \
sun/java2d/wl \
sun/java2d/x11 \
sun/java2d/vulkan \
sun/java2d/jules \
sun/java2d/xr \
com/sun/java/swing/plaf/gtk \

View File

@@ -213,6 +213,7 @@ ifeq ($(call isTargetOs, windows macosx), false)
common/awt/debug \
common/font \
common/java2d/opengl \
common/java2d/vulkan \
java.base:libjvm \
#
@@ -237,6 +238,7 @@ ifeq ($(call isTargetOs, windows macosx), false)
OPTIMIZATION := LOW, \
CFLAGS := -DHEADLESS=true $(CUPS_CFLAGS) $(FONTCONFIG_CFLAGS) \
$(X_CFLAGS) $(DBUS_CFLAGS), \
CXXFLAGS := $(CXXFLAGS_JDKLIB), \
EXTRA_HEADER_DIRS := $(LIBAWT_HEADLESS_EXTRA_HEADER_DIRS), \
DISABLED_WARNINGS_gcc := unused-variable, \
DISABLED_WARNINGS_clang := unused-variable, \
@@ -475,7 +477,7 @@ ifeq ($(call isTargetOs, macosx), true)
#
LIBAWT_LWAWT_EXCLUDE_FILES := fontpath.c awt_Font.c X11Color.c
LIBAWT_LWAWT_EXCLUDES := $(TOPDIR)/src/$(MODULE)/unix/native/common/awt/medialib \
LIBAWT_LWAWT_EXCLUDES := \
$(TOPDIR)/src/$(MODULE)/share/native/common/java2d/vulkan \
$(TOPDIR)/src/$(MODULE)/unix/native/common/awt/medialib \
#

View File

@@ -0,0 +1,904 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package sun.java2d.vulkan;
import sun.java2d.SurfaceData;
import sun.java2d.loops.Blit;
import sun.java2d.loops.CompositeType;
import sun.java2d.loops.GraphicsPrimitive;
import sun.java2d.loops.GraphicsPrimitiveMgr;
import sun.java2d.loops.ScaledBlit;
import sun.java2d.loops.SurfaceType;
import sun.java2d.loops.TransformBlit;
import sun.java2d.pipe.Region;
import sun.java2d.pipe.RenderBuffer;
import sun.java2d.pipe.RenderQueue;
import sun.java2d.pipe.hw.AccelSurface;
import java.awt.AlphaComposite;
import java.awt.Composite;
import java.awt.Transparency;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.lang.annotation.Native;
import java.lang.ref.WeakReference;
import static sun.java2d.pipe.BufferedOpCodes.BLIT;
import static sun.java2d.pipe.BufferedOpCodes.SURFACE_TO_SW_BLIT;
final class VKBlitLoops {
static void register() {
Blit blitIntArgbPreToSurface =
new VKSwToSurfaceBlit(SurfaceType.IntArgbPre,
VKSurfaceData.PF_INT_ARGB_PRE);
Blit blitIntArgbPreToTexture =
new VKSwToTextureBlit(SurfaceType.IntArgbPre,
VKSurfaceData.PF_INT_ARGB_PRE);
TransformBlit transformBlitIntArgbPreToSurface =
new VKSwToSurfaceTransform(SurfaceType.IntArgbPre,
VKSurfaceData.PF_INT_ARGB_PRE);
VKSurfaceToSwBlit blitSurfaceToIntArgbPre =
new VKSurfaceToSwBlit(SurfaceType.IntArgbPre,
VKSurfaceData.PF_INT_ARGB_PRE);
GraphicsPrimitive[] primitives = {
// surface->surface ops
new VKSurfaceToSurfaceBlit(),
new VKSurfaceToSurfaceScale(),
new VKSurfaceToSurfaceTransform(),
// render-to-texture surface->surface ops
new VKRTTSurfaceToSurfaceBlit(),
new VKRTTSurfaceToSurfaceScale(),
new VKRTTSurfaceToSurfaceTransform(),
// surface->sw ops
new VKSurfaceToSwBlit(SurfaceType.IntArgb,
VKSurfaceData.PF_INT_ARGB),
blitSurfaceToIntArgbPre,
// sw->surface ops
blitIntArgbPreToSurface,
new VKSwToSurfaceBlit(SurfaceType.IntRgb,
VKSurfaceData.PF_INT_RGB),
new VKSwToSurfaceBlit(SurfaceType.IntRgbx,
VKSurfaceData.PF_INT_RGBX),
new VKSwToSurfaceBlit(SurfaceType.IntBgr,
VKSurfaceData.PF_INT_BGR),
new VKSwToSurfaceBlit(SurfaceType.IntBgrx,
VKSurfaceData.PF_INT_BGRX),
new VKGeneralBlit(VKSurfaceData.VKSurface,
CompositeType.AnyAlpha,
blitIntArgbPreToSurface),
new VKAnyCompositeBlit(VKSurfaceData.VKSurface,
blitSurfaceToIntArgbPre,
blitSurfaceToIntArgbPre,
blitIntArgbPreToSurface),
new VKAnyCompositeBlit(SurfaceType.Any,
null,
blitSurfaceToIntArgbPre,
blitIntArgbPreToSurface),
new VKSwToSurfaceScale(SurfaceType.IntRgb,
VKSurfaceData.PF_INT_RGB),
new VKSwToSurfaceScale(SurfaceType.IntRgbx,
VKSurfaceData.PF_INT_RGBX),
new VKSwToSurfaceScale(SurfaceType.IntBgr,
VKSurfaceData.PF_INT_BGR),
new VKSwToSurfaceScale(SurfaceType.IntBgrx,
VKSurfaceData.PF_INT_BGRX),
new VKSwToSurfaceScale(SurfaceType.IntArgbPre,
VKSurfaceData.PF_INT_ARGB_PRE),
new VKSwToSurfaceTransform(SurfaceType.IntRgb,
VKSurfaceData.PF_INT_RGB),
new VKSwToSurfaceTransform(SurfaceType.IntRgbx,
VKSurfaceData.PF_INT_RGBX),
new VKSwToSurfaceTransform(SurfaceType.IntBgr,
VKSurfaceData.PF_INT_BGR),
new VKSwToSurfaceTransform(SurfaceType.IntBgrx,
VKSurfaceData.PF_INT_BGRX),
transformBlitIntArgbPreToSurface,
new VKGeneralTransformedBlit(transformBlitIntArgbPreToSurface),
// texture->surface ops
new VKTextureToSurfaceBlit(),
new VKTextureToSurfaceScale(),
new VKTextureToSurfaceTransform(),
// sw->texture ops
blitIntArgbPreToTexture,
new VKSwToTextureBlit(SurfaceType.IntRgb,
VKSurfaceData.PF_INT_RGB),
new VKSwToTextureBlit(SurfaceType.IntRgbx,
VKSurfaceData.PF_INT_RGBX),
new VKSwToTextureBlit(SurfaceType.IntBgr,
VKSurfaceData.PF_INT_BGR),
new VKSwToTextureBlit(SurfaceType.IntBgrx,
VKSurfaceData.PF_INT_BGRX),
new VKGeneralBlit(VKSurfaceData.VKTexture,
CompositeType.SrcNoEa,
blitIntArgbPreToTexture),
};
GraphicsPrimitiveMgr.register(primitives);
}
/**
* The following offsets are used to pack the parameters in
* createPackedParams(). (They are also used at the native level when
* unpacking the params.)
*/
@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;
/**
* 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)
{
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));
}
/**
* Enqueues a BLIT operation with the given parameters. Note that the
* RenderQueue lock must be held before calling this method.
*/
private static void enqueueBlit(RenderQueue rq,
SurfaceData src, SurfaceData dst,
int packedParams,
int sx1, int sy1,
int sx2, int sy2,
double dx1, double dy1,
double dx2, double dy2)
{
// assert rq.lock.isHeldByCurrentThread();
RenderBuffer buf = rq.getBuffer();
rq.ensureCapacityAndAlignment(72, 24);
buf.putInt(BLIT);
buf.putInt(packedParams);
buf.putInt(sx1).putInt(sy1);
buf.putInt(sx2).putInt(sy2);
buf.putDouble(dx1).putDouble(dy1);
buf.putDouble(dx2).putDouble(dy2);
buf.putLong(src.getNativeOps());
buf.putLong(dst.getNativeOps());
}
static void Blit(SurfaceData srcData, SurfaceData dstData,
Composite comp, Region clip,
AffineTransform xform, int hint,
int sx1, int sy1,
int sx2, int sy2,
double dx1, double dy1,
double dx2, double dy2,
int srctype, boolean texture)
{
int ctxflags = 0;
if (srcData.getTransparency() == Transparency.OPAQUE) {
ctxflags |= VKContext.SRC_IS_OPAQUE;
}
VKRenderQueue rq = VKRenderQueue.getInstance();
rq.lock();
try {
// make sure the RenderQueue keeps a hard reference to the
// source (sysmem) SurfaceData to prevent it from being
// disposed while the operation is processed on the QFT
rq.addReference(srcData);
VKSurfaceData vkDst = (VKSurfaceData)dstData;
if (texture) {
// make sure we have a current context before uploading
// the sysmem data to the texture object
VKGraphicsConfig gc = vkDst.getGraphicsConfig();
VKContext.setScratchSurface(gc);
} else {
VKContext.validateContext(vkDst, vkDst,
clip, comp, xform, null, null,
ctxflags);
}
int packedParams = createPackedParams(false, texture,
false /*unused*/, xform != null,
hint, srctype);
enqueueBlit(rq, srcData, dstData,
packedParams,
sx1, sy1, sx2, sy2,
dx1, dy1, dx2, dy2);
// always flush immediately, since we (currently) have no means
// of tracking changes to the system memory surface
rq.flushNow();
} finally {
rq.unlock();
}
}
/**
* Note: The srcImg and biop parameters are only used when invoked
* from the VKBufImgOps.renderImageWithOp() method; in all other cases,
* this method can be called with null values for those two parameters,
* and they will be effectively ignored.
*/
static void IsoBlit(SurfaceData srcData, SurfaceData dstData,
BufferedImage srcImg, BufferedImageOp biop,
Composite comp, Region clip,
AffineTransform xform, int hint,
int sx1, int sy1,
int sx2, int sy2,
double dx1, double dy1,
double dx2, double dy2,
boolean texture)
{
int ctxflags = 0;
if (srcData.getTransparency() == Transparency.OPAQUE) {
ctxflags |= VKContext.SRC_IS_OPAQUE;
}
VKRenderQueue rq = VKRenderQueue.getInstance();
rq.lock();
try {
VKSurfaceData vkSrc = (VKSurfaceData)srcData;
VKSurfaceData vkDst = (VKSurfaceData)dstData;
int srctype = vkSrc.getType();
boolean rtt;
VKSurfaceData srcCtxData;
if (srctype == VKSurfaceData.TEXTURE) {
// the source is a regular texture object; we substitute
// the destination surface for the purposes of making a
// context current
rtt = false;
srcCtxData = vkDst;
} else {
// the source is a pbuffer, backbuffer, or render-to-texture
// surface; we set rtt to true to differentiate this kind
// of surface from a regular texture object
rtt = true;
if (srctype == AccelSurface.RT_TEXTURE) {
srcCtxData = vkDst;
} else {
srcCtxData = vkSrc;
}
}
VKContext.validateContext(srcCtxData, vkDst,
clip, comp, xform, null, null,
ctxflags);
if (biop != null) {
VKBufImgOps.enableBufImgOp(rq, vkSrc, srcImg, biop);
}
int packedParams = createPackedParams(true, texture,
false /*unused*/, xform != null,
hint, 0 /*unused*/);
enqueueBlit(rq, srcData, dstData,
packedParams,
sx1, sy1, sx2, sy2,
dx1, dy1, dx2, dy2);
if (biop != null) {
VKBufImgOps.disableBufImgOp(rq, biop);
}
if (rtt && vkDst.isOnScreen()) {
// we only have to flush immediately when copying from a
// (non-texture) surface to the screen; otherwise Swing apps
// might appear unresponsive until the auto-flush completes
rq.flushNow();
}
} finally {
rq.unlock();
}
}
}
class VKSurfaceToSurfaceBlit extends Blit {
VKSurfaceToSurfaceBlit() {
super(VKSurfaceData.VKSurface,
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,
false);
}
}
class VKSurfaceToSurfaceScale extends ScaledBlit {
VKSurfaceToSurfaceScale() {
super(VKSurfaceData.VKSurface,
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,
false);
}
}
class VKSurfaceToSurfaceTransform extends TransformBlit {
VKSurfaceToSurfaceTransform() {
super(VKSurfaceData.VKSurface,
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,
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);
}
}
final class VKSurfaceToSwBlit extends Blit {
private final int typeval;
private WeakReference<SurfaceData> srcTmp;
// destination will actually be ArgbPre or Argb
VKSurfaceToSwBlit(final SurfaceType dstType, final int typeval) {
super(VKSurfaceData.VKSurface,
CompositeType.SrcNoEa,
dstType);
this.typeval = typeval;
}
private synchronized void complexClipBlit(SurfaceData src, SurfaceData dst,
Composite comp, Region clip,
int sx, int sy, int dx, int dy,
int w, int h) {
SurfaceData cachedSrc = null;
if (srcTmp != null) {
// use cached intermediate surface, if available
cachedSrc = srcTmp.get();
}
// We can convert argb_pre data from VK surface in two places:
// - During VK surface -> SW blit
// - During SW -> SW blit
// The first one is faster when we use opaque MTL surface, because in
// this case we simply skip conversion and use color components as is.
// Because of this we align intermediate buffer type with type of
// destination not source.
final int type = typeval == VKSurfaceData.PF_INT_ARGB_PRE ?
BufferedImage.TYPE_INT_ARGB_PRE :
BufferedImage.TYPE_INT_ARGB;
src = convertFrom(this, src, sx, sy, w, h, cachedSrc, type);
// copy intermediate SW to destination SW using complex clip
final Blit performop = Blit.getFromCache(src.getSurfaceType(),
CompositeType.SrcNoEa,
dst.getSurfaceType());
performop.Blit(src, dst, comp, clip, 0, 0, dx, dy, w, h);
if (src != cachedSrc) {
// cache the intermediate surface
srcTmp = new WeakReference<>(src);
}
}
public void Blit(SurfaceData src, SurfaceData dst,
Composite comp, Region clip,
int sx, int sy, int dx, int dy,
int w, int h)
{
if (clip != null) {
clip = clip.getIntersectionXYWH(dx, dy, w, h);
// At the end this method will flush the RenderQueue, we should exit
// from it as soon as possible.
if (clip.isEmpty()) {
return;
}
sx += clip.getLoX() - dx;
sy += clip.getLoY() - dy;
dx = clip.getLoX();
dy = clip.getLoY();
w = clip.getWidth();
h = clip.getHeight();
if (!clip.isRectangular()) {
complexClipBlit(src, dst, comp, clip, sx, sy, dx, dy, w, h);
return;
}
}
VKRenderQueue rq = VKRenderQueue.getInstance();
rq.lock();
try {
// make sure the RenderQueue keeps a hard reference to the
// destination (sysmem) SurfaceData to prevent it from being
// disposed while the operation is processed on the QFT
rq.addReference(dst);
RenderBuffer buf = rq.getBuffer();
VKContext.validateContext((VKSurfaceData)src);
rq.ensureCapacityAndAlignment(48, 32);
buf.putInt(SURFACE_TO_SW_BLIT);
buf.putInt(sx).putInt(sy);
buf.putInt(dx).putInt(dy);
buf.putInt(w).putInt(h);
buf.putInt(typeval);
buf.putLong(src.getNativeOps());
buf.putLong(dst.getNativeOps());
// always flush immediately
rq.flushNow();
} finally {
rq.unlock();
}
}
}
class VKSwToSurfaceBlit extends Blit {
private int typeval;
VKSwToSurfaceBlit(SurfaceType srcType, int typeval) {
super(srcType,
CompositeType.AnyAlpha,
VKSurfaceData.VKSurface);
this.typeval = typeval;
}
public void Blit(SurfaceData src, SurfaceData dst,
Composite comp, Region clip,
int sx, int sy, int dx, int dy, int w, int h)
{
VKBlitLoops.Blit(src, dst,
comp, clip, null,
AffineTransformOp.TYPE_NEAREST_NEIGHBOR,
sx, sy, sx+w, sy+h,
dx, dy, dx+w, dy+h,
typeval, false);
}
}
class VKSwToSurfaceScale extends ScaledBlit {
private int typeval;
VKSwToSurfaceScale(SurfaceType srcType, int typeval) {
super(srcType,
CompositeType.AnyAlpha,
VKSurfaceData.VKSurface);
this.typeval = typeval;
}
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.Blit(src, dst,
comp, clip, null,
AffineTransformOp.TYPE_NEAREST_NEIGHBOR,
sx1, sy1, sx2, sy2,
dx1, dy1, dx2, dy2,
typeval, false);
}
}
class VKSwToSurfaceTransform extends TransformBlit {
private int typeval;
VKSwToSurfaceTransform(SurfaceType srcType, int typeval) {
super(srcType,
CompositeType.AnyAlpha,
VKSurfaceData.VKSurface);
this.typeval = typeval;
}
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.Blit(src, dst,
comp, clip, at, hint,
sx, sy, sx+w, sy+h,
dx, dy, dx+w, dy+h,
typeval, false);
}
}
class VKSwToTextureBlit extends Blit {
private int typeval;
VKSwToTextureBlit(SurfaceType srcType, int typeval) {
super(srcType,
CompositeType.SrcNoEa,
VKSurfaceData.VKTexture);
this.typeval = typeval;
}
public void Blit(SurfaceData src, SurfaceData dst,
Composite comp, Region clip,
int sx, int sy, int dx, int dy, int w, int h)
{
VKBlitLoops.Blit(src, dst,
comp, clip, null,
AffineTransformOp.TYPE_NEAREST_NEIGHBOR,
sx, sy, sx+w, sy+h,
dx, dy, dx+w, dy+h,
typeval, true);
}
}
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
* IntArgbPre->VKSurface/Texture loop to get the intermediate
* (premultiplied) surface down to Metal using simple blit.
*/
class VKGeneralBlit extends Blit {
private final Blit performop;
private WeakReference<SurfaceData> srcTmp;
VKGeneralBlit(SurfaceType dstType,
CompositeType compType,
Blit performop)
{
super(SurfaceType.Any, compType, dstType);
this.performop = performop;
}
public synchronized void Blit(SurfaceData src, SurfaceData dst,
Composite comp, Region clip,
int sx, int sy, int dx, int dy,
int w, int h)
{
Blit convertsrc = Blit.getFromCache(src.getSurfaceType(),
CompositeType.SrcNoEa,
SurfaceType.IntArgbPre);
SurfaceData cachedSrc = null;
if (srcTmp != null) {
// use cached intermediate surface, if available
cachedSrc = srcTmp.get();
}
// convert source to IntArgbPre
src = convertFrom(convertsrc, src, sx, sy, w, h,
cachedSrc, BufferedImage.TYPE_INT_ARGB_PRE);
// copy IntArgbPre intermediate surface to Metal surface
performop.Blit(src, dst, comp, clip,
0, 0, dx, dy, w, h);
if (src != cachedSrc) {
// cache the intermediate surface
srcTmp = new WeakReference<>(src);
}
}
}
/**
* This general TransformedBlit implementation converts any source surface to an
* intermediate IntArgbPre surface, and then uses the more specific
* IntArgbPre->VKSurface/Texture loop to get the intermediate
* (premultiplied) surface down to Metal using simple transformBlit.
*/
final class VKGeneralTransformedBlit extends TransformBlit {
private final TransformBlit performop;
private WeakReference<SurfaceData> srcTmp;
VKGeneralTransformedBlit(final TransformBlit performop) {
super(SurfaceType.Any, CompositeType.AnyAlpha,
VKSurfaceData.VKSurface);
this.performop = performop;
}
@Override
public synchronized void Transform(SurfaceData src, SurfaceData dst,
Composite comp, Region clip,
AffineTransform at, int hint, int srcx,
int srcy, int dstx, int dsty, int width,
int height){
Blit convertsrc = Blit.getFromCache(src.getSurfaceType(),
CompositeType.SrcNoEa,
SurfaceType.IntArgbPre);
// use cached intermediate surface, if available
final SurfaceData cachedSrc = srcTmp != null ? srcTmp.get() : null;
// convert source to IntArgbPre
src = convertFrom(convertsrc, src, srcx, srcy, width, height, cachedSrc,
BufferedImage.TYPE_INT_ARGB_PRE);
// transform IntArgbPre intermediate surface to Metal surface
performop.Transform(src, dst, comp, clip, at, hint, 0, 0, dstx, dsty,
width, height);
if (src != cachedSrc) {
// cache the intermediate surface
srcTmp = new WeakReference<>(src);
}
}
}
/**
* This general VKAnyCompositeBlit implementation can convert any source/target
* surface to an intermediate surface using convertsrc/convertdst loops, applies
* necessary composite operation, and then uses convertresult loop to get the
* intermediate surface down to Metal.
*/
final class VKAnyCompositeBlit extends Blit {
private WeakReference<SurfaceData> dstTmp;
private WeakReference<SurfaceData> srcTmp;
private final Blit convertsrc;
private final Blit convertdst;
private final Blit convertresult;
VKAnyCompositeBlit(SurfaceType srctype, Blit convertsrc, Blit convertdst,
Blit convertresult) {
super(srctype, CompositeType.Any, VKSurfaceData.VKSurface);
this.convertsrc = convertsrc;
this.convertdst = convertdst;
this.convertresult = convertresult;
}
public synchronized void Blit(SurfaceData src, SurfaceData dst,
Composite comp, Region clip,
int sx, int sy, int dx, int dy,
int w, int h)
{
if (convertsrc != null) {
SurfaceData cachedSrc = null;
if (srcTmp != null) {
// use cached intermediate surface, if available
cachedSrc = srcTmp.get();
}
// convert source to IntArgbPre
src = convertFrom(convertsrc, src, sx, sy, w, h, cachedSrc,
BufferedImage.TYPE_INT_ARGB_PRE);
if (src != cachedSrc) {
// cache the intermediate surface
srcTmp = new WeakReference<>(src);
}
}
SurfaceData cachedDst = null;
if (dstTmp != null) {
// use cached intermediate surface, if available
cachedDst = dstTmp.get();
}
// convert destination to IntArgbPre
SurfaceData dstBuffer = convertFrom(convertdst, dst, dx, dy, w, h,
cachedDst, BufferedImage.TYPE_INT_ARGB_PRE);
Region bufferClip =
clip == null ? null : clip.getTranslatedRegion(-dx, -dy);
Blit performop = Blit.getFromCache(src.getSurfaceType(),
CompositeType.Any, dstBuffer.getSurfaceType());
performop.Blit(src, dstBuffer, comp, bufferClip, sx, sy, 0, 0, w, h);
if (dstBuffer != cachedDst) {
// cache the intermediate surface
dstTmp = new WeakReference<>(dstBuffer);
}
// now blit the buffer back to the destination
convertresult.Blit(dstBuffer, dst, AlphaComposite.Src, clip, 0, 0, dx,
dy, w, h);
}
}

View File

@@ -0,0 +1,117 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package sun.java2d.vulkan;
import sun.java2d.SunGraphics2D;
import sun.java2d.SurfaceData;
import sun.java2d.loops.CompositeType;
import sun.java2d.pipe.BufferedBufImgOps;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ConvolveOp;
import java.awt.image.LookupOp;
import java.awt.image.RescaleOp;
import static sun.java2d.vulkan.VKContext.VKContextCaps.CAPS_EXT_BIOP_SHADER;
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
* 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.
*/
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;
}
}

View File

@@ -0,0 +1,98 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package sun.java2d.vulkan;
import sun.java2d.pipe.BufferedContext;
import sun.java2d.pipe.RenderQueue;
import sun.java2d.pipe.hw.ContextCapabilities;
import sun.util.logging.PlatformLogger;
import java.lang.annotation.Native;
/**
* Note that the RenderQueue lock must be acquired before calling any of
* the methods in this class.
*/
final class VKContext extends BufferedContext {
private static final PlatformLogger log =
PlatformLogger.getLogger("sun.java2d.vulkan.VKContext");
public VKContext(RenderQueue rq) {
super(rq);
}
public static void setScratchSurface(VKGraphicsConfig gc) {
log.info("Not implemented: VKContext.setScratchSurface(VKGraphicsConfig)");
}
public static class VKContextCaps extends ContextCapabilities {
/** Indicates that the context is doublebuffered. */
@Native
public static final int CAPS_DOUBLEBUFFERED = (FIRST_PRIVATE_CAP << 0);
/**
* This cap will only be set if the lcdshader system property has been
* enabled and the hardware supports the minimum number of texture units
*/
@Native
static final int CAPS_EXT_LCD_SHADER = (FIRST_PRIVATE_CAP << 1);
/**
* This cap will only be set if the biopshader system property has been
* enabled and the hardware meets our minimum requirements.
*/
@Native
public static final int CAPS_EXT_BIOP_SHADER = (FIRST_PRIVATE_CAP << 2);
/**
* This cap will only be set if the gradshader system property has been
* enabled and the hardware meets our minimum requirements.
*/
@Native
static final int CAPS_EXT_GRAD_SHADER = (FIRST_PRIVATE_CAP << 3);
public VKContextCaps(int caps, String adapterId) {
super(caps, adapterId);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(super.toString());
if ((caps & CAPS_DOUBLEBUFFERED) != 0) {
sb.append("CAPS_DOUBLEBUFFERED|");
}
if ((caps & CAPS_EXT_LCD_SHADER) != 0) {
sb.append("CAPS_EXT_LCD_SHADER|");
}
if ((caps & CAPS_EXT_BIOP_SHADER) != 0) {
sb.append("CAPS_BIOP_SHADER|");
}
if ((caps & CAPS_EXT_GRAD_SHADER) != 0) {
sb.append("CAPS_EXT_GRAD_SHADER|");
}
return sb.toString();
}
}
}

View File

@@ -0,0 +1,115 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package sun.java2d.vulkan;
import sun.java2d.SunGraphics2D;
import sun.java2d.SurfaceData;
import sun.java2d.loops.SurfaceType;
import sun.java2d.loops.TransformBlit;
import sun.java2d.pipe.DrawImage;
import java.awt.Color;
import java.awt.Image;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
public class VKDrawImage extends DrawImage {
@Override
protected void renderImageXform(SunGraphics2D sg, Image img,
AffineTransform tx, int interpType,
int sx1, int sy1, int sx2, int sy2,
Color bgColor)
{
// punt to the MediaLib-based transformImage() in the superclass if:
// - bicubic interpolation is specified
// - a background color is specified and will be used
// - the source surface is neither a texture nor render-to-texture
// surface, and a non-default interpolation hint is specified
// (we can only control the filtering for texture->surface
// copies)
// REMIND: we should tweak the sw->texture->surface
// transform case to handle filtering appropriately
// (see 4841762)...
// - an appropriate TransformBlit primitive could not be found
if (interpType != AffineTransformOp.TYPE_BICUBIC) {
SurfaceData dstData = sg.surfaceData;
SurfaceData srcData =
dstData.getSourceSurfaceData(img,
SunGraphics2D.TRANSFORM_GENERIC,
sg.imageComp,
bgColor);
if (srcData != null &&
!isBgOperation(srcData, bgColor) &&
(srcData.getSurfaceType() == VKSurfaceData.VKTexture ||
srcData.getSurfaceType() == VKSurfaceData.VKSurfaceRTT ||
interpType == AffineTransformOp.TYPE_NEAREST_NEIGHBOR))
{
SurfaceType srcType = srcData.getSurfaceType();
SurfaceType dstType = dstData.getSurfaceType();
TransformBlit blit = TransformBlit.getFromCache(srcType,
sg.imageComp,
dstType);
if (blit != null) {
blit.Transform(srcData, dstData,
sg.composite, sg.getCompClip(),
tx, interpType,
sx1, sy1, 0, 0, sx2-sx1, sy2-sy1);
return;
}
}
}
super.renderImageXform(sg, img, tx, interpType,
sx1, sy1, sx2, sy2, bgColor);
}
@Override
public void transformImage(SunGraphics2D sg, BufferedImage img,
BufferedImageOp op, int x, int y)
{
if (op != null) {
if (op instanceof AffineTransformOp) {
AffineTransformOp atop = (AffineTransformOp) op;
transformImage(sg, img, x, y,
atop.getTransform(),
atop.getInterpolationType());
return;
} else {
if (VKBufImgOps.renderImageWithOp(sg, img, op, x, y)) {
return;
}
}
img = op.filter(img, null);
}
copyImage(sg, img, x, y, null);
}
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package sun.java2d.vulkan;
import sun.awt.image.SurfaceManager;
import sun.java2d.pipe.hw.AccelGraphicsConfig;
public interface VKGraphicsConfig extends AccelGraphicsConfig, SurfaceManager.ProxiedGraphicsConfig {
boolean isCapPresent(int capsExtGradShader);
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package sun.java2d.vulkan;
import sun.java2d.SurfaceData;
import sun.java2d.loops.CompositeType;
import sun.java2d.loops.GraphicsPrimitive;
import sun.java2d.loops.GraphicsPrimitiveMgr;
import sun.java2d.loops.SurfaceType;
import sun.java2d.pipe.BufferedMaskBlit;
import sun.java2d.pipe.Region;
import java.awt.Composite;
import static sun.java2d.loops.CompositeType.SrcNoEa;
import static sun.java2d.loops.CompositeType.SrcOver;
import static sun.java2d.loops.SurfaceType.*;
class VKMaskBlit extends BufferedMaskBlit {
static void register() {
GraphicsPrimitive[] primitives = {
new VKMaskBlit(IntArgb, SrcOver),
new VKMaskBlit(IntArgbPre, SrcOver),
new VKMaskBlit(IntRgb, SrcOver),
new VKMaskBlit(IntRgb, SrcNoEa),
new VKMaskBlit(IntBgr, SrcOver),
new VKMaskBlit(IntBgr, SrcNoEa),
};
GraphicsPrimitiveMgr.register(primitives);
}
private VKMaskBlit(SurfaceType srcType,
CompositeType compType)
{
super(VKRenderQueue.getInstance(),
srcType, compType, VKSurfaceData.VKSurface);
}
@Override
protected void validateContext(SurfaceData dstData,
Composite comp, Region clip)
{
VKSurfaceData vkDst = (VKSurfaceData)dstData;
VKContext.validateContext(vkDst, vkDst,
clip, comp, null, null, null,
VKContext.NO_CONTEXT_FLAGS);
}
}

View File

@@ -0,0 +1,81 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package sun.java2d.vulkan;
import sun.java2d.SunGraphics2D;
import sun.java2d.SurfaceData;
import sun.java2d.loops.CompositeType;
import sun.java2d.loops.GraphicsPrimitive;
import sun.java2d.loops.GraphicsPrimitiveMgr;
import sun.java2d.loops.SurfaceType;
import sun.java2d.pipe.BufferedMaskFill;
import java.awt.Composite;
import static sun.java2d.loops.CompositeType.SrcNoEa;
import static sun.java2d.loops.CompositeType.SrcOver;
import static sun.java2d.loops.SurfaceType.*;
class VKMaskFill extends BufferedMaskFill {
static void register() {
GraphicsPrimitive[] primitives = {
new VKMaskFill(AnyColor, SrcOver),
new VKMaskFill(OpaqueColor, SrcNoEa),
new VKMaskFill(GradientPaint, SrcOver),
new VKMaskFill(OpaqueGradientPaint, SrcNoEa),
new VKMaskFill(LinearGradientPaint, SrcOver),
new VKMaskFill(OpaqueLinearGradientPaint, SrcNoEa),
new VKMaskFill(RadialGradientPaint, SrcOver),
new VKMaskFill(OpaqueRadialGradientPaint, SrcNoEa),
new VKMaskFill(TexturePaint, SrcOver),
new VKMaskFill(OpaqueTexturePaint, SrcNoEa),
};
GraphicsPrimitiveMgr.register(primitives);
}
protected VKMaskFill(SurfaceType srcType, CompositeType compType) {
super(VKRenderQueue.getInstance(),
srcType, compType, VKSurfaceData.VKSurface);
}
@Override
protected native void maskFill(int x, int y, int w, int h,
int maskoff, int maskscan, int masklen,
byte[] mask);
@Override
protected void validateContext(SunGraphics2D sg2d,
Composite comp, int ctxflags)
{
VKSurfaceData dstData = SurfaceData.convertTo(VKSurfaceData.class,
sg2d.surfaceData);
VKContext.validateContext(dstData, dstData,
sg2d.getCompClip(), comp,
null, sg2d.paint, sg2d, ctxflags);
}
}

View File

@@ -0,0 +1,199 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package sun.java2d.vulkan;
import sun.java2d.SunGraphics2D;
import sun.java2d.SurfaceData;
import sun.java2d.loops.CompositeType;
import java.awt.LinearGradientPaint;
import java.awt.MultipleGradientPaint;
import java.awt.TexturePaint;
import java.awt.MultipleGradientPaint.ColorSpaceType;
import java.awt.MultipleGradientPaint.CycleMethod;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.Map;
import static sun.java2d.vulkan.VKContext.VKContextCaps.CAPS_EXT_GRAD_SHADER;
import static sun.java2d.pipe.BufferedPaints.MULTI_MAX_FRACTIONS;
abstract class VKPaints {
/**
* Holds all registered implementations, using the corresponding
* SunGraphics2D.PAINT_* constant as the hash key.
*/
private static Map<Integer, VKPaints> impls = new HashMap<>(4, 1.0f);
static {
impls.put(SunGraphics2D.PAINT_GRADIENT, new Gradient());
impls.put(SunGraphics2D.PAINT_LIN_GRADIENT, new LinearGradient());
impls.put(SunGraphics2D.PAINT_RAD_GRADIENT, new RadialGradient());
impls.put(SunGraphics2D.PAINT_TEXTURE, new Texture());
}
/**
* Attempts to locate an implementation corresponding to the paint state
* of the provided SunGraphics2D object. If no implementation can be
* found, or if the paint cannot be accelerated under the conditions
* of the SunGraphics2D, this method returns false; otherwise, returns
* true.
*/
static boolean isValid(SunGraphics2D sg2d) {
VKPaints impl = impls.get(sg2d.paintState);
return (impl != null && impl.isPaintValid(sg2d));
}
/**
* Returns true if this implementation is able to accelerate the
* Paint object associated with, and under the conditions of, the
* provided SunGraphics2D instance; otherwise returns false.
*/
abstract boolean isPaintValid(SunGraphics2D sg2d);
/************************* GradientPaint support ****************************/
private static class Gradient extends VKPaints {
private Gradient() {}
/**
* There are no restrictions for accelerating GradientPaint, so
* this method always returns true.
*/
@Override
boolean isPaintValid(SunGraphics2D sg2d) {
return true;
}
}
/************************** TexturePaint support ****************************/
private static class Texture extends VKPaints {
private Texture() {}
/**
* Returns true if the given TexturePaint instance can be used by the
* accelerated VKPaints.Texture implementation. A TexturePaint is
* considered valid if the following conditions are met:
* - the texture image dimensions are power-of-two
* - the texture image can be (or is already) cached in an Metal
* texture object
*/
@Override
boolean isPaintValid(SunGraphics2D sg2d) {
TexturePaint paint = (TexturePaint)sg2d.paint;
VKSurfaceData dstData = (VKSurfaceData)sg2d.surfaceData;
BufferedImage bi = paint.getImage();
SurfaceData srcData =
dstData.getSourceSurfaceData(bi,
SunGraphics2D.TRANSFORM_ISIDENT,
CompositeType.SrcOver, null);
if (!(srcData instanceof VKSurfaceData)) {
// REMIND: this is a hack that attempts to cache the system
// memory image from the TexturePaint instance into an
// VK texture...
srcData =
dstData.getSourceSurfaceData(bi,
SunGraphics2D.TRANSFORM_ISIDENT,
CompositeType.SrcOver, null);
if (!(srcData instanceof VKSurfaceData)) {
return false;
}
}
// verify that the source surface is actually a texture
VKSurfaceData vkData = (VKSurfaceData)srcData;
if (vkData.getType() != VKSurfaceData.TEXTURE) {
return false;
}
return true;
}
}
/****************** Shared MultipleGradientPaint support ********************/
private abstract static class MultiGradient extends VKPaints {
protected MultiGradient() {}
/**
* Returns true if the given MultipleGradientPaint instance can be
* used by the accelerated Paints.MultiGradient implementation.
* A MultipleGradientPaint is considered valid if the following
* conditions are met:
* - the number of gradient "stops" is <= MAX_FRACTIONS
* - the destination has support for fragment shaders
*/
@Override
boolean isPaintValid(SunGraphics2D sg2d) {
MultipleGradientPaint paint = (MultipleGradientPaint)sg2d.paint;
// REMIND: ugh, this creates garbage; would be nicer if
// we had a MultipleGradientPaint.getNumStops() method...
if (paint.getFractions().length > MULTI_MAX_FRACTIONS) {
return false;
}
VKSurfaceData dstData = (VKSurfaceData)sg2d.surfaceData;
VKGraphicsConfig gc = dstData.getGraphicsConfig();
if (!gc.isCapPresent(CAPS_EXT_GRAD_SHADER)) {
return false;
}
return true;
}
}
/********************** LinearGradientPaint support *************************/
private static class LinearGradient extends MultiGradient {
private LinearGradient() {}
@Override
boolean isPaintValid(SunGraphics2D sg2d) {
LinearGradientPaint paint = (LinearGradientPaint)sg2d.paint;
if (paint.getFractions().length == 2 &&
paint.getCycleMethod() != CycleMethod.REPEAT &&
paint.getColorSpace() != ColorSpaceType.LINEAR_RGB)
{
// we can delegate to the optimized two-color gradient
// codepath, which does not require fragment shader support
return true;
}
return super.isPaintValid(sg2d);
}
}
/********************** RadialGradientPaint support *************************/
private static class RadialGradient extends MultiGradient {
private RadialGradient() {}
}
}

View File

@@ -0,0 +1,217 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package sun.java2d.vulkan;
import jdk.internal.misc.InnocuousThread;
import sun.java2d.pipe.RenderQueue;
import java.security.AccessController;
import java.security.PrivilegedAction;
import static sun.java2d.pipe.BufferedOpCodes.SYNC;
/**
* VK-specific implementation of RenderQueue. This class provides a
* single (daemon) thread that is responsible for periodically flushing
* the queue.
*/
public class VKRenderQueue extends RenderQueue {
private static VKRenderQueue theInstance;
private final QueueFlusher flusher;
@SuppressWarnings("removal")
private VKRenderQueue() {
/*
* The thread must be a member of a thread group
* which will not get GCed before VM exit.
*/
flusher = AccessController.doPrivileged((PrivilegedAction<QueueFlusher>) QueueFlusher::new);
}
/**
* Returns the single VKRenderQueue instance. If it has not yet been
* initialized, this method will first construct the single instance
* before returning it.
*/
public static synchronized VKRenderQueue getInstance() {
if (theInstance == null) {
theInstance = new VKRenderQueue();
}
return theInstance;
}
/**
* Flushes the single VKRenderQueue instance synchronously. If an
* VKRenderQueue has not yet been instantiated, this method is a no-op.
* This method is useful in the case of Toolkit.sync(), in which we want
* to flush the Vulkan pipeline, but only if the Vulkan pipeline is currently
* enabled.
*/
public static void sync() {
if (theInstance != null) {
theInstance.lock();
try {
theInstance.ensureCapacity(4);
theInstance.getBuffer().putInt(SYNC);
theInstance.flushNow();
} finally {
theInstance.unlock();
}
}
}
@Override
public void flushNow() {
// assert lock.isHeldByCurrentThread();
try {
flusher.flushNow();
} catch (Exception e) {
System.err.println("exception in flushNow:");
e.printStackTrace();
}
}
public void flushAndInvokeNow(Runnable r) {
// assert lock.isHeldByCurrentThread();
try {
flusher.flushAndInvokeNow(r);
} catch (Exception e) {
System.err.println("exception in flushAndInvokeNow:");
e.printStackTrace();
}
}
private native void flushBuffer(long buf, int limit);
private void flushBuffer() {
// assert lock.isHeldByCurrentThread();
int limit = buf.position();
if (limit > 0) {
// process the queue
flushBuffer(buf.getAddress(), limit);
}
// reset the buffer position
buf.clear();
// clear the set of references, since we no longer need them
refSet.clear();
}
private class QueueFlusher implements Runnable {
private boolean needsFlush;
private Runnable task;
private Error error;
private final Thread thread;
public QueueFlusher() {
thread = InnocuousThread.newThread("Java2D Queue Flusher", this);
thread.setDaemon(true);
thread.setPriority(Thread.MAX_PRIORITY);
thread.start();
}
public synchronized void flushNow() {
// wake up the flusher
needsFlush = true;
notify();
// wait for flush to complete
while (needsFlush) {
try {
wait();
} catch (InterruptedException e) {
}
}
// re-throw any error that may have occurred during the flush
if (error != null) {
throw error;
}
}
public synchronized void flushAndInvokeNow(Runnable task) {
this.task = task;
flushNow();
}
public synchronized void run() {
boolean timedOut = false;
while (true) {
while (!needsFlush) {
try {
timedOut = false;
/*
* Wait until we're woken up with a flushNow() call,
* or the timeout period elapses (so that we can
* flush the queue periodically).
*/
wait(100);
/*
* We will automatically flush the queue if the
* following conditions apply:
* - the wait() timed out
* - we can lock the queue (without blocking)
* - there is something in the queue to flush
* Otherwise, just continue (we'll flush eventually).
*/
if (!needsFlush && (timedOut = tryLock())) {
if (buf.position() > 0) {
needsFlush = true;
} else {
unlock();
}
}
} catch (InterruptedException e) {
}
}
try {
// reset the throwable state
error = null;
// flush the buffer now
flushBuffer();
// if there's a task, invoke that now as well
if (task != null) {
task.run();
}
} catch (Error e) {
error = e;
} catch (Exception x) {
System.err.println("exception in QueueFlusher:");
x.printStackTrace();
} finally {
if (timedOut) {
unlock();
}
task = null;
// allow the waiting thread to continue
needsFlush = false;
notify();
}
}
}
}
}

View File

@@ -0,0 +1,221 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package sun.java2d.vulkan;
import sun.java2d.SunGraphics2D;
import sun.java2d.SurfaceData;
import sun.java2d.loops.GraphicsPrimitive;
import sun.java2d.pipe.BufferedRenderPipe;
import sun.java2d.pipe.ParallelogramPipe;
import sun.java2d.pipe.RenderQueue;
import sun.java2d.pipe.SpanIterator;
import java.awt.Transparency;
import java.awt.geom.Path2D;
import sun.util.logging.PlatformLogger;
import static sun.java2d.pipe.BufferedOpCodes.COPY_AREA;
class VKRenderer extends BufferedRenderPipe {
private static final PlatformLogger log =
PlatformLogger.getLogger("sun.java2d.vulkan.VKRenderer");
VKRenderer(RenderQueue rq) {
super(rq);
}
@Override
protected void validateContext(SunGraphics2D sg2d) {
int ctxflags =
sg2d.paint.getTransparency() == Transparency.OPAQUE ?
VKContext.SRC_IS_OPAQUE : VKContext.NO_CONTEXT_FLAGS;
VKSurfaceData dstData = SurfaceData.convertTo(VKSurfaceData.class,
sg2d.surfaceData);
VKContext.validateContext(dstData, dstData,
sg2d.getCompClip(), sg2d.composite,
null, sg2d.paint, sg2d, ctxflags);
}
@Override
protected void validateContextAA(SunGraphics2D sg2d) {
int ctxflags = VKContext.NO_CONTEXT_FLAGS;
VKSurfaceData dstData = SurfaceData.convertTo(VKSurfaceData.class,
sg2d.surfaceData);
VKContext.validateContext(dstData, dstData,
sg2d.getCompClip(), sg2d.composite,
null, sg2d.paint, sg2d, ctxflags);
}
void copyArea(SunGraphics2D sg2d,
int x, int y, int w, int h, int dx, int dy)
{
rq.lock();
try {
int ctxflags =
sg2d.surfaceData.getTransparency() == Transparency.OPAQUE ?
VKContext.SRC_IS_OPAQUE : VKContext.NO_CONTEXT_FLAGS;
VKSurfaceData dstData = SurfaceData.convertTo(VKSurfaceData.class,
sg2d.surfaceData);
VKContext.validateContext(dstData, dstData,
sg2d.getCompClip(), sg2d.composite,
null, null, null, ctxflags);
rq.ensureCapacity(28);
buf.putInt(COPY_AREA);
buf.putInt(x).putInt(y).putInt(w).putInt(h);
buf.putInt(dx).putInt(dy);
} finally {
rq.unlock();
}
}
@Override
protected void drawPoly(int[] xPoints, int[] yPoints,
int nPoints, boolean isClosed,
int transX, int transY) {
log.info("Not implemented: VKRenderer.drawPoly(int[] xPoints, int[] yPoints,\n" +
" int nPoints, boolean isClosed,\n" +
" int transX, int transY)");
}
VKRenderer traceWrap() {
return new Tracer(this);
}
private static class Tracer extends VKRenderer {
private VKRenderer vkr;
Tracer(VKRenderer vkr) {
super(vkr.rq);
this.vkr = vkr;
}
public ParallelogramPipe getAAParallelogramPipe() {
final ParallelogramPipe realpipe = vkr.getAAParallelogramPipe();
return new ParallelogramPipe() {
public void fillParallelogram(SunGraphics2D sg2d,
double ux1, double uy1,
double ux2, double uy2,
double x, double y,
double dx1, double dy1,
double dx2, double dy2)
{
GraphicsPrimitive.tracePrimitive("VKFillAAParallelogram");
realpipe.fillParallelogram(sg2d,
ux1, uy1, ux2, uy2,
x, y, dx1, dy1, dx2, dy2);
}
public void drawParallelogram(SunGraphics2D sg2d,
double ux1, double uy1,
double ux2, double uy2,
double x, double y,
double dx1, double dy1,
double dx2, double dy2,
double lw1, double lw2)
{
GraphicsPrimitive.tracePrimitive("VKDrawAAParallelogram");
realpipe.drawParallelogram(sg2d,
ux1, uy1, ux2, uy2,
x, y, dx1, dy1, dx2, dy2,
lw1, lw2);
}
};
}
protected void validateContext(SunGraphics2D sg2d) {
vkr.validateContext(sg2d);
}
public void drawLine(SunGraphics2D sg2d,
int x1, int y1, int x2, int y2)
{
GraphicsPrimitive.tracePrimitive("VKDrawLine");
vkr.drawLine(sg2d, x1, y1, x2, y2);
}
public void drawRect(SunGraphics2D sg2d, int x, int y, int w, int h) {
GraphicsPrimitive.tracePrimitive("VKDrawRect");
vkr.drawRect(sg2d, x, y, w, h);
}
protected void drawPoly(SunGraphics2D sg2d,
int[] xPoints, int[] yPoints,
int nPoints, boolean isClosed)
{
GraphicsPrimitive.tracePrimitive("VKDrawPoly");
vkr.drawPoly(sg2d, xPoints, yPoints, nPoints, isClosed);
}
public void fillRect(SunGraphics2D sg2d, int x, int y, int w, int h) {
GraphicsPrimitive.tracePrimitive("VKFillRect");
vkr.fillRect(sg2d, x, y, w, h);
}
protected void drawPath(SunGraphics2D sg2d,
Path2D.Float p2df, int transx, int transy)
{
GraphicsPrimitive.tracePrimitive("VKDrawPath");
vkr.drawPath(sg2d, p2df, transx, transy);
}
protected void fillPath(SunGraphics2D sg2d,
Path2D.Float p2df, int transx, int transy)
{
GraphicsPrimitive.tracePrimitive("VKFillPath");
vkr.fillPath(sg2d, p2df, transx, transy);
}
protected void fillSpans(SunGraphics2D sg2d, SpanIterator si,
int transx, int transy)
{
GraphicsPrimitive.tracePrimitive("VKFillSpans");
vkr.fillSpans(sg2d, si, transx, transy);
}
public void fillParallelogram(SunGraphics2D sg2d,
double ux1, double uy1,
double ux2, double uy2,
double x, double y,
double dx1, double dy1,
double dx2, double dy2)
{
GraphicsPrimitive.tracePrimitive("VKFillParallelogram");
vkr.fillParallelogram(sg2d,
ux1, uy1, ux2, uy2,
x, y, dx1, dy1, dx2, dy2);
}
public void drawParallelogram(SunGraphics2D sg2d,
double ux1, double uy1,
double ux2, double uy2,
double x, double y,
double dx1, double dy1,
double dx2, double dy2,
double lw1, double lw2)
{
GraphicsPrimitive.tracePrimitive("VKDrawParallelogram");
vkr.drawParallelogram(sg2d,
ux1, uy1, ux2, uy2,
x, y, dx1, dy1, dx2, dy2, lw1, lw2);
}
public void copyArea(SunGraphics2D sg2d,
int x, int y, int w, int h, int dx, int dy)
{
GraphicsPrimitive.tracePrimitive("VKCopyArea");
vkr.copyArea(sg2d, x, y, w, h, dx, dy);
}
}
}

View File

@@ -0,0 +1,304 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package sun.java2d.vulkan;
import java.awt.AlphaComposite;
import sun.awt.SunHints;
import sun.awt.image.PixelConverter;
import sun.java2d.SunGraphics2D;
import sun.java2d.SurfaceData;
import sun.java2d.loops.CompositeType;
import sun.java2d.loops.GraphicsPrimitive;
import sun.java2d.loops.SurfaceType;
import sun.java2d.pipe.ParallelogramPipe;
import sun.java2d.pipe.PixelToParallelogramConverter;
import sun.java2d.pipe.RenderBuffer;
import sun.java2d.pipe.TextPipe;
import sun.java2d.pipe.hw.AccelSurface;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.image.ColorModel;
import java.awt.image.Raster;
import static sun.java2d.pipe.BufferedOpCodes.FLUSH_SURFACE;
import static sun.java2d.pipe.hw.ContextCapabilities.CAPS_PS30;
public abstract class VKSurfaceData extends SurfaceData
implements AccelSurface {
/**
* Pixel formats
*/
public static final int PF_INT_ARGB = 0;
public static final int PF_INT_ARGB_PRE = 1;
public static final int PF_INT_RGB = 2;
public static final int PF_INT_RGBX = 3;
public static final int PF_INT_BGR = 4;
public static final int PF_INT_BGRX = 5;
public static final int PF_USHORT_565_RGB = 6;
public static final int PF_USHORT_555_RGB = 7;
public static final int PF_USHORT_555_RGBX = 8;
public static final int PF_BYTE_GRAY = 9;
public static final int PF_USHORT_GRAY = 10;
public static final int PF_3BYTE_BGR = 11;
/**
* SurfaceTypes
*/
private static final String DESC_VK_SURFACE = "VK Surface";
private static final String DESC_VK_SURFACE_RTT =
"VK Surface (render-to-texture)";
private static final String DESC_VK_TEXTURE = "VK Texture";
static final SurfaceType VKSurface =
SurfaceType.Any.deriveSubType(DESC_VK_SURFACE,
PixelConverter.ArgbPre.instance);
static final SurfaceType VKSurfaceRTT =
VKSurface.deriveSubType(DESC_VK_SURFACE_RTT);
static final SurfaceType VKTexture =
SurfaceType.Any.deriveSubType(DESC_VK_TEXTURE);
protected static VKRenderer vkRenderPipe;
protected static PixelToParallelogramConverter vkTxRenderPipe;
protected static ParallelogramPipe vkAAPgramPipe;
protected static VKTextRenderer vkTextPipe;
protected static VKDrawImage vkImagePipe;
static {
if (!GraphicsEnvironment.isHeadless()) {
VKRenderQueue rq = VKRenderQueue.getInstance();
vkImagePipe = new VKDrawImage();
vkTextPipe = new VKTextRenderer(rq);
vkRenderPipe = new VKRenderer(rq);
if (GraphicsPrimitive.tracingEnabled()) {
vkTextPipe = vkTextPipe.traceWrap();
//The wrapped vkRenderPipe will wrap the AA pipe as well...
vkAAPgramPipe = vkRenderPipe.traceWrap();
}
vkAAPgramPipe = vkRenderPipe.getAAParallelogramPipe();
vkTxRenderPipe =
new PixelToParallelogramConverter(vkRenderPipe, vkRenderPipe, 1.0, 0.25, true);
VKBlitLoops.register();
VKMaskFill.register();
VKMaskBlit.register();
}
}
protected final int scale;
protected final int width;
protected final int height;
protected int type;
private VKGraphicsConfig graphicsConfig;
// these fields are set from the native code when the surface is
// initialized
private int nativeWidth;
private int nativeHeight;
/**
* Returns the appropriate SurfaceType corresponding to the given Metal
* surface type constant (e.g. TEXTURE -> MTLTexture).
*/
private static SurfaceType getCustomSurfaceType(int vkType) {
switch (vkType) {
case TEXTURE:
return VKTexture;
case RT_TEXTURE:
return VKSurfaceRTT;
default:
return VKSurface;
}
}
protected VKSurfaceData(VKGraphicsConfig gc, ColorModel cm, int type, int width, int height)
{
super(getCustomSurfaceType(type), cm);
this.graphicsConfig = gc;
this.type = type;
setBlitProxyKey(gc.getProxyKey());
// TEXTURE shouldn't be scaled, it is used for managed BufferedImages.
scale = 1;
this.width = width * scale;
this.height = height * scale;
}
/**
* Returns one of the surface type constants defined above.
*/
public final int getType() {
return type;
}
public void flush() {
invalidate();
VKRenderQueue rq = VKRenderQueue.getInstance();
rq.lock();
try {
RenderBuffer buf = rq.getBuffer();
rq.ensureCapacityAndAlignment(12, 4);
buf.putInt(FLUSH_SURFACE);
buf.putLong(getNativeOps());
// this call is expected to complete synchronously, so flush now
rq.flushNow();
} finally {
rq.unlock();
}
}
public Raster getRaster(int x, int y, int w, int h) {
throw new InternalError("not implemented yet");
}
public Rectangle getNativeBounds() {
VKRenderQueue rq = VKRenderQueue.getInstance();
rq.lock();
try {
return new Rectangle(nativeWidth, nativeHeight);
} finally {
rq.unlock();
}
}
public void validatePipe(SunGraphics2D sg2d) {
TextPipe textpipe;
boolean validated = false;
// MTLTextRenderer handles both AA and non-AA text, but
// only works with the following modes:
// (Note: For LCD text we only enter this code path if
// canRenderLCDText() has already validated that the mode is
// CompositeType.SrcNoEa (opaque color), which will be subsumed
// by the CompositeType.SrcNoEa (any color) test below.)
if (/* CompositeType.SrcNoEa (any color) */
(sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY &&
sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR) ||
/* CompositeType.SrcOver (any color) */
(sg2d.compositeState == SunGraphics2D.COMP_ALPHA &&
sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR &&
(((AlphaComposite)sg2d.composite).getRule() ==
AlphaComposite.SRC_OVER)) ||
/* CompositeType.Xor (any color) */
(sg2d.compositeState == SunGraphics2D.COMP_XOR &&
sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR))
{
textpipe = vkTextPipe;
} else {
// do this to initialize textpipe correctly; we will attempt
// to override the non-text pipes below
super.validatePipe(sg2d);
textpipe = sg2d.textpipe;
validated = true;
}
PixelToParallelogramConverter txPipe = null;
VKRenderer nonTxPipe = null;
if (sg2d.antialiasHint != SunHints.INTVAL_ANTIALIAS_ON) {
if (sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR) {
if (sg2d.compositeState <= SunGraphics2D.COMP_XOR) {
txPipe = vkTxRenderPipe;
nonTxPipe = vkRenderPipe;
}
} else if (sg2d.compositeState <= SunGraphics2D.COMP_ALPHA) {
if (VKPaints.isValid(sg2d)) {
txPipe = vkTxRenderPipe;
nonTxPipe = vkRenderPipe;
}
// custom paints handled by super.validatePipe() below
}
} else {
if (sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR) {
if (graphicsConfig.isCapPresent(CAPS_PS30) &&
(sg2d.imageComp == CompositeType.SrcOverNoEa ||
sg2d.imageComp == CompositeType.SrcOver))
{
if (!validated) {
super.validatePipe(sg2d);
validated = true;
}
PixelToParallelogramConverter aaConverter =
new PixelToParallelogramConverter(sg2d.shapepipe,
vkAAPgramPipe,
1.0/8.0, 0.499,
false);
sg2d.drawpipe = aaConverter;
sg2d.fillpipe = aaConverter;
sg2d.shapepipe = aaConverter;
} else if (sg2d.compositeState == SunGraphics2D.COMP_XOR) {
// install the solid pipes when AA and XOR are both enabled
txPipe = vkTxRenderPipe;
nonTxPipe = vkRenderPipe;
}
}
// other cases handled by super.validatePipe() below
}
if (txPipe != null) {
if (sg2d.transformState >= SunGraphics2D.TRANSFORM_TRANSLATESCALE) {
sg2d.drawpipe = txPipe;
sg2d.fillpipe = txPipe;
} else if (sg2d.strokeState != SunGraphics2D.STROKE_THIN) {
sg2d.drawpipe = txPipe;
sg2d.fillpipe = nonTxPipe;
} else {
sg2d.drawpipe = nonTxPipe;
sg2d.fillpipe = nonTxPipe;
}
// Note that we use the transforming pipe here because it
// will examine the shape and possibly perform an optimized
// operation if it can be simplified. The simplifications
// will be valid for all STROKE and TRANSFORM types.
sg2d.shapepipe = txPipe;
} else {
if (!validated) {
super.validatePipe(sg2d);
}
}
sg2d.textpipe = textpipe;
// always override the image pipe with the specialized VK pipe
sg2d.imagepipe = vkImagePipe;
}
public VKGraphicsConfig getGraphicsConfig() {
return graphicsConfig;
}
public abstract boolean isOnScreen();
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package sun.java2d.vulkan;
import sun.font.GlyphList;
import sun.java2d.SunGraphics2D;
import sun.java2d.loops.GraphicsPrimitive;
import sun.java2d.pipe.BufferedTextPipe;
import sun.java2d.pipe.RenderQueue;
import java.awt.Composite;
class VKTextRenderer extends BufferedTextPipe {
VKTextRenderer(RenderQueue rq) {
super(rq);
}
@Override
protected native void drawGlyphList(int numGlyphs, boolean usePositions,
boolean subPixPos, boolean rgbOrder,
int lcdContrast,
float glOrigX, float glOrigY,
long[] images, float[] positions);
@Override
protected void validateContext(SunGraphics2D sg2d, Composite comp) {
// assert rq.lock.isHeldByCurrentThread();
VKSurfaceData mtlDst = (VKSurfaceData)sg2d.surfaceData;
VKContext.validateContext(mtlDst, mtlDst,
sg2d.getCompClip(), comp,
null, sg2d.paint, sg2d,
VKContext.NO_CONTEXT_FLAGS);
}
VKTextRenderer traceWrap() {
return new Tracer(this);
}
private static class Tracer extends VKTextRenderer {
Tracer(VKTextRenderer mtltr) {
super(mtltr.rq);
}
protected void drawGlyphList(SunGraphics2D sg2d, GlyphList gl) {
GraphicsPrimitive.tracePrimitive("VKDrawGlyphs");
super.drawGlyphList(sg2d, gl);
}
}
}

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 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,12 +31,10 @@
#define VALIDATION_LAYER_NAME "VK_LAYER_KHRONOS_validation"
static const uint32_t REQUIRED_VULKAN_VERSION = VK_MAKE_API_VERSION(0, 1, 0, 0);
std::unique_ptr<VKGraphicsEnvironment> VKGraphicsEnvironment::_ge_instance = nullptr;
// ========== Vulkan instance ==========
static vk::raii::Context* context = nullptr;
vk::raii::Instance vkInstance = nullptr;
#if defined(DEBUG)
static vk::raii::DebugUtilsMessengerEXT debugMessenger = nullptr;
@@ -63,118 +62,6 @@ static VkBool32 debugCallback(
}
#endif
static bool createInstance() {
try {
// Load library.
vk::raii::Context ctx;
uint32_t version = ctx.enumerateInstanceVersion();
J2dRlsTrace3(J2D_TRACE_INFO, "Vulkan: Available (%d.%d.%d)\n",
VK_API_VERSION_MAJOR(version), VK_API_VERSION_MINOR(version), VK_API_VERSION_PATCH(version));
if (version < REQUIRED_VULKAN_VERSION) {
J2dRlsTrace(J2D_TRACE_ERROR, "Vulkan: Unsupported version\n");
return false;
}
// Populate maps and log supported layers & extensions.
std::set<std::string> layers, extensions;
J2dRlsTrace(J2D_TRACE_VERBOSE, " Supported instance layers:\n");
for (auto& l : ctx.enumerateInstanceLayerProperties()) {
J2dRlsTrace1(J2D_TRACE_VERBOSE, " %s\n", (char*) l.layerName);
layers.emplace((char*) l.layerName);
}
J2dRlsTrace(J2D_TRACE_VERBOSE, " Supported instance extensions:\n");
for (auto& e : ctx.enumerateInstanceExtensionProperties(nullptr)) {
J2dRlsTrace1(J2D_TRACE_VERBOSE, " %s\n", (char*) e.extensionName);
extensions.emplace((char*) e.extensionName);
}
std::vector<const char*> enabledLayers, enabledExtensions;
const void* pNext = nullptr;
// Check required layers & extensions.
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
enabledExtensions.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
#endif
enabledExtensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
bool requiredNotFound = false;
for (auto e : enabledExtensions) {
if (extensions.find(e) == extensions.end()) {
J2dRlsTrace1(J2D_TRACE_ERROR, "Vulkan: Required instance extension not supported: %s\n", (char*) e);
requiredNotFound = true;
}
}
if (requiredNotFound) return false;
// Configure validation
#ifdef DEBUG
std::array<vk::ValidationFeatureEnableEXT, 4> enabledValidationFeatures = {
vk::ValidationFeatureEnableEXT::eGpuAssisted,
vk::ValidationFeatureEnableEXT::eGpuAssistedReserveBindingSlot,
vk::ValidationFeatureEnableEXT::eBestPractices,
vk::ValidationFeatureEnableEXT::eSynchronizationValidation
};
vk::ValidationFeaturesEXT validationFeatures {enabledValidationFeatures};
if (layers.find(VALIDATION_LAYER_NAME) != layers.end() &&
extensions.find(VK_EXT_DEBUG_UTILS_EXTENSION_NAME) != extensions.end()) {
enabledLayers.push_back(VALIDATION_LAYER_NAME);
enabledExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
pNext = &validationFeatures;
} else {
J2dRlsTrace2(J2D_TRACE_WARNING, "Vulkan: %s and %s are not supported\n",
VALIDATION_LAYER_NAME, VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
}
#endif
vk::ApplicationInfo applicationInfo {
/*pApplicationName*/ "OpenJDK",
/*applicationVersion*/ 0,
/*pEngineName*/ "OpenJDK",
/*engineVersion*/ 0,
/*apiVersion*/ REQUIRED_VULKAN_VERSION
};
vk::InstanceCreateInfo instanceCreateInfo {
/*flags*/ {},
/*pApplicationInfo*/ &applicationInfo,
/*ppEnabledLayerNames*/ enabledLayers,
/*ppEnabledExtensionNames*/ enabledExtensions,
/*pNext*/ pNext
};
// Save context object at persistent address before passing it further.
context = new vk::raii::Context(std::move(ctx));
vkInstance = vk::raii::Instance(*context, instanceCreateInfo);
J2dRlsTrace(J2D_TRACE_INFO, "Vulkan: Instance created\n");
// Create debug messenger
#if defined(DEBUG)
if (pNext) {
debugMessenger = vk::raii::DebugUtilsMessengerEXT(vkInstance, vk::DebugUtilsMessengerCreateInfoEXT {
/*flags*/ {},
/*messageSeverity*/ vk::DebugUtilsMessageSeverityFlagBitsEXT::eError |
vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning |
vk::DebugUtilsMessageSeverityFlagBitsEXT::eInfo |
vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose,
/*messageType*/ vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral |
vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation |
vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance,
/*pfnUserCallback*/ &debugCallback
});
}
#endif
return true;
} catch (std::exception& e) {
// Usually this means we didn't find the shared library.
J2dRlsTrace1(J2D_TRACE_ERROR, "Vulkan: %s\n", e.what());
return false;
}
}
// ========== Vulkan device ==========
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
@@ -182,23 +69,35 @@ extern struct wl_display *wl_display;
#endif
class PhysicalDevice : vk::raii::PhysicalDevice {
friend class Device;
bool supported = false;
int queueFamily = -1;
std::vector<const char*> enabledLayers, enabledExtensions;
friend class VKDevice;
bool _supported = false;
std::vector<const char*> _enabled_layers, _enabled_extensions;
int _queue_family = -1;
public:
PhysicalDevice(vk::raii::PhysicalDevice&& handle) : vk::raii::PhysicalDevice(std::move(handle)) {
int queue_family() const {
return _queue_family;
}
std::vector<const char *> & enabled_layers() {
return _enabled_layers;
}
std::vector<const char *> & enabled_extensions() {
return _enabled_extensions;
}
explicit PhysicalDevice(vk::raii::PhysicalDevice&& handle) : vk::raii::PhysicalDevice(std::move(handle)) {
const auto& properties = getProperties();
const auto& queueFamilies = getQueueFamilyProperties();
J2dRlsTrace5(J2D_TRACE_INFO, "Vulkan: Found device %s (%d.%d.%d, %s)\n",
(const char*) properties.deviceName,
VK_API_VERSION_MAJOR(properties.apiVersion),
VK_API_VERSION_MINOR(properties.apiVersion),
VK_API_VERSION_PATCH(properties.apiVersion),
vk::to_string(properties.deviceType).c_str());
(const char*) properties.deviceName,
VK_API_VERSION_MAJOR(properties.apiVersion),
VK_API_VERSION_MINOR(properties.apiVersion),
VK_API_VERSION_PATCH(properties.apiVersion),
vk::to_string(properties.deviceType).c_str());
if (properties.apiVersion < REQUIRED_VULKAN_VERSION) {
J2dRlsTrace(J2D_TRACE_INFO, " Unsupported Vulkan version\n");
return;
@@ -220,11 +119,12 @@ public:
J2dRlsTrace3(J2D_TRACE_INFO, " %d queues in family (%.*s)\n", family.queueCount, 5, logFlags);
// TODO use compute workloads? Separate transfer-only DMA queue?
if (queueFamily == -1 && (family.queueFlags & vk::QueueFlagBits::eGraphics) && presentationSupported) {
queueFamily = i;
if (_queue_family == -1 && (family.queueFlags & vk::QueueFlagBits::eGraphics) && presentationSupported) {
_queue_family = i;
}
}
if (queueFamily == -1) {
if (_queue_family == -1) {
J2dRlsTrace(J2D_TRACE_INFO, " No suitable queue\n");
return;
}
@@ -243,9 +143,9 @@ public:
}
// Check required layers & extensions.
enabledExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
_enabled_extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
bool requiredNotFound = false;
for (auto e : enabledExtensions) {
for (auto e : _enabled_extensions) {
if (extensions.find(e) == extensions.end()) {
J2dRlsTrace1(J2D_TRACE_INFO, " Required device extension not supported: %s\n", (char*) e);
requiredNotFound = true;
@@ -256,81 +156,205 @@ public:
// Validation layer
#ifdef DEBUG
if (layers.find(VALIDATION_LAYER_NAME) != layers.end()) {
enabledLayers.push_back(VALIDATION_LAYER_NAME);
_enabled_layers.push_back(VALIDATION_LAYER_NAME);
} else {
J2dRlsTrace1(J2D_TRACE_INFO, " %s device layer is not supported\n", VALIDATION_LAYER_NAME);
}
#endif
// This device is supported
supported = true;
_supported = true;
}
operator bool() const {
vk::PhysicalDevice handle = **this;
return handle && supported;
return handle && _supported;
}
uint32_t getMaxImageDimension2D() {
const auto& properties = getProperties();
return properties.limits.maxImageDimension2D;
}
};
Device::Device(const PhysicalDevice& physicalDevice) : vk::raii::Device(nullptr) {
VKGraphicsEnvironment *VKGraphicsEnvironment::graphics_environment() {
if (!_ge_instance) {
try {
_ge_instance = std::unique_ptr<VKGraphicsEnvironment>(new VKGraphicsEnvironment());
}
catch (std::exception& e) {
J2dRlsTrace1(J2D_TRACE_ERROR, "Vulkan: %s\n", e.what());
return nullptr;
}
}
return _ge_instance.get();
}
VKGraphicsEnvironment::VKGraphicsEnvironment() :
_vk_context(), _vk_instance(nullptr), _default_device(-1) {
// Load library.
uint32_t version = _vk_context.enumerateInstanceVersion();
J2dRlsTrace3(J2D_TRACE_INFO, "Vulkan: Available (%d.%d.%d)\n",
VK_API_VERSION_MAJOR(version), VK_API_VERSION_MINOR(version), VK_API_VERSION_PATCH(version));
if (version < REQUIRED_VULKAN_VERSION) {
throw std::runtime_error("Vulkan: Unsupported version");
}
// Populate maps and log supported layers & extensions.
std::set<std::string> layers, extensions;
J2dRlsTrace(J2D_TRACE_VERBOSE, " Supported instance layers:\n");
for (auto &l: _vk_context.enumerateInstanceLayerProperties()) {
J2dRlsTrace1(J2D_TRACE_VERBOSE, " %s\n", (char *) l.layerName);
layers.emplace((char *) l.layerName);
}
J2dRlsTrace(J2D_TRACE_VERBOSE, " Supported instance extensions:\n");
for (auto &e: _vk_context.enumerateInstanceExtensionProperties(nullptr)) {
J2dRlsTrace1(J2D_TRACE_VERBOSE, " %s\n", (char *) e.extensionName);
extensions.emplace((char *) e.extensionName);
}
std::vector<const char *> enabledLayers, enabledExtensions;
const void *pNext = nullptr;
// Check required layers & extensions.
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
enabledExtensions.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
#endif
enabledExtensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
for (auto e: enabledExtensions) {
if (extensions.find(e) == extensions.end()) {
throw std::runtime_error(std::string("Vulkan: Required instance extension not supported:") +
(char *) e);
}
}
// Configure validation
#ifdef DEBUG
std::array<vk::ValidationFeatureEnableEXT, 4> enabledValidationFeatures = {
vk::ValidationFeatureEnableEXT::eGpuAssisted,
vk::ValidationFeatureEnableEXT::eGpuAssistedReserveBindingSlot,
vk::ValidationFeatureEnableEXT::eBestPractices,
vk::ValidationFeatureEnableEXT::eSynchronizationValidation
};
vk::ValidationFeaturesEXT validationFeatures {enabledValidationFeatures};
if (layers.find(VALIDATION_LAYER_NAME) != layers.end() &&
extensions.find(VK_EXT_DEBUG_UTILS_EXTENSION_NAME) != extensions.end()) {
enabledLayers.push_back(VALIDATION_LAYER_NAME);
enabledExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
pNext = &validationFeatures;
} else {
J2dRlsTrace2(J2D_TRACE_WARNING, "Vulkan: %s and %s are not supported\n",
VALIDATION_LAYER_NAME, VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
}
#endif
vk::ApplicationInfo applicationInfo{
/*pApplicationName*/ "OpenJDK",
/*applicationVersion*/ 0,
/*pEngineName*/ "OpenJDK",
/*engineVersion*/ 0,
/*apiVersion*/ REQUIRED_VULKAN_VERSION
};
vk::InstanceCreateInfo instanceCreateInfo{
/*flags*/ {},
/*pApplicationInfo*/ &applicationInfo,
/*ppEnabledLayerNames*/ enabledLayers,
/*ppEnabledExtensionNames*/ enabledExtensions,
/*pNext*/ pNext
};
// Save context object at persistent address before passing it further.
_vk_instance = vk::raii::Instance(_vk_context, instanceCreateInfo);
J2dRlsTrace(J2D_TRACE_INFO, "Vulkan: Instance created\n");
// Create debug messenger
#if defined(DEBUG)
if (pNext) {
debugMessenger = vk::raii::DebugUtilsMessengerEXT(_vk_instance, vk::DebugUtilsMessengerCreateInfoEXT {
/*flags*/ {},
/*messageSeverity*/ vk::DebugUtilsMessageSeverityFlagBitsEXT::eError |
vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning |
vk::DebugUtilsMessageSeverityFlagBitsEXT::eInfo |
vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose,
/*messageType*/ vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral |
vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation |
vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance,
/*pfnUserCallback*/ &debugCallback
});
}
#endif
// Find suitable devices.
for (auto &handle: _vk_instance.enumeratePhysicalDevices()) {
PhysicalDevice physicalDevice{std::move(handle)};
if (physicalDevice) { // Supported.
_physical_devices.push_back(std::move(physicalDevice));
}
}
if (_physical_devices.empty()) {
throw std::runtime_error("Vulkan: No suitable device found");
}
// Create virtual device for a physical device.
// TODO system property for manual choice of GPU
// TODO integrated/discrete presets
// TODO performance/power saving mode switch on the fly?
_default_physical_device = 0; // TODO pick first just to check hat virtual device creation works
_devices.push_back(std::move(VKDevice{_physical_devices[_default_physical_device]}));
_default_device = 0;
}
uint32_t VKGraphicsEnvironment::max_texture_size() {
return _physical_devices[_default_physical_device].getMaxImageDimension2D();
}
vk::raii::Instance& VKGraphicsEnvironment::vk_instance() {
return _vk_instance;
}
void VKGraphicsEnvironment::dispose() {
_ge_instance.reset();
}
VKDevice& VKGraphicsEnvironment::default_device() {
return _devices[_default_device];
}
VKDevice::VKDevice(PhysicalDevice& physicalDevice) : vk::raii::Device(nullptr), _command_pool(nullptr) {
float queuePriorities[1] {1.0f}; // We only use one queue for now
std::vector<vk::DeviceQueueCreateInfo> queueCreateInfos;
queueCreateInfos.push_back(vk::DeviceQueueCreateInfo {
{}, (uint32_t) physicalDevice.queueFamily, 1, &queuePriorities[0]
{}, (uint32_t) physicalDevice.queue_family(), 1, &queuePriorities[0]
});
vk::DeviceCreateInfo deviceCreateInfo {
/*flags*/ {},
/*pQueueCreateInfos*/ queueCreateInfos,
/*ppEnabledLayerNames*/ physicalDevice.enabledLayers,
/*ppEnabledExtensionNames*/ physicalDevice.enabledExtensions,
/*ppEnabledLayerNames*/ physicalDevice.enabled_layers(),
/*ppEnabledExtensionNames*/ physicalDevice.enabled_extensions(),
/*pEnabledFeatures*/ nullptr
};
*((vk::raii::Device*) this) = {physicalDevice, deviceCreateInfo};
this->_queue_family = physicalDevice.queue_family();
J2dRlsTrace(J2D_TRACE_INFO, "Vulkan: Device created\n"); // TODO which one?
}
static std::vector<PhysicalDevice> physicalDevices; // Only supported ones.
static bool initDevices() {
try {
// Find suitable devices.
for (auto& handle : vkInstance.enumeratePhysicalDevices()) {
PhysicalDevice physicalDevice {std::move(handle)};
if (physicalDevice) { // Supported.
physicalDevices.push_back(std::move(physicalDevice));
}
}
if (physicalDevices.empty()) {
J2dRlsTrace(J2D_TRACE_ERROR, "Vulkan: No suitable device found\n");
return false;
}
// Create virtual device for a physical device.
// TODO system property for manual choice of GPU
// TODO integrated/discrete presets
// TODO performance/power saving mode switch on the fly?
Device device {physicalDevices[0]}; // TODO pick first just to check that virtual device creation works
return true;
} catch (std::exception& e) {
J2dRlsTrace1(J2D_TRACE_ERROR, "Vulkan: %s\n", e.what());
return false;
}
extern "C" jint VK_MaxTextureSize() {
return (jint)VKGraphicsEnvironment::graphics_environment()->max_texture_size();
}
extern "C" jboolean VK_Init() {
if (createInstance() && initDevices()) {
if (VKGraphicsEnvironment::graphics_environment() != nullptr) {
return true;
}
physicalDevices.clear();
#if defined(DEBUG)
debugMessenger = nullptr;
#endif
vkInstance = nullptr;
delete context;
return false;
}

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 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
@@ -31,22 +32,85 @@
#define VK_NO_PROTOTYPES
#define VULKAN_HPP_NO_DEFAULT_DISPATCHER
#include <vulkan/vulkan_raii.hpp>
extern vk::raii::Instance vkInstance;
#include "jni.h"
class PhysicalDevice;
class Device : public vk::raii::Device {
class VKGraphicsEnvironment;
class VKDevice : public vk::raii::Device {
friend class VKGraphicsEnvironment;
vk::raii::CommandPool _command_pool;
int _queue_family = -1;
VKDevice(PhysicalDevice& physicalDevice);
public:
Device(const PhysicalDevice& physicalDevice);
int queue_family() const {
return _queue_family;
}
};
class VKSurfaceData {
uint32_t _width;
uint32_t _height;
uint32_t _scale;
uint32_t _bg_color;
public:
VKSurfaceData(uint32_t w, uint32_t h, uint32_t s, uint32_t bgc)
: _width(w), _height(h), _scale(s), _bg_color(bgc) {};
uint32_t width() const {
return _width;
}
uint32_t height() const {
return _height;
}
uint32_t scale() const {
return _scale;
}
uint32_t bg_color() const {
return _bg_color;
}
virtual void set_bg_color(uint32_t bg_color) {
_bg_color = bg_color;
}
virtual ~VKSurfaceData() = default;
virtual void revalidate(uint32_t w, uint32_t h, uint32_t s)
{
_width = w;
_height = h;
_scale = s;
}
};
class VKGraphicsEnvironment {
vk::raii::Context _vk_context;
vk::raii::Instance _vk_instance;
std::vector<PhysicalDevice> _physical_devices;
std::vector<VKDevice> _devices;
int _default_physical_device;
int _default_device;
static std::unique_ptr<VKGraphicsEnvironment> _ge_instance;
VKGraphicsEnvironment();
public:
static VKGraphicsEnvironment* graphics_environment();
static void dispose();
VKDevice& default_device();
vk::raii::Instance& vk_instance();
uint32_t max_texture_size();
};
extern "C" {
#endif //__cplusplus
typedef unsigned char jboolean;
jboolean VK_Init();
jint VK_MaxTextureSize();
#ifdef __cplusplus
}

View File

@@ -0,0 +1,619 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
#ifndef HEADLESS
#include <stdlib.h>
#include "sun_java2d_pipe_BufferedOpCodes.h"
#include "sun_java2d_pipe_BufferedRenderPipe.h"
#include "sun_java2d_pipe_BufferedTextPipe.h"
#include "sun_java2d_vulkan_VKBlitLoops.h"
#include "Trace.h"
#include "jlong.h"
#include "VKRenderQueue.h"
#define BYTES_PER_POLY_POINT \
sun_java2d_pipe_BufferedRenderPipe_BYTES_PER_POLY_POINT
#define BYTES_PER_SCANLINE \
sun_java2d_pipe_BufferedRenderPipe_BYTES_PER_SCANLINE
#define BYTES_PER_SPAN \
sun_java2d_pipe_BufferedRenderPipe_BYTES_PER_SPAN
#define BYTES_PER_GLYPH_IMAGE \
sun_java2d_pipe_BufferedTextPipe_BYTES_PER_GLYPH_IMAGE
#define BYTES_PER_GLYPH_POSITION \
sun_java2d_pipe_BufferedTextPipe_BYTES_PER_GLYPH_POSITION
#define BYTES_PER_POSITIONED_GLYPH \
(BYTES_PER_GLYPH_IMAGE + BYTES_PER_GLYPH_POSITION)
#define OFFSET_CONTRAST sun_java2d_pipe_BufferedTextPipe_OFFSET_CONTRAST
#define OFFSET_RGBORDER sun_java2d_pipe_BufferedTextPipe_OFFSET_RGBORDER
#define OFFSET_SUBPIXPOS sun_java2d_pipe_BufferedTextPipe_OFFSET_SUBPIXPOS
#define OFFSET_POSITIONS sun_java2d_pipe_BufferedTextPipe_OFFSET_POSITIONS
#define OFFSET_SRCTYPE sun_java2d_vulkan_VKBlitLoops_OFFSET_SRCTYPE
#define OFFSET_HINT sun_java2d_vulkan_VKBlitLoops_OFFSET_HINT
#define OFFSET_TEXTURE sun_java2d_vulkan_VKBlitLoops_OFFSET_TEXTURE
#define OFFSET_RTT sun_java2d_vulkan_VKBlitLoops_OFFSET_RTT
#define OFFSET_XFORM sun_java2d_vulkan_VKBlitLoops_OFFSET_XFORM
#define OFFSET_ISOBLIT sun_java2d_vulkan_VKBlitLoops_OFFSET_ISOBLIT
extern "C" JNIEXPORT void JNICALL
Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
(JNIEnv *env, jobject oglrq,
jlong buf, jint limit)
{
jboolean sync = JNI_FALSE;
unsigned char *b, *end;
J2dTraceLn1(J2D_TRACE_INFO,
"VKRenderQueue_flushBuffer: limit=%d", limit);
b = (unsigned char *)jlong_to_ptr(buf);
if (b == NULL) {
J2dRlsTraceLn(J2D_TRACE_ERROR,
"VKRenderQueue_flushBuffer: cannot get direct buffer address");
return;
}
if (limit == 0) return;
end = b + limit;
while (b < end) {
jint opcode = NEXT_INT(b);
J2dRlsTraceLn2(J2D_TRACE_VERBOSE,
"VKRenderQueue_flushBuffer: opcode=%d, rem=%d",
opcode, (end-b));
switch (opcode) {
// draw ops
case sun_java2d_pipe_BufferedOpCodes_DRAW_LINE:
{
jint x1 = NEXT_INT(b);
jint y1 = NEXT_INT(b);
jint x2 = NEXT_INT(b);
jint y2 = NEXT_INT(b);
J2dRlsTraceLn4(J2D_TRACE_VERBOSE,
"VKRenderQueue_flushBuffer: DRAW_LINE(%d, %d, %d, %d)",
x1, y1, x2, y2);
}
break;
case sun_java2d_pipe_BufferedOpCodes_DRAW_RECT:
{
jint x = NEXT_INT(b);
jint y = NEXT_INT(b);
jint w = NEXT_INT(b);
jint h = NEXT_INT(b);
J2dRlsTraceLn4(J2D_TRACE_VERBOSE,
"VKRenderQueue_flushBuffer: DRAW_RECT(%d, %d, %d, %d)",
x, y, w, h);
}
break;
case sun_java2d_pipe_BufferedOpCodes_DRAW_POLY:
{
jint nPoints = NEXT_INT(b);
jboolean isClosed = NEXT_BOOLEAN(b);
jint transX = NEXT_INT(b);
jint transY = NEXT_INT(b);
jint *xPoints = (jint *)b;
jint *yPoints = ((jint *)b) + nPoints;
J2dRlsTraceLn(J2D_TRACE_VERBOSE, "VKRenderQueue_flushBuffer: DRAW_POLY");
SKIP_BYTES(b, nPoints * BYTES_PER_POLY_POINT);
}
break;
case sun_java2d_pipe_BufferedOpCodes_DRAW_PIXEL:
{
jint x = NEXT_INT(b);
jint y = NEXT_INT(b);
J2dRlsTraceLn(J2D_TRACE_VERBOSE, "VKRenderQueue_flushBuffer: DRAW_PIXEL");
}
break;
case sun_java2d_pipe_BufferedOpCodes_DRAW_SCANLINES:
{
jint count = NEXT_INT(b);
J2dRlsTraceLn(J2D_TRACE_VERBOSE, "VKRenderQueue_flushBuffer: DRAW_SCANLINES");
SKIP_BYTES(b, count * BYTES_PER_SCANLINE);
}
break;
case sun_java2d_pipe_BufferedOpCodes_DRAW_PARALLELOGRAM:
{
jfloat x11 = NEXT_FLOAT(b);
jfloat y11 = NEXT_FLOAT(b);
jfloat dx21 = NEXT_FLOAT(b);
jfloat dy21 = NEXT_FLOAT(b);
jfloat dx12 = NEXT_FLOAT(b);
jfloat dy12 = NEXT_FLOAT(b);
jfloat lwr21 = NEXT_FLOAT(b);
jfloat lwr12 = NEXT_FLOAT(b);
J2dRlsTraceLn8(J2D_TRACE_VERBOSE,
"VKRenderQueue_flushBuffer: DRAW_PARALLELOGRAM(%f, %f, %f, %f, %f, %f, %f, %f)",
x11, y11, dx21, dy21, dx12, dy12, lwr21, lwr12);
}
break;
case sun_java2d_pipe_BufferedOpCodes_DRAW_AAPARALLELOGRAM:
{
jfloat x11 = NEXT_FLOAT(b);
jfloat y11 = NEXT_FLOAT(b);
jfloat dx21 = NEXT_FLOAT(b);
jfloat dy21 = NEXT_FLOAT(b);
jfloat dx12 = NEXT_FLOAT(b);
jfloat dy12 = NEXT_FLOAT(b);
jfloat lwr21 = NEXT_FLOAT(b);
jfloat lwr12 = NEXT_FLOAT(b);
J2dRlsTraceLn8(J2D_TRACE_VERBOSE,
"VKRenderQueue_flushBuffer: DRAW_AAPARALLELOGRAM(%f, %f, %f, %f, %f, %f, %f, %f)",
x11, y11, dx21, dy21, dx12, dy12, lwr21, lwr12);
}
break;
// fill ops
case sun_java2d_pipe_BufferedOpCodes_FILL_RECT:
{
jint x = NEXT_INT(b);
jint y = NEXT_INT(b);
jint w = NEXT_INT(b);
jint h = NEXT_INT(b);
J2dRlsTraceLn4(J2D_TRACE_VERBOSE,
"VKRenderQueue_flushBuffer: FILL_RECT(%d, %d, %d, %d)", x, y, w, h);
}
break;
case sun_java2d_pipe_BufferedOpCodes_FILL_SPANS:
{
jint count = NEXT_INT(b);
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
"VKRenderQueue_flushBuffer: FILL_SPANS");
SKIP_BYTES(b, count * BYTES_PER_SPAN);
}
break;
case sun_java2d_pipe_BufferedOpCodes_FILL_PARALLELOGRAM:
{
jfloat x11 = NEXT_FLOAT(b);
jfloat y11 = NEXT_FLOAT(b);
jfloat dx21 = NEXT_FLOAT(b);
jfloat dy21 = NEXT_FLOAT(b);
jfloat dx12 = NEXT_FLOAT(b);
jfloat dy12 = NEXT_FLOAT(b);
J2dRlsTraceLn6(J2D_TRACE_VERBOSE,
"VKRenderQueue_flushBuffer: FILL_PARALLELOGRAM(%f, %f, %f, %f, %f, %f)",
x11, y11, dx21, dy21, dx12, dy12);
}
break;
case sun_java2d_pipe_BufferedOpCodes_FILL_AAPARALLELOGRAM:
{
jfloat x11 = NEXT_FLOAT(b);
jfloat y11 = NEXT_FLOAT(b);
jfloat dx21 = NEXT_FLOAT(b);
jfloat dy21 = NEXT_FLOAT(b);
jfloat dx12 = NEXT_FLOAT(b);
jfloat dy12 = NEXT_FLOAT(b);
J2dRlsTraceLn6(J2D_TRACE_VERBOSE,
"VKRenderQueue_flushBuffer: FILL_AAPARALLELOGRAM(%f, %f, %f, %f, %f, %f)",
x11, y11, dx21, dy21, dx12, dy12);
}
break;
// text-related ops
case sun_java2d_pipe_BufferedOpCodes_DRAW_GLYPH_LIST:
{
jint numGlyphs = NEXT_INT(b);
jint packedParams = NEXT_INT(b);
jfloat glyphListOrigX = NEXT_FLOAT(b);
jfloat glyphListOrigY = NEXT_FLOAT(b);
jboolean usePositions = EXTRACT_BOOLEAN(packedParams,
OFFSET_POSITIONS);
jboolean subPixPos = EXTRACT_BOOLEAN(packedParams,
OFFSET_SUBPIXPOS);
jboolean rgbOrder = EXTRACT_BOOLEAN(packedParams,
OFFSET_RGBORDER);
jint lcdContrast = EXTRACT_BYTE(packedParams,
OFFSET_CONTRAST);
unsigned char *images = b;
unsigned char *positions;
jint bytesPerGlyph;
if (usePositions) {
positions = (b + numGlyphs * BYTES_PER_GLYPH_IMAGE);
bytesPerGlyph = BYTES_PER_POSITIONED_GLYPH;
} else {
positions = NULL;
bytesPerGlyph = BYTES_PER_GLYPH_IMAGE;
}
J2dRlsTraceLn(J2D_TRACE_VERBOSE, "VKRenderQueue_flushBuffer: DRAW_GLYPH_LIST");
SKIP_BYTES(b, numGlyphs * bytesPerGlyph);
}
break;
// copy-related ops
case sun_java2d_pipe_BufferedOpCodes_COPY_AREA:
{
jint x = NEXT_INT(b);
jint y = NEXT_INT(b);
jint w = NEXT_INT(b);
jint h = NEXT_INT(b);
jint dx = NEXT_INT(b);
jint dy = NEXT_INT(b);
J2dRlsTraceLn6(J2D_TRACE_VERBOSE,
"VKRenderQueue_flushBuffer: COPY_AREA(%d, %d, %d, %d, %d, %d)",
x, y, w, h, dx, dy);
}
break;
case sun_java2d_pipe_BufferedOpCodes_BLIT:
{
jint packedParams = NEXT_INT(b);
jint sx1 = NEXT_INT(b);
jint sy1 = NEXT_INT(b);
jint sx2 = NEXT_INT(b);
jint sy2 = NEXT_INT(b);
jdouble dx1 = NEXT_DOUBLE(b);
jdouble dy1 = NEXT_DOUBLE(b);
jdouble dx2 = NEXT_DOUBLE(b);
jdouble dy2 = NEXT_DOUBLE(b);
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,
OFFSET_ISOBLIT);
J2dRlsTraceLn(J2D_TRACE_VERBOSE, "VKRenderQueue_flushBuffer: BLIT");
}
break;
case sun_java2d_pipe_BufferedOpCodes_SURFACE_TO_SW_BLIT:
{
jint sx = NEXT_INT(b);
jint sy = NEXT_INT(b);
jint dx = NEXT_INT(b);
jint dy = NEXT_INT(b);
jint w = NEXT_INT(b);
jint h = NEXT_INT(b);
jint dsttype = NEXT_INT(b);
jlong pSrc = NEXT_LONG(b);
jlong pDst = NEXT_LONG(b);
J2dRlsTraceLn(J2D_TRACE_VERBOSE, "VKRenderQueue_flushBuffer: SURFACE_TO_SW_BLIT");
}
break;
case sun_java2d_pipe_BufferedOpCodes_MASK_FILL:
{
jint x = NEXT_INT(b);
jint y = NEXT_INT(b);
jint w = NEXT_INT(b);
jint h = NEXT_INT(b);
jint maskoff = NEXT_INT(b);
jint maskscan = NEXT_INT(b);
jint masklen = NEXT_INT(b);
unsigned char *pMask = (masklen > 0) ? b : NULL;
J2dRlsTraceLn(J2D_TRACE_VERBOSE, "VKRenderQueue_flushBuffer: MASK_FILL");
SKIP_BYTES(b, masklen);
}
break;
case sun_java2d_pipe_BufferedOpCodes_MASK_BLIT:
{
jint dstx = NEXT_INT(b);
jint dsty = NEXT_INT(b);
jint width = NEXT_INT(b);
jint height = NEXT_INT(b);
jint masklen = width * height * sizeof(jint);
J2dRlsTraceLn(J2D_TRACE_VERBOSE, "VKRenderQueue_flushBuffer: MASK_BLIT");
SKIP_BYTES(b, masklen);
}
break;
// state-related ops
case sun_java2d_pipe_BufferedOpCodes_SET_RECT_CLIP:
{
jint x1 = NEXT_INT(b);
jint y1 = NEXT_INT(b);
jint x2 = NEXT_INT(b);
jint y2 = NEXT_INT(b);
J2dRlsTraceLn4(J2D_TRACE_VERBOSE,
"VKRenderQueue_flushBuffer: SET_RECT_CLIP(%d, %d, %d, %d)",
x1, y1, x2, y2);
}
break;
case sun_java2d_pipe_BufferedOpCodes_BEGIN_SHAPE_CLIP:
{
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
"VKRenderQueue_flushBuffer: BEGIN_SHAPE_CLIP");
}
break;
case sun_java2d_pipe_BufferedOpCodes_SET_SHAPE_CLIP_SPANS:
{
jint count = NEXT_INT(b);
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
"VKRenderQueue_flushBuffer: SET_SHAPE_CLIP_SPANS");
SKIP_BYTES(b, count * BYTES_PER_SPAN);
}
break;
case sun_java2d_pipe_BufferedOpCodes_END_SHAPE_CLIP:
{
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
"VKRenderQueue_flushBuffer: END_SHAPE_CLIP");
}
break;
case sun_java2d_pipe_BufferedOpCodes_RESET_CLIP:
{
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
"VKRenderQueue_flushBuffer: RESET_CLIP");
}
break;
case sun_java2d_pipe_BufferedOpCodes_SET_ALPHA_COMPOSITE:
{
jint rule = NEXT_INT(b);
jfloat extraAlpha = NEXT_FLOAT(b);
jint flags = NEXT_INT(b);
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
"VKRenderQueue_flushBuffer: SET_ALPHA_COMPOSITE");
}
break;
case sun_java2d_pipe_BufferedOpCodes_SET_XOR_COMPOSITE:
{
jint xorPixel = NEXT_INT(b);
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
"VKRenderQueue_flushBuffer: SET_XOR_COMPOSITE");
}
break;
case sun_java2d_pipe_BufferedOpCodes_RESET_COMPOSITE:
{
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
"VKRenderQueue_flushBuffer: RESET_COMPOSITE");
}
break;
case sun_java2d_pipe_BufferedOpCodes_SET_TRANSFORM:
{
jdouble m00 = NEXT_DOUBLE(b);
jdouble m10 = NEXT_DOUBLE(b);
jdouble m01 = NEXT_DOUBLE(b);
jdouble m11 = NEXT_DOUBLE(b);
jdouble m02 = NEXT_DOUBLE(b);
jdouble m12 = NEXT_DOUBLE(b);
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
"VKRenderQueue_flushBuffer: SET_TRANSFORM");
}
break;
case sun_java2d_pipe_BufferedOpCodes_RESET_TRANSFORM:
{
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
"VKRenderQueue_flushBuffer: RESET_TRANSFORM");
}
break;
// context-related ops
case sun_java2d_pipe_BufferedOpCodes_SET_SURFACES:
{
jlong pSrc = NEXT_LONG(b);
jlong pDst = NEXT_LONG(b);
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
"VKRenderQueue_flushBuffer: SET_SURFACES");
}
break;
case sun_java2d_pipe_BufferedOpCodes_SET_SCRATCH_SURFACE:
{
jlong pConfigInfo = NEXT_LONG(b);
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
"VKRenderQueue_flushBuffer: SET_SCRATCH_SURFACE");
}
break;
case sun_java2d_pipe_BufferedOpCodes_FLUSH_SURFACE:
{
jlong pData = NEXT_LONG(b);
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
"VKRenderQueue_flushBuffer: FLUSH_SURFACE");
}
break;
case sun_java2d_pipe_BufferedOpCodes_DISPOSE_SURFACE:
{
jlong pData = NEXT_LONG(b);
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
"VKRenderQueue_flushBuffer: FLUSH_SURFACE");
}
break;
case sun_java2d_pipe_BufferedOpCodes_DISPOSE_CONFIG:
{
jlong pConfigInfo = NEXT_LONG(b);
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
"VKRenderQueue_flushBuffer: DISPOSE_CONFIG");
}
break;
case sun_java2d_pipe_BufferedOpCodes_INVALIDATE_CONTEXT:
{
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
"VKRenderQueue_flushBuffer: INVALIDATE_CONTEXT");
}
break;
case sun_java2d_pipe_BufferedOpCodes_SYNC:
{
sync = JNI_TRUE;
}
break;
// multibuffering ops
case sun_java2d_pipe_BufferedOpCodes_SWAP_BUFFERS:
{
jlong window = NEXT_LONG(b);
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
"VKRenderQueue_flushBuffer: SWAP_BUFFERS");
}
break;
// special no-op (mainly used for achieving 8-byte alignment)
case sun_java2d_pipe_BufferedOpCodes_NOOP:
break;
// paint-related ops
case sun_java2d_pipe_BufferedOpCodes_RESET_PAINT:
{
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
"VKRenderQueue_flushBuffer: RESET_PAINT");
}
break;
case sun_java2d_pipe_BufferedOpCodes_SET_COLOR:
{
jint pixel = NEXT_INT(b);
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
"VKRenderQueue_flushBuffer: SET_COLOR");
}
break;
case sun_java2d_pipe_BufferedOpCodes_SET_GRADIENT_PAINT:
{
jboolean useMask= NEXT_BOOLEAN(b);
jboolean cyclic = NEXT_BOOLEAN(b);
jdouble p0 = NEXT_DOUBLE(b);
jdouble p1 = NEXT_DOUBLE(b);
jdouble p3 = NEXT_DOUBLE(b);
jint pixel1 = NEXT_INT(b);
jint pixel2 = NEXT_INT(b);
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
"VKRenderQueue_flushBuffer: SET_GRADIENT_PAINT");
}
break;
case sun_java2d_pipe_BufferedOpCodes_SET_LINEAR_GRADIENT_PAINT:
{
jboolean useMask = NEXT_BOOLEAN(b);
jboolean linear = NEXT_BOOLEAN(b);
jint cycleMethod = NEXT_INT(b);
jint numStops = NEXT_INT(b);
jfloat p0 = NEXT_FLOAT(b);
jfloat p1 = NEXT_FLOAT(b);
jfloat p3 = NEXT_FLOAT(b);
void *fractions, *pixels;
fractions = b; SKIP_BYTES(b, numStops * sizeof(jfloat));
pixels = b; SKIP_BYTES(b, numStops * sizeof(jint));
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
"VKRenderQueue_flushBuffer: SET_LINEAR_GRADIENT_PAINT");
}
break;
case sun_java2d_pipe_BufferedOpCodes_SET_RADIAL_GRADIENT_PAINT:
{
jboolean useMask = NEXT_BOOLEAN(b);
jboolean linear = NEXT_BOOLEAN(b);
jint numStops = NEXT_INT(b);
jint cycleMethod = NEXT_INT(b);
jfloat m00 = NEXT_FLOAT(b);
jfloat m01 = NEXT_FLOAT(b);
jfloat m02 = NEXT_FLOAT(b);
jfloat m10 = NEXT_FLOAT(b);
jfloat m11 = NEXT_FLOAT(b);
jfloat m12 = NEXT_FLOAT(b);
jfloat focusX = NEXT_FLOAT(b);
void *fractions, *pixels;
fractions = b; SKIP_BYTES(b, numStops * sizeof(jfloat));
pixels = b; SKIP_BYTES(b, numStops * sizeof(jint));
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
"VKRenderQueue_flushBuffer: SET_RADIAL_GRADIENT_PAINT");
}
break;
case sun_java2d_pipe_BufferedOpCodes_SET_TEXTURE_PAINT:
{
jboolean useMask= NEXT_BOOLEAN(b);
jboolean filter = NEXT_BOOLEAN(b);
jlong pSrc = NEXT_LONG(b);
jdouble xp0 = NEXT_DOUBLE(b);
jdouble xp1 = NEXT_DOUBLE(b);
jdouble xp3 = NEXT_DOUBLE(b);
jdouble yp0 = NEXT_DOUBLE(b);
jdouble yp1 = NEXT_DOUBLE(b);
jdouble yp3 = NEXT_DOUBLE(b);
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
"VKRenderQueue_flushBuffer: SET_TEXTURE_PAINT");
}
break;
// BufferedImageOp-related ops
case sun_java2d_pipe_BufferedOpCodes_ENABLE_CONVOLVE_OP:
{
jlong pSrc = NEXT_LONG(b);
jboolean edgeZero = NEXT_BOOLEAN(b);
jint kernelWidth = NEXT_INT(b);
jint kernelHeight = NEXT_INT(b);
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
"VKRenderQueue_flushBuffer: ENABLE_CONVOLVE_OP");
SKIP_BYTES(b, kernelWidth * kernelHeight * sizeof(jfloat));
}
break;
case sun_java2d_pipe_BufferedOpCodes_DISABLE_CONVOLVE_OP:
{
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
"VKRenderQueue_flushBuffer: DISABLE_CONVOLVE_OP");
}
break;
case sun_java2d_pipe_BufferedOpCodes_ENABLE_RESCALE_OP:
{
jlong pSrc = NEXT_LONG(b);
jboolean nonPremult = NEXT_BOOLEAN(b);
jint numFactors = 4;
unsigned char *scaleFactors = b;
unsigned char *offsets = (b + numFactors * sizeof(jfloat));
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
"VKRenderQueue_flushBuffer: ENABLE_RESCALE_OP");
SKIP_BYTES(b, numFactors * sizeof(jfloat) * 2);
}
break;
case sun_java2d_pipe_BufferedOpCodes_DISABLE_RESCALE_OP:
{
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
"VKRenderQueue_flushBuffer: DISABLE_RESCALE_OP");
}
break;
case sun_java2d_pipe_BufferedOpCodes_ENABLE_LOOKUP_OP:
{
jlong pSrc = NEXT_LONG(b);
jboolean nonPremult = NEXT_BOOLEAN(b);
jboolean shortData = NEXT_BOOLEAN(b);
jint numBands = NEXT_INT(b);
jint bandLength = NEXT_INT(b);
jint offset = NEXT_INT(b);
jint bytesPerElem = shortData ? sizeof(jshort) : sizeof(jbyte);
void *tableValues = b;
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
"VKRenderQueue_flushBuffer: ENABLE_LOOKUP_OP");
SKIP_BYTES(b, numBands * bandLength * bytesPerElem);
}
break;
case sun_java2d_pipe_BufferedOpCodes_DISABLE_LOOKUP_OP:
{
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
"VKRenderQueue_flushBuffer: DISABLE_LOOKUP_OP");
}
break;
default:
J2dRlsTraceLn1(J2D_TRACE_ERROR,
"VKRenderQueue_flushBuffer: invalid opcode=%d", opcode);
return;
}
}
}
#endif /* !HEADLESS */

View File

@@ -0,0 +1,71 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
#ifndef VKRenderQueue_h_Included
#define VKRenderQueue_h_Included
/*
* The following macros are used to pick values (of the specified type) off
* the queue.
*/
#define NEXT_VAL(buf, type) (((type *)((buf) += sizeof(type)))[-1])
#define NEXT_BYTE(buf) NEXT_VAL(buf, unsigned char)
#define NEXT_INT(buf) NEXT_VAL(buf, jint)
#define NEXT_FLOAT(buf) NEXT_VAL(buf, jfloat)
#define NEXT_BOOLEAN(buf) (jboolean)NEXT_INT(buf)
#define NEXT_LONG(buf) NEXT_VAL(buf, jlong)
#define NEXT_DOUBLE(buf) NEXT_VAL(buf, jdouble)
/*
* Increments a pointer (buf) by the given number of bytes.
*/
#define SKIP_BYTES(buf, numbytes) (buf) += (numbytes)
/*
* Extracts a value at the given offset from the provided packed value.
*/
#define EXTRACT_VAL(packedval, offset, mask) \
(((packedval) >> (offset)) & (mask))
#define EXTRACT_BYTE(packedval, offset) \
(unsigned char)EXTRACT_VAL(packedval, offset, 0xff)
#define EXTRACT_BOOLEAN(packedval, offset) \
(jboolean)EXTRACT_VAL(packedval, offset, 0x1)
/*
* The following macros allow the caller to return (or continue) if the
* provided value is NULL. (The strange else clause is included below to
* allow for a trailing ';' after RETURN/CONTINUE_IF_NULL() invocations.)
*/
#define ACT_IF_NULL(ACTION, value) \
if ((value) == NULL) { \
J2dTraceLn1(J2D_TRACE_ERROR, \
"%s is null", #value); \
ACTION; \
} else do { } while (0)
#define RETURN_IF_NULL(value) ACT_IF_NULL(return, value)
#define CONTINUE_IF_NULL(value) ACT_IF_NULL(continue, value)
#endif /* VKRenderQueue_h_Included */

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 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
@@ -25,11 +26,14 @@
// These are stubs in case we were built with Vulkan disabled.
#ifndef VULKAN_ENABLED
typedef unsigned char jboolean;
#include "jni.h"
jboolean VK_Init() {
return 0;
}
jint VK_MaxTextureSize() {
return 0;
}
#endif

View File

@@ -0,0 +1,95 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
#ifndef VKSurfaceData_h_Included
#define VKSurfaceData_h_Included
#include "java_awt_image_AffineTransformOp.h"
#include "sun_java2d_pipe_hw_AccelSurface.h"
#include "SurfaceData.h"
#include "Trace.h"
/**
* The VKSDOps structure describes a native Vulkan surface and contains all
* information pertaining to the native surface. Some information about
* the more important/different fields:
*
* void *privOps;
* Pointer to native-specific SurfaceData info, such as the
* native Drawable handle and GraphicsConfig data.
*
* jobject graphicsConfig;
* Strong reference to the VKGraphicsConfig used by this VKSurfaceData.
*
* jint drawableType;
* The surface type; can be any one of the surface type constants defined
* below (VK_WINDOW, VK_TEXTURE, etc).
*
* jboolean isOpaque;
* If true, the surface should be treated as being fully opaque.
*
* jboolean needsInit;
* If true, the surface requires some one-time initialization, which should
* be performed after a context has been made current to the surface for
* the first time.
*
* jint x/yOffset
* The offset in pixels of the Vulkan viewport origin from the lower-left
* corner of the heavyweight drawable.
*
* jint width/height;
* The cached surface bounds. For offscreen surface types (VK_RT_TEXTURE,
* VK_TEXTURE, etc.) these values must remain constant. Onscreen window
* surfaces (VK_WINDOW, etc.) may have their
* bounds changed in response to a programmatic or user-initiated event, so
* these values represent the last known dimensions. To determine the true
* current bounds of this surface, query the native Drawable through the
* privOps field.
*
*/
typedef struct _VKSDOps {
SurfaceDataOps sdOps;
void *privOps;
jobject graphicsConfig;
jint drawableType;
jboolean isOpaque;
jboolean needsInit;
jint xOffset;
jint yOffset;
jint width;
jint height;
} VKSDOps;
/**
* These are shorthand names for the surface type constants defined in
* VKSurfaceData.java.
*/
#define VKSD_UNDEFINED sun_java2d_pipe_hw_AccelSurface_UNDEFINED
#define VKSD_WINDOW sun_java2d_pipe_hw_AccelSurface_WINDOW
#define VKSD_TEXTURE sun_java2d_pipe_hw_AccelSurface_TEXTURE
#define VKSD_RT_TEXTURE sun_java2d_pipe_hw_AccelSurface_RT_TEXTURE
#endif /* VKSurfaceData_h_Included */

View File

@@ -34,7 +34,7 @@ import sun.awt.image.SunVolatileImage;
import sun.java2d.SunGraphics2D;
import sun.java2d.SurfaceData;
import sun.java2d.pipe.Region;
import sun.java2d.wl.WLSurfaceData;
import sun.java2d.wl.WLSurfaceDataExt;
import sun.util.logging.PlatformLogger;
import sun.util.logging.PlatformLogger.Level;
@@ -89,7 +89,7 @@ public class WLComponentPeer implements ComponentPeer {
protected final java.util.List<WLGraphicsDevice> devices = new ArrayList<>();
protected Color background;
WLSurfaceData surfaceData;
SurfaceData surfaceData;
WLRepaintArea paintArea;
boolean paintPending = false;
boolean isLayouting = false;
@@ -120,7 +120,7 @@ public class WLComponentPeer implements ComponentPeer {
height = bounds.height;
final WLGraphicsConfig config = (WLGraphicsConfig)target.getGraphicsConfiguration();
wlBufferScale = config.getScale();
surfaceData = (WLSurfaceData) config.createSurfaceData(this);
surfaceData = config.createSurfaceData(this);
nativePtr = nativeCreateFrame();
paintArea = new WLRepaintArea();
log.fine("WLComponentPeer: target=" + target + " x=" + x + " y=" + y +
@@ -265,7 +265,7 @@ public class WLComponentPeer implements ComponentPeer {
} else {
performLocked(() -> {
WLToolkit.unregisterWLSurface(getWLSurface(nativePtr));
surfaceData.assignSurface(0);
SurfaceData.convertTo(WLSurfaceDataExt.class, surfaceData).assignSurface(0);
nativeHideFrame(nativePtr);
});
}
@@ -276,7 +276,8 @@ public class WLComponentPeer implements ComponentPeer {
if (log.isLoggable(PlatformLogger.Level.FINE)) {
log.fine(String.format("%s is configured to %dx%d with %dx scale", this, getBufferWidth(), getBufferHeight(), getBufferScale()));
}
surfaceData.revalidate(getBufferWidth(), getBufferHeight(), getBufferScale());
SurfaceData.convertTo(WLSurfaceDataExt.class, surfaceData).revalidate(
getBufferWidth(), getBufferHeight(), getBufferScale());
}
}
@@ -337,7 +338,7 @@ public class WLComponentPeer implements ComponentPeer {
public void commitToServer() {
performLocked(() -> {
if (getWLSurface(nativePtr) != 0) {
surfaceData.commitToServer();
surfaceData.flush();
}
});
}
@@ -370,7 +371,8 @@ public class WLComponentPeer implements ComponentPeer {
if (log.isLoggable(PlatformLogger.Level.FINE)) {
log.fine(String.format("%s is resizing its buffer to %dx%d with %dx scale", this, getBufferWidth(), getBufferHeight(), getBufferScale()));
}
surfaceData.revalidate(getBufferWidth(), getBufferHeight(), getBufferScale());
SurfaceData.convertTo(WLSurfaceDataExt.class, surfaceData).revalidate(
getBufferWidth(), getBufferHeight(), getBufferScale());
updateWindowGeometry();
layout();
@@ -765,7 +767,9 @@ public class WLComponentPeer implements ComponentPeer {
if (log.isLoggable(PlatformLogger.Level.FINE)) {
log.fine(String.format("%s is updating buffer to %dx%d with %dx scale", this, getBufferWidth(), getBufferHeight(), wlBufferScale));
}
surfaceData.revalidate(getBufferWidth(), getBufferHeight(), wlBufferScale);
SurfaceData.convertTo(WLSurfaceDataExt.class, surfaceData).revalidate(
getBufferWidth(), getBufferHeight(), wlBufferScale);
postPaintEvent();
}
}
@@ -982,7 +986,7 @@ public class WLComponentPeer implements ComponentPeer {
void notifyConfigured(int newWidth, int newHeight, boolean active, boolean maximized) {
final long wlSurfacePtr = getWLSurface(nativePtr);
// TODO: this needs to be done only once after wlSetVisible(true)
surfaceData.assignSurface(wlSurfacePtr);
SurfaceData.convertTo(WLSurfaceDataExt.class, surfaceData).assignSurface(wlSurfacePtr);
if (log.isLoggable(PlatformLogger.Level.FINE)) {
log.fine(String.format("%s configured to %dx%d", this, newWidth, newHeight));
}

View File

@@ -1,8 +1,37 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package sun.awt.wl;
import sun.awt.AWTAccessor;
import sun.awt.DisplayChangedListener;
import sun.java2d.vulkan.WLVKGraphicsConfig;
import java.awt.*;
import java.util.ArrayList;
/**
* Corresponds to Wayland's output and is identified by its wlID and x, y coordinates
@@ -30,6 +59,7 @@ public class WLGraphicsDevice extends GraphicsDevice {
*/
private volatile int y; // only changes when the device gets invalidated
private final java.util.List<WLComponentPeer> peers = new ArrayList<>();
private volatile WLGraphicsConfig config = null;
private WLGraphicsDevice(int id, int x, int y) {
@@ -47,7 +77,9 @@ public class WLGraphicsDevice extends GraphicsDevice {
if (config == null || config.differsFrom(width, height, scale)) {
// It is necessary to create a new object whenever config changes as its
// identity is used to detect changes in scale, among other things.
config = new WLGraphicsConfig(this, width, height, scale);
config = WLGraphicsEnvironment.isVulkanEnabled() ?
WLVKGraphicsConfig.getConfig(this, width, height, scale) :
new WLGraphicsConfig(this, width, height, scale);
}
}

View File

@@ -1,7 +1,35 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package sun.awt.wl;
import java.awt.EventQueue;
import java.awt.GraphicsDevice;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@@ -16,13 +44,26 @@ import sun.util.logging.PlatformLogger.Level;
public class WLGraphicsEnvironment extends SunGraphicsEnvironment {
private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.wl.WLGraphicsEnvironment");
private static boolean vkwlAvailable;
private static boolean vulkanEnabled = false;
@SuppressWarnings("removal")
private static boolean vulkanRequested =
AccessController.doPrivileged(
(PrivilegedAction<Boolean>) () ->
"true".equals(System.getProperty("sun.java2d.vulkan")));
@SuppressWarnings("restricted")
private static void loadAwt() {
System.loadLibrary("awt");
}
static {
loadAwt();
SurfaceManagerFactory.setInstance(new UnixSurfaceManagerFactory());
vkwlAvailable = initVKWL();
if (vulkanRequested) {
vulkanEnabled = initVKWL();
}
if (log.isLoggable(Level.FINE)) {
log.fine("Vulkan rendering available: " + (vkwlAvailable?"YES":"NO"));
log.fine("Vulkan rendering enabled: " + (vulkanEnabled?"YES":"NO"));
}
}
@@ -31,6 +72,10 @@ public class WLGraphicsEnvironment extends SunGraphicsEnvironment {
private WLGraphicsEnvironment() {
}
public static boolean isVulkanEnabled() {
return vulkanEnabled;
}
private static class Holder {
static final WLGraphicsEnvironment INSTANCE = new WLGraphicsEnvironment();
}
@@ -39,9 +84,6 @@ public class WLGraphicsEnvironment extends SunGraphicsEnvironment {
return Holder.INSTANCE;
}
public static boolean isVKWLAvailable() {
return vkwlAvailable;
}
@Override
protected int getNumScreens() {

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2023, 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
@@ -33,6 +33,8 @@ import sun.awt.image.SunVolatileImage;
import sun.awt.image.VolatileSurfaceManager;
import sun.java2d.opengl.GLXGraphicsConfig;
import sun.java2d.opengl.GLXVolatileSurfaceManager;
import sun.java2d.vulkan.WLVKGraphicsConfig;
import sun.java2d.vulkan.WLVKVolatileSurfaceManager;
import sun.java2d.wl.WLVolatileSurfaceManager;
import sun.java2d.x11.X11VolatileSurfaceManager;
import sun.java2d.xr.*;
@@ -64,6 +66,8 @@ public class UnixSurfaceManagerFactory extends SurfaceManagerFactory {
return new XRVolatileSurfaceManager(vImg, context);
} else if (gc instanceof X11GraphicsConfig){
return new X11VolatileSurfaceManager(vImg, context);
} else if (gc instanceof WLVKGraphicsConfig) {
return new WLVKVolatileSurfaceManager(vImg, context);
} else {
return new WLVolatileSurfaceManager(vImg, context);
}

View File

@@ -0,0 +1,226 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package sun.java2d.vulkan;
import static sun.java2d.pipe.hw.AccelSurface.RT_TEXTURE;
import static sun.java2d.pipe.hw.AccelSurface.TEXTURE;
import static sun.java2d.pipe.hw.ContextCapabilities.CAPS_MULTITEXTURE;
import static sun.java2d.pipe.hw.ContextCapabilities.CAPS_PS20;
import static sun.java2d.pipe.hw.ContextCapabilities.CAPS_PS30;
import static sun.java2d.pipe.hw.ContextCapabilities.CAPS_RT_TEXTURE_ALPHA;
import static sun.java2d.pipe.hw.ContextCapabilities.CAPS_RT_TEXTURE_OPAQUE;
import static sun.java2d.pipe.hw.ContextCapabilities.CAPS_TEXNONPOW2;
import static sun.java2d.pipe.hw.ContextCapabilities.CAPS_TEXNONSQUARE;
import java.awt.BufferCapabilities;
import java.awt.ImageCapabilities;
import java.awt.Transparency;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DirectColorModel;
import java.awt.image.VolatileImage;
import java.awt.image.WritableRaster;
import sun.awt.image.SunVolatileImage;
import sun.awt.wl.WLComponentPeer;
import sun.awt.wl.WLGraphicsConfig;
import sun.awt.wl.WLGraphicsDevice;
import sun.java2d.Surface;
import sun.java2d.SurfaceData;
import sun.java2d.pipe.hw.AccelGraphicsConfig;
import sun.java2d.pipe.hw.AccelSurface;
import sun.java2d.pipe.hw.AccelTypedVolatileImage;
import sun.java2d.pipe.hw.ContextCapabilities;
import sun.util.logging.PlatformLogger;
public final class WLVKGraphicsConfig extends WLGraphicsConfig
implements VKGraphicsConfig
{
private static final PlatformLogger log =
PlatformLogger.getLogger("sun.java2d.vulkan.WLVKGraphicsConfig");
private static ImageCapabilities imageCaps = new VKImageCaps();
private final int maxTextureSize;
private BufferCapabilities bufferCaps;
private ContextCapabilities vkCaps;
private final VKContext context;
private static native long getVKConfigInfo();
/**
* Returns maximum texture size supported by Vulkan. Must be
* called under VKRQ lock.
*/
private static native int nativeGetMaxTextureSize();
public WLVKGraphicsConfig(WLGraphicsDevice device, int width, int height, int scale, int maxTextureSize,
ContextCapabilities vkCaps) {
super(device, width, height, scale);
this.vkCaps = vkCaps;
this.maxTextureSize = maxTextureSize;
context = new VKContext(VKRenderQueue.getInstance());
}
@Override
public Object getProxyKey() {
return this;
}
public static WLVKGraphicsConfig getConfig(WLGraphicsDevice device, int width, int height, int scale)
{
ContextCapabilities caps = new VKContext.VKContextCaps(
CAPS_PS30 | CAPS_PS20 | CAPS_RT_TEXTURE_ALPHA |
CAPS_RT_TEXTURE_OPAQUE | CAPS_MULTITEXTURE | CAPS_TEXNONPOW2 |
CAPS_TEXNONSQUARE, null);
return new WLVKGraphicsConfig(device, width, height, scale, nativeGetMaxTextureSize(), caps);
}
/**
* Returns true if the provided capability bit is present for this config.
* See VKContext.java for a list of supported capabilities.
*/
@Override
public boolean isCapPresent(int cap) {
return ((vkCaps.getCaps() & cap) != 0);
}
/**
* {@inheritDoc}
*
* @see sun.java2d.pipe.hw.BufferedContextProvider#getContext
*/
@Override
public VKContext getContext() {
return context;
}
@Override
public BufferedImage createCompatibleImage(int width, int height) {
ColorModel model = new DirectColorModel(24, 0xff0000, 0xff00, 0xff);
WritableRaster
raster = model.createCompatibleWritableRaster(width, height);
return new BufferedImage(model, raster, model.isAlphaPremultiplied(),
null);
}
@Override
public ColorModel getColorModel(int transparency) {
switch (transparency) {
case Transparency.OPAQUE:
return new DirectColorModel(24, 0xff0000, 0xff00, 0xff);
case Transparency.BITMASK:
return new DirectColorModel(25, 0xff0000, 0xff00, 0xff, 0x1000000);
case Transparency.TRANSLUCENT:
ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
return new DirectColorModel(cs, 32,
0xff0000, 0xff00, 0xff, 0xff000000,
true, DataBuffer.TYPE_INT);
default:
return null;
}
}
public boolean isDoubleBuffered() {
return true;
}
@Override
public String toString() {
return ("VKGraphicsConfig[" + getDevice().getIDstring() + "]");
}
private static class VKBufferCaps extends BufferCapabilities {
public VKBufferCaps(boolean dblBuf) {
super(imageCaps, imageCaps,
dblBuf ? FlipContents.UNDEFINED : null);
}
}
@Override
public BufferCapabilities getBufferCapabilities() {
if (bufferCaps == null) {
bufferCaps = new VKBufferCaps(isDoubleBuffered());
}
return bufferCaps;
}
private static class VKImageCaps extends ImageCapabilities {
private VKImageCaps() {
super(true);
}
public boolean isTrueVolatile() {
return true;
}
}
@Override
public ImageCapabilities getImageCapabilities() {
return imageCaps;
}
@Override
public VolatileImage createCompatibleVolatileImage(int width, int height,
int transparency,
int type) {
if ((type != RT_TEXTURE && type != TEXTURE) ||
transparency == Transparency.BITMASK) {
return null;
}
SunVolatileImage vi = new AccelTypedVolatileImage(this, width, height,
transparency, type);
Surface sd = vi.getDestSurface();
if (!(sd instanceof AccelSurface) ||
((AccelSurface)sd).getType() != type)
{
vi.flush();
vi = null;
}
return vi;
}
@Override
public SurfaceData createSurfaceData(WLComponentPeer peer) {
return WLVKSurfaceData.createData(peer);
}
/**
* {@inheritDoc}
*
* @see AccelGraphicsConfig#getContextCapabilities
*/
@Override
public ContextCapabilities getContextCapabilities() {
return vkCaps;
}
}

View File

@@ -0,0 +1,149 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package sun.java2d.vulkan;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.image.ColorModel;
import sun.awt.wl.WLComponentPeer;
import sun.awt.wl.WLGraphicsConfig;
import sun.java2d.SurfaceData;
import sun.java2d.loops.SurfaceType;
import sun.java2d.pipe.BufferedContext;
import sun.java2d.wl.WLSurfaceData;
import sun.java2d.wl.WLSurfaceDataExt;
import sun.util.logging.PlatformLogger;
public abstract class WLVKSurfaceData extends VKSurfaceData implements WLSurfaceDataExt {
private static final PlatformLogger log = PlatformLogger.getLogger("sun.java2d.vulkan.WLVKSurfaceData");
protected WLComponentPeer peer;
protected WLVKGraphicsConfig graphicsConfig;
private native void initOps(WLVKGraphicsConfig gc, WLComponentPeer peer);
@Override
public native void assignSurface(long surfacePtr);
@Override
public native void revalidate(int width, int height, int scale);
protected native void initOps(int width, int height, int scale, int backgroundRGB);
protected WLVKSurfaceData(WLComponentPeer peer, WLVKGraphicsConfig gc,
SurfaceType sType, ColorModel cm, int type)
{
super(gc, cm, type, 0, 0);
this.peer = peer;
this.graphicsConfig = gc;
final int backgroundRGB = peer.getBackground() != null
? peer.getBackground().getRGB()
: 0;
int scale = ((WLGraphicsConfig)peer.getGraphicsConfiguration()).getScale();
initOps(peer.getBufferWidth(), peer.getBufferHeight(), scale, backgroundRGB);
}
@Override
public boolean isOnScreen() {
return false;
}
public GraphicsConfiguration getDeviceConfiguration() {
return graphicsConfig;
}
/**
* Creates a SurfaceData object representing surface of on-screen Window.
*/
public static WLVKWindowSurfaceData createData(WLComponentPeer peer) {
WLVKGraphicsConfig gc = getGC(peer);
return new WLVKWindowSurfaceData(peer, gc);
}
public static WLVKGraphicsConfig getGC(WLComponentPeer peer) {
if (peer != null) {
return (WLVKGraphicsConfig) peer.getGraphicsConfiguration();
} else {
// REMIND: this should rarely (never?) happen, but what if
// default config is not WLVK?
GraphicsEnvironment env =
GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gd = env.getDefaultScreenDevice();
return (WLVKGraphicsConfig)gd.getDefaultConfiguration();
}
}
public static class WLVKWindowSurfaceData extends WLVKSurfaceData {
public WLVKWindowSurfaceData(WLComponentPeer peer, WLVKGraphicsConfig gc)
{
super(peer, gc, gc.getSurfaceType(), peer.getColorModel(), WINDOW);
}
public SurfaceData getReplacement() {
return WLSurfaceData.createData(peer);
}
@Override
public long getNativeResource(int resType) {
return 0;
}
public Rectangle getBounds() {
Rectangle r = peer.getVisibleBounds();
r.x = r.y = 0;
r.width = (int) Math.ceil(r.width * scale);
r.height = (int) Math.ceil(r.height * scale);
return r;
}
/**
* Returns destination Component associated with this SurfaceData.
*/
public Object getDestination() {
return peer.getTarget();
}
@Override
public double getDefaultScaleX() {
return scale;
}
@Override
public double getDefaultScaleY() {
return scale;
}
@Override
public BufferedContext getContext() {
return graphicsConfig.getContext();
}
@Override
public boolean isOnScreen() {
return true;
}
}
}

View File

@@ -0,0 +1,96 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package sun.java2d.vulkan;
import sun.awt.image.SunVolatileImage;
import sun.awt.image.VolatileSurfaceManager;
import sun.java2d.SurfaceData;
import java.awt.GraphicsConfiguration;
import java.awt.Transparency;
import java.awt.image.ColorModel;
import sun.java2d.pipe.hw.AccelSurface;
public class WLVKVolatileSurfaceManager extends VolatileSurfaceManager {
private final boolean accelerationEnabled;
public WLVKVolatileSurfaceManager(SunVolatileImage vImg, Object context) {
super(vImg, context);
/*
* We will attempt to accelerate this image only
* if the image is not bitmask
*/
int transparency = vImg.getTransparency();
// TODO: enable acceleration
accelerationEnabled = false; // transparency != Transparency.BITMASK;
}
protected boolean isAccelerationEnabled() {
return accelerationEnabled;
}
/**
* Create a SurfaceData object (or init the backbuffer
* of an existing window if this is a double buffered GraphicsConfig)
*/
protected SurfaceData initAcceleratedSurface() {
/* TODO
try {
WLVKGraphicsConfig gc =
(WLVKGraphicsConfig)vImg.getGraphicsConfig();
ColorModel cm = gc.getColorModel(vImg.getTransparency());
int type = vImg.getForcedAccelSurfaceType();
// if acceleration type is forced (type != UNDEFINED) then
// use the forced type, otherwise choose RT_TEXTURE
if (type == AccelSurface.UNDEFINED) {
type = AccelSurface.RT_TEXTURE;
}
return WLVKSurfaceData.createData(gc,
vImg.getWidth(),
vImg.getHeight(),
cm, vImg, type);
} catch (NullPointerException | OutOfMemoryError ignored) {
return null;
}
*/
return null;
}
@Override
protected boolean isConfigValid(GraphicsConfiguration gc) {
return ((gc == null) || (gc == vImg.getGraphicsConfig()));
}
@Override
public void initContents() {
if (vImg.getForcedAccelSurfaceType() != AccelSurface.TEXTURE) {
super.initContents();
}
}
}

View File

@@ -15,7 +15,7 @@ import sun.java2d.SurfaceData;
import sun.java2d.loops.SurfaceType;
import sun.util.logging.PlatformLogger;
public class WLSurfaceData extends SurfaceData {
public class WLSurfaceData extends SurfaceData implements WLSurfaceDataExt {
private static final PlatformLogger log = PlatformLogger.getLogger("sun.java2d.wl.WLSurfaceData");
private final WLComponentPeer peer;
@@ -71,10 +71,6 @@ public class WLSurfaceData extends SurfaceData {
return peer.getTarget();
}
public static boolean isAccelerationEnabled() {
return false;
}
public static SurfaceData createData(WLGraphicsConfig gc, int width, int height, ColorModel cm,
SunVolatileImage vImg, long drawable, int opaque,
boolean b) {
@@ -83,5 +79,6 @@ public class WLSurfaceData extends SurfaceData {
public native void revalidate(int width, int height, int scale);
public native void commitToServer();
@Override
public native void flush();
}

View File

@@ -0,0 +1,7 @@
package sun.java2d.wl;
public interface WLSurfaceDataExt {
void assignSurface(long surfacePtr);
void revalidate(int width, int height, int scale);
}

View File

@@ -1,8 +0,0 @@
#include "VKWLGraphicsConfig.h"
#include <dlfcn.h>
#include <Trace.h>
#include <stdint.h>
#include <jvm_md.h>
#include "jni.h"
// TODO

View File

@@ -1,6 +0,0 @@
#ifndef VKWLGraphicsConfig_h_Included
#define VKWLGraphicsConfig_h_Included
// TODO
#endif /* VKWLGraphicsConfig_h_Included */

View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
#include "jni.h"
#include "VKBase.h"
/*
* Class: sun_java2d_vulkan_WLVKGraphicsConfig
* Method: nativeGetMaxTextureSize
* Signature: ()I
*/
extern "C" JNIEXPORT jint JNICALL Java_sun_java2d_vulkan_WLVKGraphicsConfig_nativeGetMaxTextureSize
(JNIEnv *env, jclass vkgc) {
return VK_MaxTextureSize();
}

View File

@@ -0,0 +1,339 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
#include "jni.h"
#include "WLVKSurfaceData.h"
#include <Trace.h>
#include <SurfaceData.h>
#include "VKSurfaceData.h"
#include "VKBase.h"
#include <jni_util.h>
#include <cstdlib>
#include <string>
extern struct wl_display *wl_display;
/**
* This is the implementation of the general surface LockFunc defined in
* SurfaceData.h.
*/
jint
WLVKSD_Lock(JNIEnv *env,
SurfaceDataOps *ops,
SurfaceDataRasInfo *pRasInfo,
jint lockflags)
{
#ifndef HEADLESS
VKSDOps *vsdo = (VKSDOps*)ops;
J2dTrace1(J2D_TRACE_INFO, "WLVKSD_Unlock: %p\n", ops);
pthread_mutex_lock(&((WLVKSDOps*)vsdo->privOps)->lock);
#endif
return SD_SUCCESS;
}
static void
WLVKSD_GetRasInfo(JNIEnv *env,
SurfaceDataOps *ops,
SurfaceDataRasInfo *pRasInfo)
{
#ifndef HEADLESS
VKSDOps *vsdo = (VKSDOps*)ops;
#endif
}
static void
WLVKSD_Unlock(JNIEnv *env,
SurfaceDataOps *ops,
SurfaceDataRasInfo *pRasInfo)
{
#ifndef HEADLESS
VKSDOps *vsdo = (VKSDOps*)ops;
J2dTrace1(J2D_TRACE_INFO, "WLVKSD_Unlock: %p\n", ops);
pthread_mutex_unlock(&((WLVKSDOps*)vsdo->privOps)->lock);
#endif
}
static void
WLVKSD_Dispose(JNIEnv *env, SurfaceDataOps *ops)
{
#ifndef HEADLESS
/* ops is assumed non-null as it is checked in SurfaceData_DisposeOps */
VKSDOps *vsdo = (VKSDOps*)ops;
J2dTrace1(J2D_TRACE_INFO, "WLSD_Dispose %p\n", ops);
WLVKSDOps *wlvksdOps = (WLVKSDOps*)vsdo->privOps;
pthread_mutex_destroy(&wlvksdOps->lock);
if (wlvksdOps->wlvkSD !=nullptr) {
delete wlvksdOps->wlvkSD;
wlvksdOps->wlvkSD = nullptr;
}
#endif
}
extern "C" JNIEXPORT void JNICALL Java_sun_java2d_vulkan_WLVKSurfaceData_initOps
(JNIEnv *env, jclass vksd, jint width, jint height, jint scale, jint backgroundRGB) {
#ifndef HEADLESS
VKSDOps *vsdo = (VKSDOps*)SurfaceData_InitOps(env, vksd, sizeof(VKSDOps));
J2dRlsTraceLn1(J2D_TRACE_INFO, "WLVKSurfaceData_initOps: %p", vsdo);
jboolean hasException;
if (vsdo == NULL) {
JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed.");
return;
}
if (width <= 0) {
width = 1;
}
if (height <= 0) {
height = 1;
}
WLVKSDOps *wlvksdOps = (WLVKSDOps *)malloc(sizeof(WLVKSDOps));
if (wlvksdOps == NULL) {
JNU_ThrowOutOfMemoryError(env, "creating native WLVK ops");
return;
}
vsdo->privOps = wlvksdOps;
vsdo->sdOps.Lock = WLVKSD_Lock;
vsdo->sdOps.Unlock = WLVKSD_Unlock;
vsdo->sdOps.GetRasInfo = WLVKSD_GetRasInfo;
vsdo->sdOps.Dispose = WLVKSD_Dispose;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
// Recursive mutex is required because blit can be done with both source
// and destination being the same surface (during scrolling, for example).
// So WLSD_Lock() should be able to lock the same surface twice in a row.
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
pthread_mutex_init(&wlvksdOps->lock, &attr);
wlvksdOps->wlvkSD = new WLVKSurfaceData(width, height, scale, backgroundRGB);
#endif /* !HEADLESS */
}
extern "C" JNIEXPORT void JNICALL
Java_sun_java2d_vulkan_WLVKSurfaceData_assignSurface(JNIEnv *env, jobject wsd,
jlong wlSurfacePtr)
{
#ifndef HEADLESS
VKSDOps *vsdo = (VKSDOps*)SurfaceData_GetOps(env, wsd);
if (vsdo == NULL) {
return;
}
WLVKSDOps *wlvksdOps = (WLVKSDOps*)vsdo->privOps;
wl_surface* wlSurface = (struct wl_surface*)jlong_to_ptr(wlSurfacePtr);
J2dTraceLn2(J2D_TRACE_INFO, "WLVKSurfaceData_assignSurface wl_surface(%p) wl_display(%p)",
wlSurface, wl_display);
try {
wlvksdOps->wlvkSD->validate(wlSurface);
} catch (std::exception& e) {
J2dRlsTrace1(J2D_TRACE_ERROR, "WLVKSurfaceData_assignSurface: %s\n", e.what());
}
#endif /* !HEADLESS */
}
extern "C" JNIEXPORT void JNICALL
Java_sun_java2d_vulkan_WLVKSurfaceData_flush(JNIEnv *env, jobject wsd)
{
#ifndef HEADLESS
J2dTrace(J2D_TRACE_INFO, "WLVKSurfaceData_flush\n");
#endif /* !HEADLESS */
}
extern "C" JNIEXPORT void JNICALL
Java_sun_java2d_vulkan_WLVKSurfaceData_revalidate(JNIEnv *env, jobject wsd,
jint width, jint height, jint scale)
{
#ifndef HEADLESS
VKSDOps *vsdo = (VKSDOps*)SurfaceData_GetOps(env, wsd);
if (vsdo == NULL) {
return;
}
J2dTrace3(J2D_TRACE_INFO, "WLVKSurfaceData_revalidate to size %d x %d and scale %d\n", width, height, scale);
WLVKSDOps *wlvksdOps = (WLVKSDOps*)vsdo->privOps;
try {
wlvksdOps->wlvkSD->revalidate(width, height, scale);
wlvksdOps->wlvkSD->update();
} catch (std::exception& e) {
J2dRlsTrace1(J2D_TRACE_ERROR, "WLVKSurfaceData_revalidate: %s\n", e.what());
}
#endif /* !HEADLESS */
}
extern "C" JNIEXPORT void JNICALL
JNI_OnUnload(JavaVM *vm, void *reserved) {
#ifndef HEADLESS
VKGraphicsEnvironment::dispose();
#endif /* !HEADLESS */
}
WLVKSurfaceData::WLVKSurfaceData(uint32_t w, uint32_t h, uint32_t s, uint32_t bgc)
:VKSurfaceData(w, h, s, bgc), _wl_surface(nullptr), _surface_khr(nullptr), _swapchain_khr(nullptr)
{
J2dTrace3(J2D_TRACE_INFO, "Create WLVKSurfaceData with size %d x %d and scale %d\n", w, h, s);
}
void WLVKSurfaceData::validate(wl_surface* wls)
{
if (wls ==_wl_surface) {
return;
}
_wl_surface = wls;
vk::WaylandSurfaceCreateInfoKHR createInfoKhr = {
{}, wl_display, _wl_surface
};
_surface_khr =
VKGraphicsEnvironment::graphics_environment()->vk_instance().createWaylandSurfaceKHR(
createInfoKhr);
revalidate(width(), height(), scale());
update();
}
void WLVKSurfaceData::revalidate(uint32_t w, uint32_t h, uint32_t s)
{
if (s == scale() && w == width() && h == height() ) {
if (!*_surface_khr || *_swapchain_khr) {
J2dTraceLn2(J2D_TRACE_INFO,
"WLVKSurfaceData_revalidate is skipped: surface_khr(%p) swapchain_khr(%p)",
*_surface_khr, *_swapchain_khr);
return;
}
} else {
VKSurfaceData::revalidate(w, h, s);
if (!*_surface_khr) {
J2dTraceLn1(J2D_TRACE_INFO,"WLVKSurfaceData_revalidate is skipped: surface_khr(%p)",
*_surface_khr);
return;
}
}
vk::SwapchainCreateInfoKHR swapchainCreateInfoKhr{
{},
*_surface_khr,
1, vk::Format::eB8G8R8A8Unorm,
vk::ColorSpaceKHR::eVkColorspaceSrgbNonlinear,
{width()/scale(), height()/scale()},
1,
vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferDst,
vk::SharingMode::eExclusive,
0,
nullptr,
vk::SurfaceTransformFlagBitsKHR::eIdentity,
vk::CompositeAlphaFlagBitsKHR::eOpaque,
vk::PresentModeKHR::eImmediate,
false, *_swapchain_khr
};
auto& device = VKGraphicsEnvironment::graphics_environment()->default_device();
_swapchain_khr = device.createSwapchainKHR(swapchainCreateInfoKhr);
}
void WLVKSurfaceData::set_bg_color(uint32_t bgc)
{
if (bg_color() == bgc) {
return;
}
VKSurfaceData::set_bg_color(bgc);
update();
}
void WLVKSurfaceData::update()
{
if (!*_swapchain_khr) {
return;
}
auto& device = VKGraphicsEnvironment::graphics_environment()->default_device();
vk::SemaphoreCreateInfo semInfo = {};
vk::raii::Semaphore presentCompleteSem = device.createSemaphore(semInfo);
std::pair<vk::Result, uint32_t> img = _swapchain_khr.acquireNextImage(0, *presentCompleteSem, nullptr);
if (img.first!=vk::Result::eSuccess) {
J2dRlsTraceLn(J2D_TRACE_INFO, "failed to get image");
}
else {
J2dRlsTraceLn(J2D_TRACE_INFO, "obtained image");
}
auto images = _swapchain_khr.getImages();
vk::CommandPoolCreateInfo poolInfo{
{vk::CommandPoolCreateFlagBits::eResetCommandBuffer},
static_cast<uint32_t>(device.queue_family())
};
auto pool = device.createCommandPool(poolInfo);
vk::CommandBufferAllocateInfo buffInfo{
*pool, vk::CommandBufferLevel::ePrimary, (uint32_t) 1, nullptr
};
auto buffers = device.allocateCommandBuffers(buffInfo);
vk::CommandBufferBeginInfo begInfo{
};
uint32_t alpha = (bg_color() >> 24) & 0xFF;
uint32_t red = (bg_color() >> 16) & 0xFF;
uint32_t green = (bg_color() >> 8) & 0xFF;
uint32_t blue = bg_color() & 0xFF;
vk::ClearColorValue color = {
static_cast<float>(red)/255.0f,
static_cast<float>(green)/255.0f,
static_cast<float>(blue)/255.0f,
static_cast<float>(alpha)/255.0f
};
std::vector<vk::ImageSubresourceRange> range = {{
vk::ImageAspectFlagBits::eColor,
0, 1, 0, 1}};
buffers[0].begin(begInfo);
buffers[0].clearColorImage(images[img.second], vk::ImageLayout::eSharedPresentKHR, color, range);
buffers[0].end();
vk::SubmitInfo submitInfo{
nullptr, nullptr, *buffers[0], nullptr
};
auto queue = device.getQueue(device.queue_family(), 0);
queue.submit(submitInfo, nullptr);
queue.waitIdle();
vk::PresentInfoKHR presentInfo;
presentInfo.swapchainCount = 1;
presentInfo.pSwapchains = &*_swapchain_khr;
presentInfo.pImageIndices = &(img.second);
queue.presentKHR(presentInfo);
queue.waitIdle();
device.waitIdle();
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
#ifndef WLVKSurfaceData_h_Included
#define WLVKSurfaceData_h_Included
#include <cstdlib>
#include <vulkan/vulkan.h>
#include <SurfaceData.h>
#include <VKBase.h>
#ifdef HEADLESS
#define WLVKSDOps void
#else /* HEADLESS */
class WLVKSurfaceData : public VKSurfaceData {
wl_surface* _wl_surface;
vk::raii::SurfaceKHR _surface_khr;
vk::raii::SwapchainKHR _swapchain_khr;
public:
WLVKSurfaceData(uint32_t w, uint32_t h, uint32_t s, uint32_t bgc);
void validate(wl_surface* wls);
void revalidate(uint32_t w, uint32_t h, uint32_t s);
void set_bg_color(uint32_t bgc);
void update();
};
/**
* The WLVKSDOps structure contains the WLVK-specific information for a given
* WLVKSurfaceData. It is referenced by the native OGLSDOps structure.
*
* wl_surface* wlSurface;
* For onscreen windows, we maintain a reference to that window's associated
* wl_surface handle here. Offscreen surfaces have no associated Window, so for
* those surfaces, this value will simply be zero.
*
* VkSurfaceKHR* surface;
* Vulkan surface associated with this surface.
*/
typedef struct _WLVKSDOps {
SurfaceDataOps sdOps;
WLVKSurfaceData* wlvkSD;
pthread_mutex_t lock;
} WLVKSDOps;
#endif /* HEADLESS */
#endif /* WLVKSurfaceData_h_Included */

View File

@@ -92,10 +92,10 @@ Java_sun_java2d_wl_WLSurfaceData_assignSurface(JNIEnv *env, jobject wsd,
}
JNIEXPORT void JNICALL
Java_sun_java2d_wl_WLSurfaceData_commitToServer(JNIEnv *env, jobject wsd)
Java_sun_java2d_wl_WLSurfaceData_flush(JNIEnv *env, jobject wsd)
{
#ifndef HEADLESS
J2dTrace(J2D_TRACE_INFO, "WLSurfaceData_commitToServer\n");
J2dTrace(J2D_TRACE_INFO, "WLSurfaceData_flush\n");
WLSDOps *wsdo = (WLSDOps*)SurfaceData_GetOps(env, wsd);
if (wsdo == NULL) {
return;

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2022, JetBrains s.r.o.. All rights reserved.
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 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
@@ -24,19 +25,13 @@
*/
#ifndef HEADLESS
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <Trace.h>
#include "jvm_md.h"
#include "jni_util.h"
#include "awt.h"
#include "WLToolkit.h"
#include "VKBase.h"
#include "VKWLGraphicsConfig.h"
typedef struct WLOutput {
struct WLOutput * next;