Skip to content

Commit

Permalink
JBR-8118 TextureWrapperImage for MTLTexture
Browse files Browse the repository at this point in the history
  • Loading branch information
ujpv committed Feb 19, 2025
1 parent 8a8750e commit 71b988a
Show file tree
Hide file tree
Showing 14 changed files with 638 additions and 3 deletions.
3 changes: 3 additions & 0 deletions make/test/JtregNativeJdk.gmk
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,14 @@ ifeq ($(call isTargetOs, macosx), true)
BUILD_JDK_JTREG_EXECUTABLES_JDK_LIBS_exeJniInvocationTest := java.base:libjli
BUILD_JDK_JTREG_LIBRARIES_LIBS_libTestDynamicStore := \
-framework Cocoa -framework SystemConfiguration
BUILD_JDK_JTREG_LIBRARIES_LIBS_libSharedTexturesTest := \
-framework Cocoa -framework Metal
else
BUILD_JDK_JTREG_EXCLUDE += libTestMainKeyWindow.m
BUILD_JDK_JTREG_EXCLUDE += libTestDynamicStore.m
BUILD_JDK_JTREG_EXCLUDE += exeJniInvocationTest.c
BUILD_JDK_JTREG_EXCLUDE += exeLibraryCache.c
BUILD_JDK_JTREG_EXCLUDE += libSharedTexturesTest.m
endif

ifeq ($(OPENJDK_TARGET_OS), windows)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,16 @@

package sun.java2d;

import java.awt.GraphicsConfiguration;
import java.awt.Image;

import sun.awt.CGraphicsEnvironment;
import sun.awt.image.SunVolatileImage;
import sun.awt.image.SurfaceManager;
import sun.awt.image.TextureWrapperSurfaceManager;
import sun.awt.image.VolatileSurfaceManager;
import sun.java2d.metal.MTLGraphicsConfig;
import sun.java2d.metal.MTLSurfaceData;
import sun.java2d.metal.MTLVolatileSurfaceManager;
import sun.java2d.opengl.CGLVolatileSurfaceManager;

Expand All @@ -54,4 +61,15 @@ public VolatileSurfaceManager createVolatileManager(SunVolatileImage vImg,
return CGraphicsEnvironment.usingMetalPipeline() ? new MTLVolatileSurfaceManager(vImg, context) :
new CGLVolatileSurfaceManager(vImg, context);
}

@Override
public SurfaceManager createTextureWrapperSurfaceManager(GraphicsConfiguration gc, Image image, long texture) {
SurfaceData sd;
if (gc instanceof MTLGraphicsConfig) {
sd = MTLSurfaceData.createData((MTLGraphicsConfig) gc, image, texture);
} else {
throw new UnsupportedOperationException("Unsupported GraphicsConfiguration");
}
return new TextureWrapperSurfaceManager(sd);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@

import java.awt.image.ColorModel;
import java.awt.image.Raster;
import java.util.concurrent.atomic.AtomicBoolean;

import static sun.java2d.pipe.BufferedOpCodes.DISPOSE_SURFACE;
import static sun.java2d.pipe.BufferedOpCodes.FLUSH_SURFACE;
Expand Down Expand Up @@ -200,6 +201,10 @@ public static MTLOffScreenSurfaceData createData(MTLGraphicsConfig gc,
type);
}

public static MTLTextureWrapperSurfaceData createData(MTLGraphicsConfig gc, Image image, long pTexture) {
return new MTLTextureWrapperSurfaceData(gc, image, pTexture);
}

