mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-06 01:19:28 +01:00
JBR-8119 JBR-9104 JBR-9106 opengl: shared textures
This commit is contained in:
@@ -98,7 +98,8 @@ ifeq ($(call isTargetOs, macosx), true)
|
||||
BUILD_JDK_JTREG_LIBRARIES_LIBS_libTestDynamicStore := \
|
||||
-framework Cocoa -framework SystemConfiguration
|
||||
BUILD_JDK_JTREG_LIBRARIES_LIBS_libSharedTexturesTest := \
|
||||
-framework Cocoa -framework Metal
|
||||
-framework Cocoa -framework Metal -framework OpenGL
|
||||
BUILD_JDK_JTREG_EXCLUDE += libSharedTexturesTest.c
|
||||
else
|
||||
BUILD_JDK_JTREG_EXCLUDE += libTestMainKeyWindow.m
|
||||
BUILD_JDK_JTREG_EXCLUDE += libTestDynamicStore.m
|
||||
@@ -110,6 +111,7 @@ endif
|
||||
ifeq ($(OPENJDK_TARGET_OS), windows)
|
||||
BUILD_JDK_JTREG_LIBRARIES_LIBS_libwindows_touch_robot := user32.lib
|
||||
BUILD_JDK_JTREG_EXCLUDE += libtouchscreen_device.c
|
||||
BUILD_JDK_JTREG_LIBRARIES_LIBS_libSharedTexturesTest := gdi32.lib opengl32.lib user32.lib
|
||||
else
|
||||
ifeq ($(OPENJDK_TARGET_OS), linux)
|
||||
BUILD_JDK_JTREG_EXCLUDE += libwindows_touch_robot.c
|
||||
@@ -125,6 +127,8 @@ ifeq ($(call isTargetOs, linux), true)
|
||||
BUILD_JDK_JTREG_LIBRARIES_STRIP_SYMBOLS_libFib := false
|
||||
# nio tests' libCreationTimeHelper native needs -ldl linker flag
|
||||
BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libCreationTimeHelper := -ldl
|
||||
# libSharedTexturesTest needs X11 and GL libraries
|
||||
# BUILD_JDK_JTREG_LIBRARIES_LIBS_libSharedTexturesTest := -lX11 -lGL -lGLX
|
||||
endif
|
||||
|
||||
ifeq ($(ASAN_ENABLED), true)
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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.TextureWrapperSurfaceManager;
|
||||
import com.jetbrains.exported.JBRApi;
|
||||
import sun.awt.image.SurfaceManager;
|
||||
import sun.java2d.SurfaceData;
|
||||
|
||||
import sun.java2d.opengl.*;
|
||||
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.Image;
|
||||
|
||||
@JBRApi.Service
|
||||
@JBRApi.Provides("SharedTextures")
|
||||
public class SharedTexturesService extends SharedTextures {
|
||||
@Override
|
||||
public int getTextureType(GraphicsConfiguration gc) {
|
||||
if (gc instanceof GLXGraphicsConfig) {
|
||||
return OPENGL_TEXTURE_TYPE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long[] getOpenGLContextInfo(GraphicsConfiguration gc) {
|
||||
if (gc instanceof GLXGraphicsConfig glxGraphicsConfig) {
|
||||
return new long[] {
|
||||
GLXGraphicsConfigExt.getSharedContext(),
|
||||
GLXGraphicsConfigExt.getAwtDisplay(),
|
||||
GLXGraphicsConfigExt.getFBConfig(glxGraphicsConfig),
|
||||
};
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException("Unsupported graphics configuration: " + gc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SurfaceManager createSurfaceManager(GraphicsConfiguration gc, Image image, long texture) {
|
||||
SurfaceData sd;
|
||||
if (gc instanceof GLXGraphicsConfig glxGraphicsConfig) {
|
||||
sd = new GLXTextureWrapperSurfaceData(glxGraphicsConfig, image, texture);
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Unsupported graphics configuration: " + gc);
|
||||
}
|
||||
|
||||
return new TextureWrapperSurfaceManager(sd);
|
||||
}
|
||||
}
|
||||
@@ -31,36 +31,21 @@ import sun.awt.image.SurfaceManager;
|
||||
import sun.java2d.SurfaceData;
|
||||
import sun.java2d.metal.MTLGraphicsConfig;
|
||||
import sun.java2d.metal.MTLTextureWrapperSurfaceData;
|
||||
import sun.java2d.opengl.CGLGraphicsConfig;
|
||||
import sun.java2d.opengl.CGLGraphicsConfigExt;
|
||||
import sun.java2d.opengl.CGLTextureWrapperSurfaceData;
|
||||
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Image;
|
||||
import java.awt.*;
|
||||
|
||||
@JBRApi.Service
|
||||
@JBRApi.Provides("SharedTextures")
|
||||
public class SharedTexturesService extends SharedTextures {
|
||||
private final int textureType;
|
||||
|
||||
public SharedTexturesService() {
|
||||
textureType = getTextureTypeImpl();
|
||||
if (textureType == UNDEFINED_TEXTURE_TYPE) {
|
||||
throw new JBRApi.ServiceNotAvailableException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTextureType() {
|
||||
return textureType;
|
||||
}
|
||||
|
||||
private static int getTextureTypeImpl() {
|
||||
GraphicsConfiguration gc = GraphicsEnvironment
|
||||
.getLocalGraphicsEnvironment()
|
||||
.getDefaultScreenDevice()
|
||||
.getDefaultConfiguration();
|
||||
|
||||
public int getTextureType(GraphicsConfiguration gc) {
|
||||
if (gc instanceof MTLGraphicsConfig) {
|
||||
return METAL_TEXTURE_TYPE;
|
||||
} else if (gc instanceof CGLGraphicsConfig) {
|
||||
return OPENGL_TEXTURE_TYPE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -71,10 +56,24 @@ public class SharedTexturesService extends SharedTextures {
|
||||
SurfaceData sd;
|
||||
if (gc instanceof MTLGraphicsConfig mtlGraphicsConfig) {
|
||||
sd = new MTLTextureWrapperSurfaceData(mtlGraphicsConfig, image, texture);
|
||||
} else if (gc instanceof CGLGraphicsConfig cglGraphicsConfig) {
|
||||
sd = new CGLTextureWrapperSurfaceData(cglGraphicsConfig, image, texture);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported graphics configuration: " + gc);
|
||||
throw new UnsupportedOperationException("Unsupported graphics configuration: " + gc);
|
||||
}
|
||||
|
||||
return new TextureWrapperSurfaceManager(sd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long[] getOpenGLContextInfo(GraphicsConfiguration gc) {
|
||||
if (gc instanceof CGLGraphicsConfig cglGraphicsConfig) {
|
||||
return new long[] {
|
||||
CGLGraphicsConfigExt.getSharedContext(),
|
||||
CGLGraphicsConfigExt.getPixelFormat()
|
||||
};
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException("Unsupported graphics configuration: " + gc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package sun.java2d.opengl;
|
||||
|
||||
public class CGLGraphicsConfigExt {
|
||||
public static native long getSharedContext();
|
||||
public static native long getPixelFormat();
|
||||
}
|
||||
@@ -43,8 +43,8 @@ public abstract class CGLSurfaceData extends OGLSurfaceData {
|
||||
long pPeerData, long layerPtr, int xoff,
|
||||
int yoff, boolean isOpaque);
|
||||
|
||||
private CGLSurfaceData(CGLLayer layer, CGLGraphicsConfig gc,
|
||||
ColorModel cm, int type, int width, int height) {
|
||||
protected CGLSurfaceData(CGLLayer layer, CGLGraphicsConfig gc,
|
||||
ColorModel cm, int type, int width, int height) {
|
||||
super(gc, cm, type);
|
||||
// TEXTURE shouldn't be scaled, it is used for managed BufferedImages.
|
||||
scale = type == TEXTURE ? 1 : gc.getDevice().getScaleFactor();
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package sun.java2d.opengl;
|
||||
|
||||
import sun.java2d.SurfaceData;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class CGLTextureWrapperSurfaceData extends CGLSurfaceData {
|
||||
|
||||
public CGLTextureWrapperSurfaceData(CGLGraphicsConfig gc, Image image, long textureId) {
|
||||
super(null, gc, gc.getColorModel(TRANSLUCENT), RT_TEXTURE, 0, 0);
|
||||
|
||||
OGLRenderQueue rq = OGLRenderQueue.getInstance();
|
||||
AtomicBoolean success = new AtomicBoolean(false);
|
||||
rq.lock();
|
||||
try {
|
||||
OGLContext.setScratchSurface(gc);
|
||||
rq.flushAndInvokeNow(() -> success.set(OGLSurfaceDataExt.initWithTexture(this, textureId)));
|
||||
} finally {
|
||||
rq.unlock();
|
||||
}
|
||||
|
||||
if (!success.get()) {
|
||||
throw new IllegalArgumentException("Failed to init the surface data");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SurfaceData getReplacement() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rectangle getBounds() {
|
||||
return getNativeBounds();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getDestination() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
// reset the texture id first to avoid the texture deallocation
|
||||
OGLSurfaceDataExt.resetTextureId(this);
|
||||
super.flush();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#import "sun_java2d_opengl_CGLGraphicsConfigExt.h"
|
||||
|
||||
#import "JNIUtilities.h"
|
||||
|
||||
extern NSOpenGLContext *sharedContext;
|
||||
extern NSOpenGLPixelFormat *sharedPixelFormat;
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_sun_java2d_opengl_CGLGraphicsConfigExt_getSharedContext
|
||||
(JNIEnv *env, jclass cls)
|
||||
{
|
||||
return ptr_to_jlong(sharedContext.CGLContextObj);
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_sun_java2d_opengl_CGLGraphicsConfigExt_getPixelFormat
|
||||
(JNIEnv *env, jclass cls)
|
||||
{
|
||||
return ptr_to_jlong(sharedPixelFormat.CGLPixelFormatObj);
|
||||
}
|
||||
@@ -33,12 +33,24 @@ import java.awt.*;
|
||||
public abstract class SharedTextures {
|
||||
public final static int UNDEFINED_TEXTURE_TYPE = 0;
|
||||
public final static int METAL_TEXTURE_TYPE = 1;
|
||||
public final static int OPENGL_TEXTURE_TYPE = 2;
|
||||
|
||||
public abstract int getTextureType();
|
||||
@Deprecated
|
||||
public int getTextureType() {
|
||||
GraphicsConfiguration gc = GraphicsEnvironment
|
||||
.getLocalGraphicsEnvironment()
|
||||
.getDefaultScreenDevice()
|
||||
.getDefaultConfiguration();
|
||||
return getTextureType(gc);
|
||||
}
|
||||
|
||||
public abstract int getTextureType(GraphicsConfiguration gc);
|
||||
|
||||
public final Image wrapTexture(GraphicsConfiguration gc, long texture) {
|
||||
return new TextureWrapperImage((img) -> createSurfaceManager(gc, img, texture));
|
||||
}
|
||||
|
||||
public abstract long[] getOpenGLContextInfo(GraphicsConfiguration gc);
|
||||
|
||||
protected abstract SurfaceManager createSurfaceManager(GraphicsConfiguration gc, Image image, long texture);
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ import java.awt.ImageCapabilities;
|
||||
|
||||
|
||||
public class TextureWrapperSurfaceManager extends SurfaceManager {
|
||||
private final SurfaceData sd;
|
||||
private SurfaceData sd;
|
||||
|
||||
public TextureWrapperSurfaceManager(SurfaceData sd) {
|
||||
this.sd = sd;
|
||||
@@ -53,4 +53,10 @@ public class TextureWrapperSurfaceManager extends SurfaceManager {
|
||||
public ImageCapabilities getCapabilities(GraphicsConfiguration gc) {
|
||||
return new ImageCapabilities(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void flush() {
|
||||
sd.flush();
|
||||
sd = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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 sun.java2d.opengl;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
public class OGLGraphicsConfigExt {
|
||||
public static long getSharedContext(GraphicsConfiguration gc) {
|
||||
if (gc instanceof OGLGraphicsConfig) {
|
||||
return getSharedContext();
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Not an OpenGL graphics config: " + gc);
|
||||
}
|
||||
|
||||
public static long getPixelFormat(GraphicsConfiguration gc) {
|
||||
if (gc instanceof OGLGraphicsConfig oglGc) {
|
||||
return getPixelFormat(oglGc.getNativeConfigInfo());
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Not an OpenGL graphics config: " + gc);
|
||||
}
|
||||
|
||||
private static native long getPixelFormat(long pConfigInfo);
|
||||
private static native long getSharedContext();
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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 sun.java2d.opengl;
|
||||
|
||||
public class OGLSurfaceDataExt {
|
||||
public static boolean initWithTexture(OGLSurfaceData surfaceData, long textureId) {
|
||||
return OGLSurfaceDataExt.initWithTexture(surfaceData.getNativeOps(), textureId);
|
||||
}
|
||||
|
||||
public static void resetTextureId(OGLSurfaceData surfaceData) {
|
||||
resetTextureId(surfaceData.getNativeOps());
|
||||
}
|
||||
|
||||
private static native boolean initWithTexture(long pData, long textureId);
|
||||
private static native void resetTextureId(long pData);
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef HEADLESS
|
||||
|
||||
#include "sun_java2d_opengl_OGLSurfaceDataExt.h"
|
||||
|
||||
#include "jni_util.h"
|
||||
|
||||
#include "OGLSurfaceData.h"
|
||||
|
||||
void
|
||||
OGLSD_DisposeTextureWrapper
|
||||
(JNIEnv *env, SurfaceDataOps *ops)
|
||||
{
|
||||
OGLSDOps *oglsdo = (OGLSDOps *)ops;
|
||||
if (!oglsdo) {
|
||||
J2dTraceLn(J2D_TRACE_ERROR, "OGLSD_DisposeTextureWrapper: oglsdo is null");
|
||||
return;
|
||||
}
|
||||
|
||||
if(oglsdo->textureID) {
|
||||
oglsdo->textureID = 0;
|
||||
J2dTraceLn(J2D_TRACE_VERBOSE, "OGLSD_DisposeTextureWrapper: texture %d is reset", oglsdo->textureID);
|
||||
} else {
|
||||
J2dTraceLn(J2D_TRACE_WARNING, "OGLSD_DisposeTextureWrapper: texture ID is 0");
|
||||
}
|
||||
OGLSD_Dispose(env, ops);
|
||||
}
|
||||
|
||||
// from OGLSurfaceData.c
|
||||
extern void
|
||||
OGLSD_SetNativeDimensions
|
||||
(JNIEnv *env, OGLSDOps *oglsdo, jint width, jint height);
|
||||
|
||||
JNIEXPORT
|
||||
jboolean JNICALL
|
||||
Java_sun_java2d_opengl_OGLSurfaceDataExt_initWithTexture
|
||||
(JNIEnv *env, jclass cls, jlong pData, jlong textureId)
|
||||
{
|
||||
OGLSDOps *oglsdo = jlong_to_ptr(pData);
|
||||
|
||||
if (oglsdo == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "OGLSurfaceData_initWithTexture: ops are null");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
j2d_glBindTexture(GL_TEXTURE_2D, textureId);
|
||||
GLenum error = j2d_glGetError();
|
||||
if (error != GL_NO_ERROR) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR,
|
||||
"OGLSurfaceData_initWithTexture: could not bind texture: id=%d error=%x",
|
||||
textureId, error);
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
if (!j2d_glIsTexture(textureId)) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "OGLSurfaceData_initWithTexture: textureId is not a valid texture id");
|
||||
j2d_glBindTexture(GL_TEXTURE_2D, 0);
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
GLsizei width, height;
|
||||
j2d_glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
|
||||
j2d_glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height);
|
||||
j2d_glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
GLint texMax;
|
||||
j2d_glGetIntegerv(GL_MAX_TEXTURE_SIZE, &texMax);
|
||||
if (width >= texMax || height >= texMax || width <= 0 || height <= 0) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR,
|
||||
"OGLSurfaceData_initWithTexture: wrong texture size %d x %d",
|
||||
width, height);
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
oglsdo->xOffset = 0;
|
||||
oglsdo->yOffset = 0;
|
||||
oglsdo->width = width;
|
||||
oglsdo->height = height;
|
||||
oglsdo->textureID = textureId;
|
||||
oglsdo->textureWidth = width;
|
||||
oglsdo->textureHeight = height;
|
||||
oglsdo->isOpaque = JNI_FALSE;
|
||||
oglsdo->textureTarget = GL_TEXTURE_2D;
|
||||
|
||||
// Add a custom disposer to reset the texture id before deleting it
|
||||
oglsdo->sdOps.Dispose = OGLSD_DisposeTextureWrapper;
|
||||
|
||||
GLuint fbobjectID, depthID;
|
||||
if (!OGLSD_InitFBObject(&fbobjectID, &depthID,
|
||||
oglsdo->textureID, oglsdo->textureTarget,
|
||||
oglsdo->textureWidth, oglsdo->textureHeight))
|
||||
{
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR,
|
||||
"OGLSurfaceData_initWithTexture: could not init fbobject");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
oglsdo->drawableType = OGLSD_FBOBJECT;
|
||||
oglsdo->fbobjectID = fbobjectID;
|
||||
oglsdo->depthID = depthID;
|
||||
|
||||
OGLSD_SetNativeDimensions(env, oglsdo, width, height);
|
||||
|
||||
oglsdo->activeBuffer = GL_COLOR_ATTACHMENT0_EXT;
|
||||
|
||||
J2dTraceLn(J2D_TRACE_VERBOSE, "OGLSurfaceData_initWithTexture: wrapped texture: w=%d h=%d id=%d",
|
||||
width, height, textureId);
|
||||
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_java2d_opengl_OGLSurfaceDataExt_resetTextureId
|
||||
(JNIEnv *env, jclass cls, jlong pData)
|
||||
{
|
||||
OGLSDOps *oglsdo = jlong_to_ptr(pData);
|
||||
oglsdo->textureID = 0;
|
||||
}
|
||||
|
||||
#endif /* !HEADLESS */
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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 sun.java2d.opengl;
|
||||
|
||||
public class GLXGraphicsConfigExt {
|
||||
public static long getFBConfig(GLXGraphicsConfig config) {
|
||||
return getFBConfig(config.getNativeConfigInfo());
|
||||
}
|
||||
|
||||
public native static long getAwtDisplay();
|
||||
|
||||
public native static long getSharedContext();
|
||||
|
||||
private static native long getFBConfig(long pNativeConfigInfo);
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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 sun.java2d.opengl;
|
||||
|
||||
import sun.java2d.SurfaceData;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class GLXTextureWrapperSurfaceData extends GLXSurfaceData {
|
||||
private final Image image;
|
||||
|
||||
public GLXTextureWrapperSurfaceData(GLXGraphicsConfig gc, Image image, long textureId) {
|
||||
super(null, gc, gc.getColorModel(TRANSLUCENT), RT_TEXTURE);
|
||||
this.image = image;
|
||||
|
||||
OGLRenderQueue rq = OGLRenderQueue.getInstance();
|
||||
AtomicBoolean success = new AtomicBoolean(false);
|
||||
rq.lock();
|
||||
try {
|
||||
OGLContext.setScratchSurface(gc);
|
||||
rq.flushAndInvokeNow(() -> success.set(OGLSurfaceDataExt.initWithTexture(this, textureId)));
|
||||
} finally {
|
||||
rq.unlock();
|
||||
}
|
||||
|
||||
if (!success.get()) {
|
||||
throw new IllegalArgumentException("Failed to init the surface data");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SurfaceData getReplacement() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rectangle getBounds() {
|
||||
return getNativeBounds();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getDestination() {
|
||||
return image;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
// reset the texture id first to avoid the texture deallocation
|
||||
OGLSurfaceDataExt.resetTextureId(this);
|
||||
super.flush();
|
||||
}
|
||||
}
|
||||
@@ -435,6 +435,10 @@ GLXGC_FindBestVisual(JNIEnv *env, jint screen)
|
||||
return visualid;
|
||||
}
|
||||
|
||||
GLXContext GLXGC_GetSharedContext() {
|
||||
return sharedContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a scratch pbuffer, which can be used to make a context current
|
||||
* for extension queries, etc.
|
||||
|
||||
@@ -88,6 +88,7 @@ typedef struct _GLXCtxInfo {
|
||||
|
||||
jboolean GLXGC_IsGLXAvailable(jboolean glxRecommended);
|
||||
VisualID GLXGC_FindBestVisual(JNIEnv *env, jint screen);
|
||||
GLXContext GLXGC_GetSharedContext();
|
||||
|
||||
#endif /* HEADLESS */
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
#include <jni.h>
|
||||
|
||||
#include "jni_util.h"
|
||||
|
||||
#include "sun_java2d_opengl_GLXGraphicsConfigExt.h"
|
||||
|
||||
#include "GLXGraphicsConfig.h"
|
||||
|
||||
#ifndef HEADLESS
|
||||
#include <X11/Xlib.h>
|
||||
extern Display *awt_display;
|
||||
#endif /* !HEADLESS */
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_sun_java2d_opengl_GLXGraphicsConfigExt_getSharedContext
|
||||
(JNIEnv *env, jclass class)
|
||||
{
|
||||
#ifndef HEADLESS
|
||||
return ptr_to_jlong(GLXGC_GetSharedContext());
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL Java_sun_java2d_opengl_GLXGraphicsConfigExt_getAwtDisplay
|
||||
(JNIEnv *env, jclass class) {
|
||||
#ifndef HEADLESS
|
||||
return ptr_to_jlong(awt_display);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL Java_sun_java2d_opengl_GLXGraphicsConfigExt_getFBConfig
|
||||
(JNIEnv *env, jclass class, jlong pGlxNativeConfig)
|
||||
{
|
||||
#ifndef HEADLESS
|
||||
if (!pGlxNativeConfig) {
|
||||
J2dTraceLn(J2D_TRACE_ERROR, "GLXGraphicsConfigExt_getPixelFormat: pGlxNativeConfig is nullptr");
|
||||
}
|
||||
|
||||
GLXGraphicsConfigInfo *glxinfo = jlong_to_ptr(pGlxNativeConfig);
|
||||
return ptr_to_jlong(glxinfo->fbconfig);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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.desktop.image.TextureWrapperSurfaceManager;
|
||||
import com.jetbrains.exported.JBRApi;
|
||||
import sun.awt.image.SurfaceManager;
|
||||
import sun.java2d.SurfaceData;
|
||||
|
||||
import sun.java2d.opengl.*;
|
||||
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Image;
|
||||
|
||||
@JBRApi.Service
|
||||
@JBRApi.Provides("SharedTextures")
|
||||
public class SharedTexturesService extends SharedTextures {
|
||||
@Override
|
||||
public int getTextureType(GraphicsConfiguration gc) {
|
||||
if (gc instanceof WGLGraphicsConfig) {
|
||||
return OPENGL_TEXTURE_TYPE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long[] getOpenGLContextInfo(GraphicsConfiguration gc) {
|
||||
if (gc instanceof WGLGraphicsConfig wglGraphicsConfig) {
|
||||
return new long[] {
|
||||
WGLGraphicsConfigExt.getSharedOpenGLContext(),
|
||||
WGLGraphicsConfigExt.getSharedOpenGLPixelFormat(wglGraphicsConfig),
|
||||
};
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException("Unsupported graphics configuration: " + gc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SurfaceManager createSurfaceManager(GraphicsConfiguration gc, Image image, long texture) {
|
||||
SurfaceData sd;
|
||||
if (gc instanceof WGLGraphicsConfig wglGraphicsConfig) {
|
||||
sd = new WGLTextureWrapperSurfaceData(wglGraphicsConfig, image, texture);
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Unsupported graphics configuration: " + gc);
|
||||
}
|
||||
|
||||
return new TextureWrapperSurfaceManager(sd);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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 sun.java2d.opengl;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
public class WGLGraphicsConfigExt {
|
||||
public static native long getSharedOpenGLContext();
|
||||
public static long getSharedOpenGLPixelFormat(WGLGraphicsConfig gc) {
|
||||
return getSharedOpenGLPixelFormat(gc.getNativeConfigInfo());
|
||||
}
|
||||
|
||||
private static native long getSharedOpenGLPixelFormat(long pCongigInfo);
|
||||
}
|
||||
@@ -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 sun.java2d.opengl;
|
||||
|
||||
import sun.java2d.SurfaceData;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class WGLTextureWrapperSurfaceData extends WGLSurfaceData {
|
||||
private final Image image;
|
||||
|
||||
public WGLTextureWrapperSurfaceData(WGLGraphicsConfig gc, Image image, long textureId) {
|
||||
super(null, gc, gc.getColorModel(TRANSLUCENT), RT_TEXTURE);
|
||||
this.image = image;
|
||||
|
||||
OGLRenderQueue rq = OGLRenderQueue.getInstance();
|
||||
AtomicBoolean success = new AtomicBoolean(false);
|
||||
rq.lock();
|
||||
try {
|
||||
OGLContext.setScratchSurface(gc);
|
||||
rq.flushAndInvokeNow(() -> success.set(OGLSurfaceDataExt.initWithTexture(this, textureId)));
|
||||
} finally {
|
||||
rq.unlock();
|
||||
}
|
||||
|
||||
if (!success.get()) {
|
||||
throw new IllegalArgumentException("Failed to init the surface data");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SurfaceData getReplacement() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rectangle getBounds() {
|
||||
return getNativeBounds();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getDestination() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
// reset the texture id first to avoid the texture deallocation
|
||||
OGLSurfaceDataExt.resetTextureId(this);
|
||||
super.flush();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. 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 <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "jlong.h"
|
||||
|
||||
#include "WGLGraphicsConfig.h"
|
||||
#include "sun_java2d_opengl_WGLGraphicsConfigExt.h"
|
||||
|
||||
extern HGLRC sharedContext;
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_sun_java2d_opengl_WGLGraphicsConfigExt_getSharedOpenGLContext(JNIEnv *env,
|
||||
jclass wglcl)
|
||||
{
|
||||
return (jlong)sharedContext;
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_sun_java2d_opengl_WGLGraphicsConfigExt_getSharedOpenGLPixelFormat(JNIEnv *env,
|
||||
jclass wglcl,
|
||||
jlong pConfigInfo)
|
||||
{
|
||||
WGLGraphicsConfigInfo *wglinfo =
|
||||
(WGLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo);
|
||||
|
||||
J2dTraceLn(J2D_TRACE_VERBOSE, "OGLGraphicsConfigJbrApi_getPixelFormat");
|
||||
|
||||
if (wglinfo == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR,
|
||||
"OGLGraphicsConfigJbrApi_getPixelFormat: config info is null");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return wglinfo->pixfmt;
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import com.jetbrains.desktop.SharedTexturesService;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.VolatileImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -20,63 +21,96 @@ import java.awt.*;
|
||||
* the same content.
|
||||
* @library /test/lib
|
||||
* @compile --add-exports java.desktop/com.jetbrains.desktop=ALL-UNNAMED SharedTexturesTest.java
|
||||
* @run main/othervm/native -Dsun.java2d.uiScale=1 -Dsun.java2d.metal=True --add-exports java.desktop/com.jetbrains.desktop=ALL-UNNAMED SharedTexturesTest
|
||||
* @run main/othervm/native -Dsun.java2d.uiScale=1 -Dsun.java2d.metal=true -Dsun.java2d.opengl=false --enable-native-access=ALL-UNNAMED --add-exports java.desktop/com.jetbrains.desktop=ALL-UNNAMED SharedTexturesTest
|
||||
* @run main/othervm/native -Dsun.java2d.uiScale=1 -Dsun.java2d.metal=false -Dsun.java2d.opengl=true --enable-native-access=ALL-UNNAMED --add-exports java.desktop/com.jetbrains.desktop=ALL-UNNAMED SharedTexturesTest
|
||||
* @requires (os.family=="mac")
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @key headful
|
||||
* @summary The test creates a BufferedImage and makes a texture from its content.
|
||||
* The texture gets wrapped into a TextureWrapperImage image by SharedTextures JBR API service.
|
||||
* The TextureWrapperImage is copied into a BufferedImage and VolatileImage and expects that all images have
|
||||
* the same content.
|
||||
* @library /test/lib
|
||||
* @compile --add-exports java.desktop/com.jetbrains.desktop=ALL-UNNAMED SharedTexturesTest.java
|
||||
* @run main/othervm/native -Dsun.java2d.uiScale=1 -Dsun.java2d.opengl=true --enable-native-access=ALL-UNNAMED --add-exports java.desktop/com.jetbrains.desktop=ALL-UNNAMED SharedTexturesTest
|
||||
* @requires (os.family=="windows")
|
||||
*/
|
||||
|
||||
public class SharedTexturesTest {
|
||||
static {
|
||||
System.loadLibrary("SharedTexturesTest");
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
BufferedImage originalImage = createImage();
|
||||
byte[] bytes = getPixelData(originalImage);
|
||||
public static void main(String[] args) throws IOException, InterruptedException {
|
||||
GraphicsConfiguration gc = GraphicsEnvironment
|
||||
.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
|
||||
|
||||
SharedTextures sharedTexturesService = new SharedTexturesService();
|
||||
Asserts.assertEquals(sharedTexturesService.getTextureType(), SharedTexturesService.METAL_TEXTURE_TYPE);
|
||||
SharedTextures sharedTextures = new SharedTexturesService();
|
||||
int textureType = sharedTextures.getTextureType(gc);
|
||||
if ("true".equals(System.getProperty("sun.java2d.opengl"))) {
|
||||
Asserts.assertEquals(textureType, SharedTextures.OPENGL_TEXTURE_TYPE, "Expected OpenGL texture type");
|
||||
} else if ("true".equals(System.getProperty("sun.java2d.metal"))) {
|
||||
Asserts.assertEquals(textureType, SharedTextures.METAL_TEXTURE_TYPE, "Expected Metal texture type");
|
||||
} else {
|
||||
throw new RuntimeException("The rendering pipeline has to be specified explicitly");
|
||||
}
|
||||
|
||||
BufferedImage originalImage = createImage();
|
||||
boolean flipY = textureType == SharedTextures.OPENGL_TEXTURE_TYPE;
|
||||
byte[] bytes = getPixelData(originalImage, TexturePixelLayout.get(textureType), flipY);
|
||||
|
||||
BufferedImage bufferedImageContent;
|
||||
BufferedImage volatileImageContent;
|
||||
|
||||
if (textureType == SharedTextures.OPENGL_TEXTURE_TYPE) {
|
||||
setSharedContextInfo(sharedTextures.getOpenGLContextInfo(gc));
|
||||
}
|
||||
initNative(textureType);
|
||||
long textureId = createTexture(bytes, originalImage.getWidth(), originalImage.getHeight());
|
||||
try {
|
||||
GraphicsConfiguration gc = GraphicsEnvironment
|
||||
.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
|
||||
Image textureImage = sharedTexturesService.wrapTexture(gc, textureId);
|
||||
|
||||
// Create a BufferedImage containing a copy of textureImage
|
||||
try {
|
||||
Image textureImage = sharedTextures.wrapTexture(gc, textureId);
|
||||
|
||||
// Render the shared texture image onto a BufferedImage
|
||||
bufferedImageContent = new BufferedImage(
|
||||
textureImage.getWidth(null), textureImage.getHeight(null), BufferedImage.TYPE_INT_ARGB);
|
||||
copyImage(textureImage, bufferedImageContent);
|
||||
|
||||
// Create a VolatileImage containing a copy of textureImage and dump it to a BufferedImage
|
||||
// Render the shared texture image onto a VolatileImage and copy it to another BufferedImage
|
||||
// to check the content later
|
||||
volatileImageContent = new BufferedImage(
|
||||
textureImage.getWidth(null), textureImage.getHeight(null), BufferedImage.TYPE_INT_ARGB);
|
||||
VolatileImage volatileImage = gc.createCompatibleVolatileImage(
|
||||
VolatileImage volatileImageTarget = gc.createCompatibleVolatileImage(
|
||||
textureImage.getWidth(null), textureImage.getHeight(null), Transparency.TRANSLUCENT);
|
||||
int attempts = 10;
|
||||
do {
|
||||
copyImage(textureImage, volatileImage);
|
||||
copyImage(volatileImage, volatileImageContent);
|
||||
copyImage(textureImage, volatileImageTarget);
|
||||
copyImage(volatileImageTarget, volatileImageContent);
|
||||
attempts--;
|
||||
} while (volatileImage.contentsLost() && attempts > 0);
|
||||
} while (volatileImageTarget.contentsLost() && attempts > 0);
|
||||
Asserts.assertNotEquals(attempts, 0, "Failed to draw the VolatileImage");
|
||||
} finally {
|
||||
disposeTexture(textureId);
|
||||
releaseContext();
|
||||
}
|
||||
|
||||
try {
|
||||
Asserts.assertEquals(originalImage.getWidth(), bufferedImageContent.getWidth());
|
||||
Asserts.assertEquals(originalImage.getHeight(), bufferedImageContent.getHeight());
|
||||
Asserts.assertEquals(countImageDiff(originalImage, bufferedImageContent), 0);
|
||||
Asserts.assertEquals(originalImage.getWidth(), bufferedImageContent.getWidth(), "Unexpected BI width");
|
||||
Asserts.assertEquals(originalImage.getHeight(), bufferedImageContent.getHeight(), "Unexpected BI height");
|
||||
Asserts.assertLT(countImageDiff(originalImage, bufferedImageContent), 5, "BI validation failed");
|
||||
|
||||
Asserts.assertEquals(originalImage.getWidth(), volatileImageContent.getWidth());
|
||||
Asserts.assertEquals(originalImage.getHeight(), volatileImageContent.getHeight());
|
||||
Asserts.assertEquals(countImageDiff(originalImage, volatileImageContent), 0);
|
||||
Asserts.assertEquals(originalImage.getWidth(), volatileImageContent.getWidth(), "Unexpected VI width");
|
||||
Asserts.assertEquals(originalImage.getHeight(), volatileImageContent.getHeight(), "Unexpected VI height");
|
||||
Asserts.assertLT(countImageDiff(originalImage, volatileImageContent), 5, "BI validation failed");
|
||||
} catch (Exception e) {
|
||||
saveImage(originalImage, "original_image.png");
|
||||
saveImage(bufferedImageContent, "buffered_image.png");
|
||||
saveImage(volatileImageContent, "volatile_image.png");
|
||||
saveImage(imagesDiff(originalImage, bufferedImageContent), "buffered_image_diff.png");
|
||||
saveImage(imagesDiff(originalImage, volatileImageContent), "volatile_image_diff.png");
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@@ -106,6 +140,10 @@ public class SharedTexturesTest {
|
||||
|
||||
g.setColor(new Color(255, 0, 0, 128));
|
||||
g.fillOval(0, 0, width, height);
|
||||
|
||||
g.setColor(Color.BLUE);
|
||||
g.drawLine(0, 0, width, height - 50);
|
||||
|
||||
g.dispose();
|
||||
|
||||
return bufferedImage;
|
||||
@@ -117,19 +155,34 @@ public class SharedTexturesTest {
|
||||
ImageIO.write(image, formatName, outputFile);
|
||||
}
|
||||
|
||||
private native static long createTexture(byte[] data, int width, int height);
|
||||
private static class TexturePixelLayout {
|
||||
int r, g, b, a; // color component indexes
|
||||
private TexturePixelLayout(int r, int g, int b, int a) {this.r = r; this.g = g; this.b = b; this.a = a;}
|
||||
final static TexturePixelLayout GL_RGBA_UINT_8_8_8_8 = new TexturePixelLayout(3, 2, 1, 0);
|
||||
final static TexturePixelLayout MTL_BGRA8Unorm = new TexturePixelLayout(2, 1, 0, 3);
|
||||
|
||||
private native static void disposeTexture(long textureId);
|
||||
static TexturePixelLayout get(int textureType) {
|
||||
return switch (textureType) {
|
||||
case SharedTextures.OPENGL_TEXTURE_TYPE -> TexturePixelLayout.GL_RGBA_UINT_8_8_8_8;
|
||||
case SharedTextures.METAL_TEXTURE_TYPE -> TexturePixelLayout.MTL_BGRA8Unorm;
|
||||
default -> throw new RuntimeException("Unexpected texture type: " + textureType);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] getPixelData(BufferedImage image) {
|
||||
private static byte[] getPixelData(BufferedImage image, TexturePixelLayout pixelLayout, boolean flipY) {
|
||||
byte[] rawPixels = new byte[image.getWidth() * image.getHeight() * 4];
|
||||
int[] argbPixels = image.getRGB(0, 0, image.getWidth(), image.getHeight(), null, 0, image.getWidth());
|
||||
ColorModel cm = image.getColorModel();
|
||||
for (int i = 0; i < argbPixels.length; i++) {
|
||||
int x = i % image.getWidth();
|
||||
int y = flipY ? image.getHeight() - (i / image.getWidth()) - 1 : i / image.getWidth();
|
||||
int targetIndex = (x + y * image.getWidth()) * 4;
|
||||
int argb = argbPixels[i];
|
||||
rawPixels[i * 4] = (byte) (argb & 0xFF);
|
||||
rawPixels[i * 4 + 1] = (byte) ((argb >> 8) & 0xFF);
|
||||
rawPixels[i * 4 + 2] = (byte) ((argb >> 16) & 0xFF);
|
||||
rawPixels[i * 4 + 3] = (byte) ((argb >> 24) & 0xFF);
|
||||
rawPixels[targetIndex + pixelLayout.r] = (byte) cm.getRed(argb);
|
||||
rawPixels[targetIndex + pixelLayout.g] = (byte) cm.getGreen(argb);
|
||||
rawPixels[targetIndex + pixelLayout.b] = (byte) cm.getBlue(argb);
|
||||
rawPixels[targetIndex + pixelLayout.a] = (byte) cm.getAlpha(argb);
|
||||
}
|
||||
|
||||
return rawPixels;
|
||||
@@ -147,4 +200,29 @@ public class SharedTexturesTest {
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
private static BufferedImage imagesDiff(BufferedImage lhs, BufferedImage rhs) {
|
||||
int width = Math.min(lhs.getWidth(), rhs.getWidth());
|
||||
int height = Math.min(lhs.getHeight(), rhs.getHeight());
|
||||
BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
||||
ColorModel lhsCM = lhs.getColorModel();
|
||||
ColorModel rhsCM = rhs.getColorModel();
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
result.setRGB(x, y, lhsCM.getRGB(lhs.getRGB(x, y)) ^ rhsCM.getRGB(rhs.getRGB(x, y)));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private native static void initNative(int textureType);
|
||||
|
||||
private native static void setSharedContextInfo(long[] sharedContextInfo);
|
||||
|
||||
private native static long createTexture(byte[] data, int width, int height);
|
||||
|
||||
private native static void disposeTexture(long textureId);
|
||||
|
||||
private native static void releaseContext();
|
||||
}
|
||||
|
||||
284
test/jdk/jb/SharedTextures/libSharedTexturesTest.c
Normal file
284
test/jdk/jb/SharedTextures/libSharedTexturesTest.c
Normal file
@@ -0,0 +1,284 @@
|
||||
#ifndef LINUX // remove this line to this text compile on Linux
|
||||
|
||||
#include <jni.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <GL/gl.h>
|
||||
|
||||
#ifdef LINUX
|
||||
#include <X11/Xlib.h>
|
||||
#include <GL/glx.h>
|
||||
#include <X11/Xlib.h>
|
||||
#endif
|
||||
|
||||
static int gTextureType = -1;
|
||||
|
||||
static const int METAL_TEXTURE_TYPE = 1;
|
||||
static const int OPENGL_TEXTURE_TYPE = 2;
|
||||
|
||||
static void check_gl_error(JNIEnv *env, const char* msgPrefix) {
|
||||
GLenum err = glGetError();
|
||||
if (err != GL_NO_ERROR) {
|
||||
char msg[256];
|
||||
snprintf(msg, sizeof(msg), "%s: OpenGL error %d", msgPrefix, err);
|
||||
jclass excCls = (*env)->FindClass(env, "java/lang/RuntimeException");
|
||||
(*env)->ThrowNew(env, excCls, msg);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
static HWND gHwnd = 0;
|
||||
static HGLRC gSharedContext = 0;
|
||||
static int gPixelFormat = 0;
|
||||
|
||||
static HDC dc = 0;
|
||||
static HGLRC gGLContext = 0;
|
||||
|
||||
static int initOpenGL() {
|
||||
gHwnd = CreateWindowEx(0, "STATIC", "Hidden", WS_POPUP, 0,0,1,1, NULL, NULL, GetModuleHandle(NULL), NULL);
|
||||
if (gHwnd == 0) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
dc = GetDC(gHwnd);
|
||||
if (!dc) {
|
||||
DestroyWindow(gHwnd);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!SetPixelFormat(dc, gPixelFormat, 0)) {
|
||||
ReleaseDC(0, dc);
|
||||
DestroyWindow(gHwnd);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gGLContext = wglCreateContext(dc);
|
||||
if (!gGLContext) {
|
||||
ReleaseDC(0, dc);
|
||||
DestroyWindow(gHwnd);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!wglShareLists(gSharedContext, gGLContext)) {
|
||||
ReleaseDC(0, dc);
|
||||
DestroyWindow(gHwnd);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!wglMakeCurrent(dc, gGLContext)) {
|
||||
wglDeleteContext(gGLContext);
|
||||
gGLContext = 0;
|
||||
ReleaseDC(0, dc);
|
||||
DestroyWindow(gHwnd);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
wglMakeCurrent(0, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int makeContextCurrent(int isCurrent) {
|
||||
if (isCurrent) {
|
||||
return wglMakeCurrent(dc, gGLContext);
|
||||
}
|
||||
return wglMakeCurrent(0, 0);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_SharedTexturesTest_setSharedContextInfo
|
||||
(JNIEnv *env, jclass clazz, jlongArray sharedContextInfo) {
|
||||
jsize length = (*env)->GetArrayLength(env, sharedContextInfo);
|
||||
if (length != 2) {
|
||||
(*env)->ThrowNew(env, (*env)->FindClass(env, "java/lang/IllegalArgumentException"),
|
||||
"Unexpected shared context info size");
|
||||
}
|
||||
|
||||
jlong contextInfo[2];
|
||||
(*env)->GetLongArrayRegion(env, sharedContextInfo, 0, length, contextInfo);
|
||||
gSharedContext = (HGLRC)contextInfo[0];
|
||||
gPixelFormat = (int)contextInfo[1];
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_SharedTexturesTest_releaseContext
|
||||
(JNIEnv *env, jclass clazz) {
|
||||
if (gTextureType == OPENGL_TEXTURE_TYPE) {
|
||||
if (gGLContext) {
|
||||
wglMakeCurrent(0, 0);
|
||||
wglDeleteContext(gGLContext);
|
||||
gGLContext = 0;
|
||||
}
|
||||
|
||||
if (dc) {
|
||||
ReleaseDC(0, dc);
|
||||
DestroyWindow(gHwnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef LINUX
|
||||
|
||||
static Display *gDisplay = NULL;
|
||||
static GLXContext gSharedContext = 0;
|
||||
static GLXFBConfig gFBConfig = 0;
|
||||
|
||||
static GLXPbuffer gPbuffer = 0;
|
||||
static GLXContext gGLContext = 0;
|
||||
|
||||
static int initOpenGL() {
|
||||
int pbAttribs[] = {
|
||||
GLX_PBUFFER_WIDTH, 1000,
|
||||
GLX_PBUFFER_HEIGHT, 1000,
|
||||
None
|
||||
};
|
||||
|
||||
gPbuffer = glXCreatePbuffer(gDisplay, gFBConfig, pbAttribs);
|
||||
gGLContext = glXCreateNewContext(gDisplay, gFBConfig, GLX_RGBA_TYPE, gSharedContext, /* direct = */ GL_TRUE);
|
||||
|
||||
if (!gGLContext) {
|
||||
printf("Failed to glXCreateNewContext: %d\n", glGetError());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!glXMakeCurrent(gDisplay, gPbuffer, gGLContext)) {
|
||||
printf("Failed to glXMakeCurrent: %d\n", glGetError());
|
||||
glXDestroyContext(gDisplay, gGLContext);
|
||||
gGLContext = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
glXMakeCurrent(gDisplay, None, NULL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int makeContextCurrent(int isCurrent) {
|
||||
if (isCurrent) {
|
||||
return glXMakeCurrent(gDisplay, gPbuffer, gGLContext);
|
||||
}
|
||||
return glXMakeCurrent(gDisplay, None, NULL);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_SharedTexturesTest_setSharedContextInfo
|
||||
(JNIEnv *env, jclass clazz, jlongArray sharedContextInfo) {
|
||||
jsize length = (*env)->GetArrayLength(env, sharedContextInfo);
|
||||
if (length != 3) {
|
||||
(*env)->ThrowNew(env, (*env)->FindClass(env, "java/lang/IllegalArgumentException"),
|
||||
"Unexpected shared context info size");
|
||||
}
|
||||
|
||||
jlong contextInfo[3];
|
||||
(*env)->GetLongArrayRegion(env, sharedContextInfo, 0, length, contextInfo);
|
||||
|
||||
gSharedContext = (GLXContext)contextInfo[0];
|
||||
gDisplay = (Display*)contextInfo[1];
|
||||
gFBConfig = (GLXFBConfig)contextInfo[2];
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_SharedTexturesTest_releaseContext
|
||||
(JNIEnv *env, jclass clazz) {
|
||||
if (gTextureType == OPENGL_TEXTURE_TYPE) {
|
||||
if (gGLContext) {
|
||||
glXMakeCurrent(gDisplay, None, NULL);
|
||||
glXDestroyContext(gDisplay, gGLContext);
|
||||
gGLContext = 0;
|
||||
}
|
||||
|
||||
if (gPbuffer) {
|
||||
glXDestroyPbuffer(gDisplay, gPbuffer);
|
||||
gPbuffer = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
JNIEXPORT void JNICALL Java_SharedTexturesTest_initNative
|
||||
(JNIEnv *env, jclass clazz, jint textureType) {
|
||||
if (textureType != OPENGL_TEXTURE_TYPE) {
|
||||
(*env)->ThrowNew(env, (*env)->FindClass(env, "java/lang/RuntimeException"),
|
||||
"Unsupported texture type");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!initOpenGL()) {
|
||||
(*env)->ThrowNew(env, (*env)->FindClass(env, "java/lang/RuntimeException"),
|
||||
"Failed to init OpenGL");
|
||||
return;
|
||||
}
|
||||
|
||||
gTextureType = textureType;
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL Java_SharedTexturesTest_createTexture
|
||||
(JNIEnv *env, jclass clazz, jbyteArray byteArray, jint width, jint height) {
|
||||
if (!makeContextCurrent(1)) {
|
||||
(*env)->ThrowNew(env, (*env)->FindClass(env, "java/lang/RuntimeException"),
|
||||
"SharedTexturesTest: can't make the context current");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (gTextureType == -1) {
|
||||
(*env)->ThrowNew(env, (*env)->FindClass(env, "java/lang/RuntimeException"),
|
||||
"SharedTexturesTest: native is not initialized");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (gTextureType != OPENGL_TEXTURE_TYPE) {
|
||||
(*env)->ThrowNew(env, (*env)->FindClass(env, "java/lang/RuntimeException"),
|
||||
"Unsupported texture type");
|
||||
return 0;
|
||||
}
|
||||
|
||||
jsize length = (*env)->GetArrayLength(env, byteArray);
|
||||
jbyte *pixels = (*env)->GetByteArrayElements(env, byteArray, NULL);
|
||||
|
||||
GLuint texId = 0;
|
||||
glGenTextures(1, &texId);
|
||||
check_gl_error(env, "glGenTextures");
|
||||
glBindTexture(GL_TEXTURE_2D, texId);
|
||||
check_gl_error(env, "glBindTexture");
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
check_gl_error(env, "glTexParameteri GL_TEXTURE_MAG_FILTER");
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
check_gl_error(env, "glTexParameteri GL_TEXTURE_MIN_FILTER");
|
||||
|
||||
#ifndef GL_CLAMP_TO_EDGE
|
||||
#define GL_CLAMP_TO_EDGE 0x812F
|
||||
#endif
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
#ifndef GL_UNSIGNED_INT_8_8_8_8
|
||||
#define GL_UNSIGNED_INT_8_8_8_8 0x8035
|
||||
#endif
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
|
||||
GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, (const void*)pixels);
|
||||
check_gl_error(env, "glTexImage2D");
|
||||
|
||||
(*env)->ReleaseByteArrayElements(env, byteArray, pixels, JNI_ABORT);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glFinish();
|
||||
check_gl_error(env, "glFinish");
|
||||
|
||||
makeContextCurrent(0);
|
||||
|
||||
return (jlong)texId;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_SharedTexturesTest_disposeTexture
|
||||
(JNIEnv *env, jclass clazz, jlong texture) {
|
||||
if (gTextureType == OPENGL_TEXTURE_TYPE) {
|
||||
GLuint texId = (GLuint)texture;
|
||||
glDeleteTextures(1, &texId);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // remove this line to this text compile on Linux
|
||||
@@ -1,7 +1,50 @@
|
||||
#define GL_SILENCE_DEPRECATION
|
||||
|
||||
#import <jni.h>
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import <Metal/Metal.h>
|
||||
|
||||
#include <jni.h>
|
||||
#import <OpenGL/CGLCurrent.h>
|
||||
#import <OpenGL/CGLTypes.h>
|
||||
#import <OpenGL/OpenGL.h>
|
||||
#import <OpenGL/gl3.h>
|
||||
|
||||
static int METAL_TEXTURE_TYPE = 1;
|
||||
static int OPENGL_TEXTURE_TYPE = 2;
|
||||
|
||||
static int gTextureType = -1;
|
||||
|
||||
static CGLContextObj gOpenGLContext = 0;
|
||||
|
||||
static CGLContextObj gSharedContext = 0;
|
||||
static CGLPixelFormatObj gPixelFormat = 0;
|
||||
|
||||
static void throw(JNIEnv *env, const char* msg) {
|
||||
(*env)->ThrowNew(env, (*env)->FindClass(env, "java/lang/RuntimeException"), msg);
|
||||
}
|
||||
|
||||
static const char* gl_error_string(GLenum err) {
|
||||
switch (err) {
|
||||
case GL_NO_ERROR: return "GL_NO_ERROR";
|
||||
case GL_INVALID_ENUM: return "GL_INVALID_ENUM";
|
||||
case GL_INVALID_VALUE: return "GL_INVALID_VALUE";
|
||||
case GL_INVALID_OPERATION: return "GL_INVALID_OPERATION";
|
||||
case GL_OUT_OF_MEMORY: return "GL_OUT_OF_MEMORY";
|
||||
|
||||
default: return "Unknown GL error";
|
||||
}
|
||||
}
|
||||
|
||||
static void check_gl_error(JNIEnv *env, const char* msgPrefix) {
|
||||
GLenum err = glGetError();
|
||||
if (err != GL_NO_ERROR) {
|
||||
char msg[256];
|
||||
snprintf(msg, sizeof(msg), "%s: OpenGL error %d (%s)", msgPrefix, err, gl_error_string(err));
|
||||
throw(env, msg);
|
||||
}
|
||||
}
|
||||
|
||||
static id <MTLTexture>
|
||||
createMTLTextureFromNSData(id <MTLDevice> device, NSData *textureData, NSUInteger width, NSUInteger height) {
|
||||
@@ -31,8 +74,7 @@ createMTLTextureFromNSData(id <MTLDevice> device, NSData *textureData, NSUIntege
|
||||
return texture;
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL Java_SharedTexturesTest_createTexture
|
||||
(JNIEnv *env, jclass clazz, jbyteArray byteArray, jint width, jint height) {
|
||||
static jlong createTextureMTL(JNIEnv *env, jbyteArray byteArray, jint width, jint height) {
|
||||
@autoreleasepool {
|
||||
id <MTLDevice> device = MTLCreateSystemDefaultDevice();
|
||||
if (!device) {
|
||||
@@ -50,10 +92,107 @@ JNIEXPORT jlong JNICALL Java_SharedTexturesTest_createTexture
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_SharedTexturesTest_disposeTexture
|
||||
(JNIEnv *env, jclass clazz, jlong pTexture) {
|
||||
id <MTLTexture> texture = (__bridge id <MTLTexture>) (void *) pTexture;
|
||||
if (texture != nil) {
|
||||
[texture release];
|
||||
static jlong createTextureOpenGL(JNIEnv *env, jbyteArray byteArray, jint width, jint height) {
|
||||
CGLSetCurrentContext(gSharedContext);
|
||||
|
||||
jbyte *pixels = (*env)->GetByteArrayElements(env, byteArray, NULL);
|
||||
|
||||
GLuint texId = 0;
|
||||
glGenTextures(1, &texId);
|
||||
check_gl_error(env, "glGenTextures");
|
||||
glBindTexture(GL_TEXTURE_2D, texId);
|
||||
check_gl_error(env, "glBindTexture");
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
check_gl_error(env, "glTexParameteri GL_TEXTURE_MAG_FILTER");
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
check_gl_error(env, "glTexParameteri GL_TEXTURE_MIN_FILTER");
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
check_gl_error(env, "glTexParameteri GL_TEXTURE_WRAP_S GL_CLAMP_TO_EDGE");
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
check_gl_error(env, "glTexParameteri GL_TEXTURE_WRAP_T GL_CLAMP_TO_EDGE");
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
|
||||
GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, (const void*)pixels);
|
||||
check_gl_error(env, "glTexImage2D");
|
||||
|
||||
(*env)->ReleaseByteArrayElements(env, byteArray, pixels, JNI_ABORT);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
glFinish();
|
||||
check_gl_error(env, "glFinish");
|
||||
|
||||
CGLSetCurrentContext(0);
|
||||
|
||||
return texId;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_SharedTexturesTest_setSharedContextInfo
|
||||
(JNIEnv *env, jclass clazz, jlongArray sharedContextInfo) {
|
||||
jsize length = (*env)->GetArrayLength(env, sharedContextInfo);
|
||||
if (length != 2) {
|
||||
(*env)->ThrowNew(env, (*env)->FindClass(env, "java/lang/IllegalArgumentException"),
|
||||
"Unexpected shared context info size");
|
||||
}
|
||||
|
||||
jlong contextInfo[2];
|
||||
(*env)->GetLongArrayRegion(env, sharedContextInfo, 0, length, contextInfo);
|
||||
gSharedContext = (CGLContextObj)contextInfo[0];
|
||||
gPixelFormat = (CGLPixelFormatObj)contextInfo[1];
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_SharedTexturesTest_initNative
|
||||
(JNIEnv *env, jclass clazz, jint textureType) {
|
||||
gTextureType = textureType;
|
||||
if (textureType == METAL_TEXTURE_TYPE) {
|
||||
// nothing
|
||||
} else if (textureType == OPENGL_TEXTURE_TYPE) {
|
||||
CGLError error = CGLCreateContext(gPixelFormat, gSharedContext, &gOpenGLContext);
|
||||
if (error != kCGLNoError || !gOpenGLContext) {
|
||||
throw(env, "Failed to init OpenGL context");
|
||||
}
|
||||
} else {
|
||||
throw(env, "Unknown texture type");
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL Java_SharedTexturesTest_createTexture
|
||||
(JNIEnv *env, jclass clazz, jbyteArray byteArray, jint width, jint height) {
|
||||
if (gTextureType == METAL_TEXTURE_TYPE) {
|
||||
return createTextureMTL(env, byteArray, width, height);
|
||||
} else if (gTextureType == OPENGL_TEXTURE_TYPE) {
|
||||
return createTextureOpenGL(env, byteArray, width, height);
|
||||
}
|
||||
|
||||
throw(env, "Unknown texture type");
|
||||
return 0;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_SharedTexturesTest_disposeTexture
|
||||
(JNIEnv *env, jclass clazz, jlong texture) {
|
||||
if (gTextureType == METAL_TEXTURE_TYPE) {
|
||||
id <MTLTexture> mtlTexture = (__bridge id <MTLTexture>) (void *) texture;
|
||||
if (mtlTexture != nil) {
|
||||
[mtlTexture release];
|
||||
}
|
||||
} else if (gTextureType == OPENGL_TEXTURE_TYPE) {
|
||||
GLuint texId = (GLuint)texture;
|
||||
glDeleteTextures(1, &texId);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_SharedTexturesTest_releaseContext
|
||||
(JNIEnv *env, jclass clazz) {
|
||||
if (gTextureType == OPENGL_TEXTURE_TYPE) {
|
||||
if (gOpenGLContext != 0) {
|
||||
CGLSetCurrentContext(0);
|
||||
CGLDestroyContext(gOpenGLContext);
|
||||
gOpenGLContext = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user