@Override
public double getDefaultScaleX() {
return scale;
Expand All @@ -219,6 +224,8 @@ public Rectangle getBounds() {

protected native boolean initTexture(long pData, boolean isOpaque, int width, int height);

protected native boolean initWithTexture(long pData, boolean isOpaque, long texturePtr);

protected native boolean initRTexture(long pData, boolean isOpaque, int width, int height);

protected native boolean initFlipBackbuffer(long pData, boolean isOpaque, int width, int height);
Expand Down Expand Up @@ -674,4 +681,46 @@ protected void loadNativeRaster(long pRaster, int width, int height, long pRects
}

private static native boolean loadNativeRasterWithRects(long sdops, long pRaster, int width, int height, long pRects, int rectsCount);

/**
* Surface data for an existing texture
*/
public static final class MTLTextureWrapperSurfaceData extends MTLSurfaceData {
private final Image myImage;

private MTLTextureWrapperSurfaceData(MTLGraphicsConfig gc, Image image, long pTexture) throws IllegalArgumentException {
super(null, gc, ColorModel.getRGBdefault(), RT_TEXTURE, /*width=*/ 0, /*height=*/ 0);
myImage = image;

MTLRenderQueue rq = MTLRenderQueue.getInstance();
AtomicBoolean success = new AtomicBoolean(false);

rq.lock();
try {
MTLContext.setScratchSurface(gc);
rq.flushAndInvokeNow(() -> success.set(initWithTexture(getNativeOps(), false, pTexture)));
} finally {
rq.unlock();
}

if (!success.get()) {
throw new IllegalArgumentException("Failed to init the surface data");
}
}

@Override
public SurfaceData getReplacement() {
throw new UnsupportedOperationException("not implemented");
}

@Override
public Object getDestination() {
return myImage;
}

@Override
public Rectangle getBounds() {
return getNativeBounds();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,81 @@ static jboolean MTLSurfaceData_initTexture(BMTLSDOps *bmtlsdo, jboolean isOpaque
}
}

static jboolean MTLSurfaceData_initWithTexture(BMTLSDOps *bmtlsdo, jboolean isOpaque, void* pTexture) {
@autoreleasepool {
if (bmtlsdo == NULL) {
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: ops are null");
return JNI_FALSE;
}

if (pTexture == NULL) {
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: texture is null");
return JNI_FALSE;
}

id <MTLTexture> texture = (__bridge id <MTLTexture>) pTexture;
if (texture == NULL) {
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: failed to cast texture to MTLTexture");
return JNI_FALSE;
}

if (texture.width >= MTL_GPU_FAMILY_MAC_TXT_SIZE || texture.height >= MTL_GPU_FAMILY_MAC_TXT_SIZE ||
texture.width == 0 || texture.height == 0) {
J2dRlsTraceLn2(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: wrong texture size %d x %d",
texture.width, texture.height);
return JNI_FALSE;
}

if (texture.pixelFormat != MTLPixelFormatBGRA8Unorm) {
J2dRlsTraceLn1(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: unsupported pixel format: %d",
texture.pixelFormat);
return JNI_FALSE;
}

bmtlsdo->pTexture = texture;
bmtlsdo->pOutTexture = NULL;

MTLSDOps *mtlsdo = (MTLSDOps *)bmtlsdo->privOps;
if (mtlsdo == NULL) {
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: MTLSDOps are null");
return JNI_FALSE;
}
if (mtlsdo->configInfo == NULL || mtlsdo->configInfo->context == NULL) {
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initWithTexture: MTLSDOps wasn't initialized (context is null)");
return JNI_FALSE;
}
MTLContext* ctx = mtlsdo->configInfo->context;
MTLTextureDescriptor *stencilDataDescriptor =
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatR8Uint
width:texture.width
height:texture.height
mipmapped:NO];
stencilDataDescriptor.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead;
stencilDataDescriptor.storageMode = MTLStorageModePrivate;
bmtlsdo->pStencilData = [ctx.device newTextureWithDescriptor:stencilDataDescriptor];

MTLTextureDescriptor *stencilTextureDescriptor =
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatStencil8
width:texture.width
height:texture.height
mipmapped:NO];
stencilTextureDescriptor.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite;
stencilTextureDescriptor.storageMode = MTLStorageModePrivate;
bmtlsdo->pStencilTexture = [ctx.device newTextureWithDescriptor:stencilTextureDescriptor];

bmtlsdo->isOpaque = isOpaque;
bmtlsdo->width = texture.width;
bmtlsdo->height = texture.height;
bmtlsdo->drawableType = MTLSD_RT_TEXTURE;

[texture retain];

J2dTraceLn6(J2D_TRACE_VERBOSE, "MTLSurfaceData_initTexture: w=%d h=%d bp=%p [tex=%p] opaque=%d sfType=%d",
bmtlsdo->width, bmtlsdo->height, bmtlsdo, bmtlsdo->pTexture, isOpaque, bmtlsdo->drawableType);
return JNI_TRUE;
}
}

/**
* Initializes an MTL texture, using the given width and height as
* a guide.
Expand All @@ -120,6 +195,19 @@ static jboolean MTLSurfaceData_initTexture(BMTLSDOps *bmtlsdo, jboolean isOpaque
return JNI_TRUE;
}

JNIEXPORT jboolean JNICALL
Java_sun_java2d_metal_MTLSurfaceData_initWithTexture(
JNIEnv *env, jobject mtlds,
jlong pData, jboolean isOpaque,
jlong pTexture) {
BMTLSDOps *bmtlsdops = (BMTLSDOps *) pData;
if (!MTLSurfaceData_initWithTexture(bmtlsdops, isOpaque, jlong_to_ptr(pTexture))) {
return JNI_FALSE;
}
MTLSD_SetNativeDimensions(env, (BMTLSDOps *) pData, bmtlsdops->width, bmtlsdops->height);
return JNI_TRUE;
}

/**
* Initializes a framebuffer object, using the given width and height as
* a guide. See MTLSD_InitTextureObject() and MTLSD_initRTexture()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright 2025 JetBrains s.r.o.
* 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 com.jetbrains.desktop;

import com.jetbrains.desktop.image.TextureWrapperImage;
import com.jetbrains.exported.JBRApi;
import sun.awt.SunToolkit;

import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.Image;

@JBRApi.Service
@JBRApi.Provides("SharedTextures")
public class SharedTextures {
public final static int METAL_TEXTURE_TYPE = 1;

private final int textureType;

public static SharedTextures create() {
return new SharedTextures();
}

private SharedTextures() {
textureType = getTextureTypeImpl();
if (textureType == 0) {
throw new JBRApi.ServiceNotAvailableException();
}
}

public int getTextureType() {
return textureType;
}

public Image wrapTexture(GraphicsConfiguration gc, long texture) {
return new TextureWrapperImage(gc, texture);
}

private static int getTextureTypeImpl() {
GraphicsConfiguration gc = GraphicsEnvironment
.getLocalGraphicsEnvironment()
.getDefaultScreenDevice()
.getDefaultConfiguration();
try {
if (SunToolkit.isInstanceOf(gc, "sun.java2d.metal.MTLGraphicsConfig")) {
return METAL_TEXTURE_TYPE;
}
} catch (Exception e) {
throw new InternalError("Unexpected exception during reflection", e);
}

return 0;
}
}
Loading

0 comments on commit 71b988a

Please sign in to comment.