mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-25 10:49:41 +01:00
Compare commits
40 Commits
metal-prot
...
metal_text
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d7040fc9af | ||
|
|
97428befdc | ||
|
|
3c97fc0994 | ||
|
|
ba5352cd1d | ||
|
|
7c5303d165 | ||
|
|
737282af47 | ||
|
|
c645e6d516 | ||
|
|
5e62f37e30 | ||
|
|
a22b6c76e0 | ||
|
|
e3b69a412c | ||
|
|
cc5e746558 | ||
|
|
d5b78ddeb8 | ||
|
|
66cc7dbe8c | ||
|
|
e68ed092ea | ||
|
|
b3aafa946a | ||
|
|
89f9020408 | ||
|
|
600c2302bd | ||
|
|
bf1b49569c | ||
|
|
2c5aa85c84 | ||
|
|
d5bdb9ee89 | ||
|
|
3203bbb4aa | ||
|
|
80c9f7c103 | ||
|
|
e5fe46f243 | ||
|
|
7c8923fdfb | ||
|
|
b9bc959ab1 | ||
|
|
c25756ad98 | ||
|
|
d05b9a0f35 | ||
|
|
5cb66def9d | ||
|
|
9eaaca1598 | ||
|
|
2dccfc2fc6 | ||
|
|
d4c16e4cc8 | ||
|
|
ac8cd67dd9 | ||
|
|
28f2429359 | ||
|
|
f578a41e61 | ||
|
|
ee55ef1524 | ||
|
|
9055bb22c5 | ||
|
|
e306de9239 | ||
|
|
4d5b05c180 | ||
|
|
142faacf67 | ||
|
|
93d1ca5a56 |
2966
jb/project/hotspot-cmake/CMakeLists.txt
Normal file
2966
jb/project/hotspot-cmake/CMakeLists.txt
Normal file
File diff suppressed because it is too large
Load Diff
30
jb/project/java-common.cmake
Normal file
30
jb/project/java-common.cmake
Normal file
@@ -0,0 +1,30 @@
|
||||
# common for all OS
|
||||
set(CMAKE_CXX_STANDARD 98)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_GNU_SOURCE -D_REENTRANT -DVM_LITTLE_ENDIAN -D_LP64 -DTARGET_ARCH_x86 ")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DINCLUDE_SUFFIX_CPU=_x86 -DAMD64 -DHOTSPOT_LIB_ARCH='amd64' -DCOMPILER1 -DCOMPILER2")
|
||||
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin" OR ${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DTARGET_COMPILER_gcc")
|
||||
endif ()
|
||||
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DLINUX -DTARGET_OS_FAMILY_linux -DTARGET_COMPILER_gcc -D_GNU_SOURCE")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DLINUX -DTARGET_OS_FAMILY_linux -DTARGET_COMPILER_gcc -D_GNU_SOURCE")
|
||||
endif ()
|
||||
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_ALLBSD_SOURCE -DTARGET_OS_FAMILY_bsd")
|
||||
endif ()
|
||||
|
||||
if ("${CMAKE_SYSTEM_NAME}" MATCHES "CYGWIN") #not shure about TARGET_COMPILER
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DTARGET_COMPILER_visCPP -DWIN64 -D_WINDOWS -DTARGET_OS_FAMILY_windows")
|
||||
endif ()
|
||||
|
||||
add_custom_target(configure
|
||||
COMMAND bash configure
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/../../../)
|
||||
|
||||
add_custom_target(build_images
|
||||
COMMAND make COMPILER_WARNINGS_FATAL=false images
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/../../../
|
||||
DEPENDS ${SOURCE_FILES})
|
||||
129
jb/project/java-gradle/build.gradle
Normal file
129
jb/project/java-gradle/build.gradle
Normal file
@@ -0,0 +1,129 @@
|
||||
apply plugin: 'java'
|
||||
import org.gradle.internal.os.OperatingSystem
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
def test_jvm = {
|
||||
if (project.hasProperty('jbsdkhome')) {
|
||||
file(jbsdkhome + (OperatingSystem.current().isWindows()?"/bin/java.exe" : "/bin/java")).absolutePath
|
||||
} else {
|
||||
if (OperatingSystem.current().isMacOsX()) {
|
||||
file('../../../build/macosx-x86_64-server-release/images/jdk-bundle/jdk-13.jdk/Contents/Home/bin/java').absolutePath
|
||||
} else if (OperatingSystem.current().isLinux()) {
|
||||
file('../../../build/linux-x86_64-server-release/images/jdk/bin/java').absolutePath
|
||||
} else {
|
||||
file('../../../build/windows-x86_64-server-release/images/j2sdk-image/bin/java.exe').absolutePath
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testCompile('junit:junit:4.12'){
|
||||
exclude group: 'org.hamcrest'
|
||||
}
|
||||
testCompile 'org.hamcrest:hamcrest-library:1.3'
|
||||
testCompile 'net.java.dev.jna:jna:4.4.0'
|
||||
testCompile 'com.twelvemonkeys.imageio:imageio-tiff:3.3.2'
|
||||
testCompile 'org.apache.commons:commons-lang3:3.0'
|
||||
}
|
||||
|
||||
def jdk_modules = ["java.base", "java.logging", "java.prefs",
|
||||
"java.se.ee", "java.sql", "java.datatransfer",
|
||||
"java.management", "java.rmi", "java.security.jgss",
|
||||
"java.sql.rowset", "java.desktop", "java.management.rmi",
|
||||
"java.scripting", "java.security.sasl", "java.transaction",
|
||||
"java.instrument", "java.naming", "java.se",
|
||||
"java.smartcardio", "java.xml.crypto"]
|
||||
|
||||
def jdk_class_dirs = []
|
||||
|
||||
jdk_modules.collect(jdk_class_dirs) {
|
||||
new File("../../../src/" + it + "/share/classes")
|
||||
}
|
||||
|
||||
if (OperatingSystem.current().isMacOsX())
|
||||
jdk_modules.collect(jdk_class_dirs) {
|
||||
"../../../src/" + it + "/macosx/classes"
|
||||
}
|
||||
else if (OperatingSystem.current().isLinux()) {
|
||||
jdk_modules.collect(jdk_class_dirs) {
|
||||
"../../../src/" + it + "/solaris/classes"
|
||||
}
|
||||
jdk_modules.collect(jdk_class_dirs) {
|
||||
"../../../src/" + it + "/unix/classes"
|
||||
}
|
||||
} else
|
||||
jdk_modules.collect(jdk_class_dirs) {
|
||||
"../../../src/" + it + "/windows/classes"
|
||||
}
|
||||
|
||||
sourceSets.main.java.srcDirs = jdk_class_dirs
|
||||
|
||||
sourceSets {
|
||||
test {
|
||||
java {
|
||||
srcDir "../../../test/jdk/jbu"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test.dependsOn.clear()
|
||||
|
||||
test.dependsOn tasks.compileTestJava
|
||||
|
||||
test {
|
||||
systemProperty "jb.java2d.metal", "true"
|
||||
systemProperty "testdata", file('../../../test/jdk/jbu/testdata').absolutePath
|
||||
|
||||
// Generate golden images for DroidFontTest and MixedTextTest
|
||||
// systemProperty "gentestdata", ""
|
||||
|
||||
// Enable Java2D logging (https://confluence.jetbrains.com/display/JRE/Java2D+Rendering+Logging)
|
||||
// systemProperty "sun.java2d.trace", "log"
|
||||
// systemProperty "sun.java2d.trace", "log,pimpl"
|
||||
|
||||
outputs.upToDateWhen { false }
|
||||
executable = test_jvm()
|
||||
|
||||
// Enable async/dtrace profiler
|
||||
jvmArgs "-XX:+PreserveFramePointer"
|
||||
// Enable native J2D logging (only in debug build)
|
||||
// Can be turned on for J2D by adding "#define DEBUG 1" into jdk/src/share/native/sun/java2d/Trace.h
|
||||
|
||||
// environment 'J2D_TRACE_LEVEL', '4'
|
||||
}
|
||||
|
||||
def buildDir = project.buildscript.sourceFile.parentFile.parentFile.parentFile.parentFile
|
||||
|
||||
def make_cmd = "make"
|
||||
if (OperatingSystem.current().isWindows()) {
|
||||
def cyg_make_cmd = new File("c:/cygwin64/bin/make.exe")
|
||||
if (cyg_make_cmd.exists()) make_cmd = cyg_make_cmd.absolutePath
|
||||
}
|
||||
def test_run = false
|
||||
task make_images << {
|
||||
if (!test_run) {
|
||||
def pb = new ProcessBuilder().command(make_cmd.toString(), "-C", buildDir.absolutePath, "images")
|
||||
def proc = pb.redirectErrorStream(true).start()
|
||||
proc.inputStream.eachLine { println it }
|
||||
assert proc.waitFor() == 0
|
||||
}
|
||||
}
|
||||
|
||||
task make_clean << {
|
||||
def pb = new ProcessBuilder().command(make_cmd.toString(), "-C", buildDir.absolutePath, "clean")
|
||||
def proc = pb.redirectErrorStream(true).start()
|
||||
proc.inputStream.eachLine {println it}
|
||||
assert proc.waitFor() == 0
|
||||
}
|
||||
|
||||
task run_test << {
|
||||
test_run = true
|
||||
}
|
||||
|
||||
tasks.cleanTest.dependsOn tasks.run_test
|
||||
classes.dependsOn.clear()
|
||||
classes.dependsOn tasks.make_images
|
||||
tasks.cleanClasses.dependsOn tasks.make_clean
|
||||
1490
jb/project/jdk-cmake/CMakeLists.txt
Normal file
1490
jb/project/jdk-cmake/CMakeLists.txt
Normal file
File diff suppressed because it is too large
Load Diff
@@ -246,6 +246,8 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBAWT, \
|
||||
LIBS_macosx := -lmlib_image \
|
||||
-framework Cocoa \
|
||||
-framework OpenGL \
|
||||
-framework Metal \
|
||||
-framework MetalKit \
|
||||
-framework JavaNativeFoundation \
|
||||
-framework JavaRuntimeSupport \
|
||||
-framework ApplicationServices \
|
||||
@@ -823,6 +825,8 @@ ifeq ($(ENABLE_HEADLESS_ONLY), false)
|
||||
-framework ApplicationServices \
|
||||
-framework Foundation \
|
||||
-framework Cocoa \
|
||||
-framework Metal \
|
||||
-framework MetalKit \
|
||||
-framework JavaNativeFoundation
|
||||
else ifeq ($(call isTargetOs, windows), true)
|
||||
LIBSPLASHSCREEN_LIBS += kernel32.lib user32.lib gdi32.lib delayimp.lib $(WIN_JAVA_LIB) jvm.lib
|
||||
@@ -885,6 +889,7 @@ ifeq ($(call isTargetOs, macosx), true)
|
||||
libawt_lwawt/awt \
|
||||
libawt_lwawt/font \
|
||||
libawt_lwawt/java2d/opengl \
|
||||
libawt_lwawt/java2d/metal \
|
||||
include \
|
||||
common/awt/debug \
|
||||
common/java2d/opengl \
|
||||
@@ -920,6 +925,8 @@ ifeq ($(call isTargetOs, macosx), true)
|
||||
-framework AudioToolbox \
|
||||
-framework Carbon \
|
||||
-framework Cocoa \
|
||||
-framework Metal \
|
||||
-framework MetalKit \
|
||||
-framework Security \
|
||||
-framework ExceptionHandling \
|
||||
-framework JavaNativeFoundation \
|
||||
@@ -943,6 +950,11 @@ endif
|
||||
################################################################################
|
||||
|
||||
ifeq ($(call isTargetOs, macosx), true)
|
||||
XCODE_PATH := $(shell /usr/bin/xcode-select -p)
|
||||
CompileMetalShaders :
|
||||
$(XCODE_PATH)/Platforms/MacOSX.platform/usr/bin/metal -O2 -std=osx-metal1.1 -o $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libosxui/shaders.air $(TOPDIR)/src/java.desktop/macosx/native/libawt_lwawt/awt/shaders.metal
|
||||
$(XCODE_PATH)/Platforms/MacOSX.platform/usr/bin/metal-ar r $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libosxui/shaders.metal-ar $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libosxui/shaders.air
|
||||
$(XCODE_PATH)/Platforms/MacOSX.platform/usr/bin/metallib -o $(INSTALL_LIBRARIES_HERE)/shaders.metallib $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libosxui/shaders.metal-ar
|
||||
|
||||
$(eval $(call SetupJdkLibrary, BUILD_LIBOSXUI, \
|
||||
NAME := osxui, \
|
||||
@@ -958,6 +970,9 @@ ifeq ($(call isTargetOs, macosx), true)
|
||||
-L$(INSTALL_LIBRARIES_HERE), \
|
||||
LIBS := -lawt -losxapp -lawt_lwawt \
|
||||
-framework Cocoa \
|
||||
-framework Metal \
|
||||
-framework MetalKit \
|
||||
-framework OpenGL \
|
||||
-framework Carbon \
|
||||
-framework ApplicationServices \
|
||||
-framework JavaNativeFoundation \
|
||||
@@ -966,6 +981,7 @@ ifeq ($(call isTargetOs, macosx), true)
|
||||
))
|
||||
|
||||
TARGETS += $(BUILD_LIBOSXUI)
|
||||
$(BUILD_LIBOSXUI): CompileMetalShaders
|
||||
|
||||
$(BUILD_LIBOSXUI): $(BUILD_LIBAWT)
|
||||
|
||||
|
||||
@@ -1162,6 +1162,7 @@ sun.java2d.d3d
|
||||
sun.java2d.jules
|
||||
sun.java2d.loops
|
||||
sun.java2d.opengl
|
||||
sun.java2d.metal
|
||||
sun.java2d.pipe
|
||||
sun.java2d.pipe.hw
|
||||
sun.java2d.pisces
|
||||
|
||||
@@ -34,6 +34,7 @@ import java.awt.image.ColorModel;
|
||||
import sun.java2d.SurfaceData;
|
||||
import sun.java2d.opengl.CGLLayer;
|
||||
import sun.lwawt.LWGraphicsConfig;
|
||||
import sun.lwawt.macosx.CFRetainedResource;
|
||||
import sun.lwawt.macosx.CPlatformView;
|
||||
|
||||
public abstract class CGraphicsConfig extends GraphicsConfiguration
|
||||
@@ -87,7 +88,7 @@ public abstract class CGraphicsConfig extends GraphicsConfiguration
|
||||
* Creates a new SurfaceData that will be associated with the given
|
||||
* CGLLayer.
|
||||
*/
|
||||
public abstract SurfaceData createSurfaceData(CGLLayer layer);
|
||||
public abstract SurfaceData createSurfaceData(CFRetainedResource layer);
|
||||
|
||||
@Override
|
||||
public final boolean isTranslucencyCapable() {
|
||||
|
||||
@@ -36,6 +36,8 @@ import java.awt.geom.Rectangle2D;
|
||||
import java.util.Objects;
|
||||
|
||||
import sun.java2d.SunGraphicsEnvironment;
|
||||
import sun.java2d.macos.MacOSFlags;
|
||||
import sun.java2d.metal.MTLGraphicsConfig;
|
||||
import sun.java2d.opengl.CGLGraphicsConfig;
|
||||
|
||||
public final class CGraphicsDevice extends GraphicsDevice
|
||||
@@ -60,7 +62,9 @@ public final class CGraphicsDevice extends GraphicsDevice
|
||||
|
||||
public CGraphicsDevice(final int displayID) {
|
||||
this.displayID = displayID;
|
||||
config = CGLGraphicsConfig.getConfig(this, displayID, 0);
|
||||
config = MacOSFlags.isMetalEnabled() ?
|
||||
MTLGraphicsConfig.getConfig(this, displayID, 0) :
|
||||
CGLGraphicsConfig.getConfig(this, displayID, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,6 +27,8 @@ package sun.java2d;
|
||||
|
||||
import sun.awt.image.SunVolatileImage;
|
||||
import sun.awt.image.VolatileSurfaceManager;
|
||||
import sun.java2d.macos.MacOSFlags;
|
||||
import sun.java2d.metal.MTLVolatileSurfaceManager;
|
||||
import sun.java2d.opengl.CGLVolatileSurfaceManager;
|
||||
|
||||
/**
|
||||
@@ -49,6 +51,7 @@ public class MacosxSurfaceManagerFactory extends SurfaceManagerFactory {
|
||||
public VolatileSurfaceManager createVolatileManager(SunVolatileImage vImg,
|
||||
Object context)
|
||||
{
|
||||
return new CGLVolatileSurfaceManager(vImg, context);
|
||||
return MacOSFlags.isMetalEnabled() ? new MTLVolatileSurfaceManager(vImg, context) :
|
||||
new CGLVolatileSurfaceManager(vImg, context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
package sun.java2d.macos;
|
||||
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
public class MacOSFlags {
|
||||
|
||||
/**
|
||||
* Description of command-line flags. All flags with [true|false]
|
||||
* values
|
||||
* metalEnabled: usage: "-Djb.java2d.metal=[true|false]"
|
||||
*/
|
||||
|
||||
private static boolean metalEnabled;
|
||||
|
||||
static {
|
||||
initJavaFlags();
|
||||
initNativeFlags();
|
||||
}
|
||||
|
||||
private static native boolean initNativeFlags();
|
||||
|
||||
private static boolean getBooleanProp(String p, boolean defaultVal) {
|
||||
String propString = System.getProperty(p);
|
||||
boolean returnVal = defaultVal;
|
||||
if (propString != null) {
|
||||
if (propString.equals("true") ||
|
||||
propString.equals("t") ||
|
||||
propString.equals("True") ||
|
||||
propString.equals("T") ||
|
||||
propString.equals("")) // having the prop name alone
|
||||
{ // is equivalent to true
|
||||
returnVal = true;
|
||||
} else if (propString.equals("false") ||
|
||||
propString.equals("f") ||
|
||||
propString.equals("False") ||
|
||||
propString.equals("F"))
|
||||
{
|
||||
returnVal = false;
|
||||
}
|
||||
}
|
||||
return returnVal;
|
||||
}
|
||||
|
||||
|
||||
private static boolean getPropertySet(String p) {
|
||||
String propString = System.getProperty(p);
|
||||
return (propString != null) ? true : false;
|
||||
}
|
||||
|
||||
private static void initJavaFlags() {
|
||||
java.security.AccessController.doPrivileged(
|
||||
(PrivilegedAction<Object>) () -> {
|
||||
metalEnabled = getBooleanProp("jb.java2d.metal", false);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
public static boolean isMetalEnabled() {
|
||||
return metalEnabled;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,945 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
package sun.java2d.metal;
|
||||
|
||||
import sun.java2d.SurfaceData;
|
||||
import sun.java2d.loops.*;
|
||||
import sun.java2d.pipe.Region;
|
||||
import sun.java2d.pipe.RenderBuffer;
|
||||
import sun.java2d.pipe.RenderQueue;
|
||||
import sun.java2d.pipe.hw.AccelSurface;
|
||||
|
||||
import java.awt.*;
|
||||
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 MTLBlitLoops {
|
||||
|
||||
static void register() {
|
||||
Blit blitIntArgbPreToSurface =
|
||||
new MTLSwToSurfaceBlit(SurfaceType.IntArgbPre,
|
||||
MTLSurfaceData.PF_INT_ARGB_PRE);
|
||||
Blit blitIntArgbPreToTexture =
|
||||
new MTLSwToTextureBlit(SurfaceType.IntArgbPre,
|
||||
MTLSurfaceData.PF_INT_ARGB_PRE);
|
||||
TransformBlit transformBlitIntArgbPreToSurface =
|
||||
new MTLSwToSurfaceTransform(SurfaceType.IntArgbPre,
|
||||
MTLSurfaceData.PF_INT_ARGB_PRE);
|
||||
MTLSurfaceToSwBlit blitSurfaceToIntArgbPre =
|
||||
new MTLSurfaceToSwBlit(SurfaceType.IntArgbPre,
|
||||
MTLSurfaceData.PF_INT_ARGB_PRE);
|
||||
|
||||
GraphicsPrimitive[] primitives = {
|
||||
// surface->surface ops
|
||||
new MTLSurfaceToSurfaceBlit(),
|
||||
new MTLSurfaceToSurfaceScale(),
|
||||
new MTLSurfaceToSurfaceTransform(),
|
||||
|
||||
// render-to-texture surface->surface ops
|
||||
new MTLRTTSurfaceToSurfaceBlit(),
|
||||
new MTLRTTSurfaceToSurfaceScale(),
|
||||
new MTLRTTSurfaceToSurfaceTransform(),
|
||||
|
||||
// surface->sw ops
|
||||
new MTLSurfaceToSwBlit(SurfaceType.IntArgb,
|
||||
MTLSurfaceData.PF_INT_ARGB),
|
||||
blitSurfaceToIntArgbPre,
|
||||
|
||||
// sw->surface ops
|
||||
blitIntArgbPreToSurface,
|
||||
new MTLSwToSurfaceBlit(SurfaceType.IntRgb,
|
||||
MTLSurfaceData.PF_INT_RGB),
|
||||
new MTLSwToSurfaceBlit(SurfaceType.IntRgbx,
|
||||
MTLSurfaceData.PF_INT_RGBX),
|
||||
new MTLSwToSurfaceBlit(SurfaceType.IntBgr,
|
||||
MTLSurfaceData.PF_INT_BGR),
|
||||
new MTLSwToSurfaceBlit(SurfaceType.IntBgrx,
|
||||
MTLSurfaceData.PF_INT_BGRX),
|
||||
new MTLSwToSurfaceBlit(SurfaceType.ThreeByteBgr,
|
||||
MTLSurfaceData.PF_3BYTE_BGR),
|
||||
new MTLSwToSurfaceBlit(SurfaceType.Ushort565Rgb,
|
||||
MTLSurfaceData.PF_USHORT_565_RGB),
|
||||
new MTLSwToSurfaceBlit(SurfaceType.Ushort555Rgb,
|
||||
MTLSurfaceData.PF_USHORT_555_RGB),
|
||||
new MTLSwToSurfaceBlit(SurfaceType.Ushort555Rgbx,
|
||||
MTLSurfaceData.PF_USHORT_555_RGBX),
|
||||
new MTLSwToSurfaceBlit(SurfaceType.ByteGray,
|
||||
MTLSurfaceData.PF_BYTE_GRAY),
|
||||
new MTLSwToSurfaceBlit(SurfaceType.UshortGray,
|
||||
MTLSurfaceData.PF_USHORT_GRAY),
|
||||
new MTLGeneralBlit(MTLSurfaceData.MTLSurface,
|
||||
CompositeType.AnyAlpha,
|
||||
blitIntArgbPreToSurface),
|
||||
|
||||
new MTLAnyCompositeBlit(MTLSurfaceData.MTLSurface,
|
||||
blitSurfaceToIntArgbPre,
|
||||
blitSurfaceToIntArgbPre,
|
||||
blitIntArgbPreToSurface),
|
||||
new MTLAnyCompositeBlit(SurfaceType.Any,
|
||||
null,
|
||||
blitSurfaceToIntArgbPre,
|
||||
blitIntArgbPreToSurface),
|
||||
|
||||
new MTLSwToSurfaceScale(SurfaceType.IntRgb,
|
||||
MTLSurfaceData.PF_INT_RGB),
|
||||
new MTLSwToSurfaceScale(SurfaceType.IntRgbx,
|
||||
MTLSurfaceData.PF_INT_RGBX),
|
||||
new MTLSwToSurfaceScale(SurfaceType.IntBgr,
|
||||
MTLSurfaceData.PF_INT_BGR),
|
||||
new MTLSwToSurfaceScale(SurfaceType.IntBgrx,
|
||||
MTLSurfaceData.PF_INT_BGRX),
|
||||
new MTLSwToSurfaceScale(SurfaceType.ThreeByteBgr,
|
||||
MTLSurfaceData.PF_3BYTE_BGR),
|
||||
new MTLSwToSurfaceScale(SurfaceType.Ushort565Rgb,
|
||||
MTLSurfaceData.PF_USHORT_565_RGB),
|
||||
new MTLSwToSurfaceScale(SurfaceType.Ushort555Rgb,
|
||||
MTLSurfaceData.PF_USHORT_555_RGB),
|
||||
new MTLSwToSurfaceScale(SurfaceType.Ushort555Rgbx,
|
||||
MTLSurfaceData.PF_USHORT_555_RGBX),
|
||||
new MTLSwToSurfaceScale(SurfaceType.ByteGray,
|
||||
MTLSurfaceData.PF_BYTE_GRAY),
|
||||
new MTLSwToSurfaceScale(SurfaceType.UshortGray,
|
||||
MTLSurfaceData.PF_USHORT_GRAY),
|
||||
new MTLSwToSurfaceScale(SurfaceType.IntArgbPre,
|
||||
MTLSurfaceData.PF_INT_ARGB_PRE),
|
||||
|
||||
new MTLSwToSurfaceTransform(SurfaceType.IntRgb,
|
||||
MTLSurfaceData.PF_INT_RGB),
|
||||
new MTLSwToSurfaceTransform(SurfaceType.IntRgbx,
|
||||
MTLSurfaceData.PF_INT_RGBX),
|
||||
new MTLSwToSurfaceTransform(SurfaceType.IntBgr,
|
||||
MTLSurfaceData.PF_INT_BGR),
|
||||
new MTLSwToSurfaceTransform(SurfaceType.IntBgrx,
|
||||
MTLSurfaceData.PF_INT_BGRX),
|
||||
new MTLSwToSurfaceTransform(SurfaceType.ThreeByteBgr,
|
||||
MTLSurfaceData.PF_3BYTE_BGR),
|
||||
new MTLSwToSurfaceTransform(SurfaceType.Ushort565Rgb,
|
||||
MTLSurfaceData.PF_USHORT_565_RGB),
|
||||
new MTLSwToSurfaceTransform(SurfaceType.Ushort555Rgb,
|
||||
MTLSurfaceData.PF_USHORT_555_RGB),
|
||||
new MTLSwToSurfaceTransform(SurfaceType.Ushort555Rgbx,
|
||||
MTLSurfaceData.PF_USHORT_555_RGBX),
|
||||
new MTLSwToSurfaceTransform(SurfaceType.ByteGray,
|
||||
MTLSurfaceData.PF_BYTE_GRAY),
|
||||
new MTLSwToSurfaceTransform(SurfaceType.UshortGray,
|
||||
MTLSurfaceData.PF_USHORT_GRAY),
|
||||
transformBlitIntArgbPreToSurface,
|
||||
|
||||
new MTLGeneralTransformedBlit(transformBlitIntArgbPreToSurface),
|
||||
|
||||
// texture->surface ops
|
||||
new MTLTextureToSurfaceBlit(),
|
||||
new MTLTextureToSurfaceScale(),
|
||||
new MTLTextureToSurfaceTransform(),
|
||||
|
||||
// sw->texture ops
|
||||
blitIntArgbPreToTexture,
|
||||
new MTLSwToTextureBlit(SurfaceType.IntRgb,
|
||||
MTLSurfaceData.PF_INT_RGB),
|
||||
new MTLSwToTextureBlit(SurfaceType.IntRgbx,
|
||||
MTLSurfaceData.PF_INT_RGBX),
|
||||
new MTLSwToTextureBlit(SurfaceType.IntBgr,
|
||||
MTLSurfaceData.PF_INT_BGR),
|
||||
new MTLSwToTextureBlit(SurfaceType.IntBgrx,
|
||||
MTLSurfaceData.PF_INT_BGRX),
|
||||
new MTLSwToTextureBlit(SurfaceType.ThreeByteBgr,
|
||||
MTLSurfaceData.PF_3BYTE_BGR),
|
||||
new MTLSwToTextureBlit(SurfaceType.Ushort565Rgb,
|
||||
MTLSurfaceData.PF_USHORT_565_RGB),
|
||||
new MTLSwToTextureBlit(SurfaceType.Ushort555Rgb,
|
||||
MTLSurfaceData.PF_USHORT_555_RGB),
|
||||
new MTLSwToTextureBlit(SurfaceType.Ushort555Rgbx,
|
||||
MTLSurfaceData.PF_USHORT_555_RGBX),
|
||||
new MTLSwToTextureBlit(SurfaceType.ByteGray,
|
||||
MTLSurfaceData.PF_BYTE_GRAY),
|
||||
new MTLSwToTextureBlit(SurfaceType.UshortGray,
|
||||
MTLSurfaceData.PF_USHORT_GRAY),
|
||||
new MTLGeneralBlit(MTLSurfaceData.MTLTexture,
|
||||
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 |= MTLContext.SRC_IS_OPAQUE;
|
||||
}
|
||||
|
||||
MTLRenderQueue rq = MTLRenderQueue.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);
|
||||
|
||||
MTLSurfaceData oglDst = (MTLSurfaceData)dstData;
|
||||
if (texture) {
|
||||
// make sure we have a current context before uploading
|
||||
// the sysmem data to the texture object
|
||||
MTLGraphicsConfig gc = oglDst.getMTLGraphicsConfig();
|
||||
MTLContext.setScratchSurface(gc);
|
||||
} else {
|
||||
MTLContext.validateContext(oglDst, oglDst,
|
||||
clip, comp, xform, null, null,
|
||||
ctxflags);
|
||||
}
|
||||
|
||||
int packedParams = createPackedParams(false, texture,
|
||||
false, 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 MTLBufImgOps.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 |= MTLContext.SRC_IS_OPAQUE;
|
||||
}
|
||||
|
||||
MTLRenderQueue rq = MTLRenderQueue.getInstance();
|
||||
rq.lock();
|
||||
try {
|
||||
MTLSurfaceData oglSrc = (MTLSurfaceData)srcData;
|
||||
MTLSurfaceData oglDst = (MTLSurfaceData)dstData;
|
||||
int srctype = oglSrc.getType();
|
||||
boolean rtt;
|
||||
MTLSurfaceData srcCtxData;
|
||||
if (srctype == MTLSurfaceData.TEXTURE) {
|
||||
// the source is a regular texture object; we substitute
|
||||
// the destination surface for the purposes of making a
|
||||
// context current
|
||||
rtt = false;
|
||||
srcCtxData = oglDst;
|
||||
} 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 = oglDst;
|
||||
} else {
|
||||
srcCtxData = oglSrc;
|
||||
}
|
||||
}
|
||||
|
||||
MTLContext.validateContext(srcCtxData, oglDst,
|
||||
clip, comp, xform, null, null,
|
||||
ctxflags);
|
||||
|
||||
if (biop != null) {
|
||||
MTLBufImgOps.enableBufImgOp(rq, oglSrc, srcImg, biop);
|
||||
}
|
||||
|
||||
int packedParams = createPackedParams(true, texture,
|
||||
rtt, xform != null,
|
||||
hint, 0 /*unused*/);
|
||||
enqueueBlit(rq, srcData, dstData,
|
||||
packedParams,
|
||||
sx1, sy1, sx2, sy2,
|
||||
dx1, dy1, dx2, dy2);
|
||||
|
||||
if (biop != null) {
|
||||
MTLBufImgOps.disableBufImgOp(rq, biop);
|
||||
}
|
||||
|
||||
if (rtt && oglDst.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 MTLSurfaceToSurfaceBlit extends Blit {
|
||||
|
||||
MTLSurfaceToSurfaceBlit() {
|
||||
super(MTLSurfaceData.MTLSurface,
|
||||
CompositeType.AnyAlpha,
|
||||
MTLSurfaceData.MTLSurface);
|
||||
}
|
||||
|
||||
public void Blit(SurfaceData src, SurfaceData dst,
|
||||
Composite comp, Region clip,
|
||||
int sx, int sy, int dx, int dy, int w, int h)
|
||||
{
|
||||
MTLBlitLoops.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 MTLSurfaceToSurfaceScale extends ScaledBlit {
|
||||
|
||||
MTLSurfaceToSurfaceScale() {
|
||||
super(MTLSurfaceData.MTLSurface,
|
||||
CompositeType.AnyAlpha,
|
||||
MTLSurfaceData.MTLSurface);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
MTLBlitLoops.IsoBlit(src, dst,
|
||||
null, null,
|
||||
comp, clip, null,
|
||||
AffineTransformOp.TYPE_NEAREST_NEIGHBOR,
|
||||
sx1, sy1, sx2, sy2,
|
||||
dx1, dy1, dx2, dy2,
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
class MTLSurfaceToSurfaceTransform extends TransformBlit {
|
||||
|
||||
MTLSurfaceToSurfaceTransform() {
|
||||
super(MTLSurfaceData.MTLSurface,
|
||||
CompositeType.AnyAlpha,
|
||||
MTLSurfaceData.MTLSurface);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
MTLBlitLoops.IsoBlit(src, dst,
|
||||
null, null,
|
||||
comp, clip, at, hint,
|
||||
sx, sy, sx+w, sy+h,
|
||||
dx, dy, dx+w, dy+h,
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
class MTLRTTSurfaceToSurfaceBlit extends Blit {
|
||||
|
||||
MTLRTTSurfaceToSurfaceBlit() {
|
||||
super(MTLSurfaceData.MTLSurfaceRTT,
|
||||
CompositeType.AnyAlpha,
|
||||
MTLSurfaceData.MTLSurface);
|
||||
}
|
||||
|
||||
public void Blit(SurfaceData src, SurfaceData dst,
|
||||
Composite comp, Region clip,
|
||||
int sx, int sy, int dx, int dy, int w, int h)
|
||||
{
|
||||
MTLBlitLoops.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 MTLRTTSurfaceToSurfaceScale extends ScaledBlit {
|
||||
|
||||
MTLRTTSurfaceToSurfaceScale() {
|
||||
super(MTLSurfaceData.MTLSurfaceRTT,
|
||||
CompositeType.AnyAlpha,
|
||||
MTLSurfaceData.MTLSurface);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
MTLBlitLoops.IsoBlit(src, dst,
|
||||
null, null,
|
||||
comp, clip, null,
|
||||
AffineTransformOp.TYPE_NEAREST_NEIGHBOR,
|
||||
sx1, sy1, sx2, sy2,
|
||||
dx1, dy1, dx2, dy2,
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
class MTLRTTSurfaceToSurfaceTransform extends TransformBlit {
|
||||
|
||||
MTLRTTSurfaceToSurfaceTransform() {
|
||||
super(MTLSurfaceData.MTLSurfaceRTT,
|
||||
CompositeType.AnyAlpha,
|
||||
MTLSurfaceData.MTLSurface);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
MTLBlitLoops.IsoBlit(src, dst,
|
||||
null, null,
|
||||
comp, clip, at, hint,
|
||||
sx, sy, sx+w, sy+h,
|
||||
dx, dy, dx+w, dy+h,
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
final class MTLSurfaceToSwBlit extends Blit {
|
||||
|
||||
private final int typeval;
|
||||
private WeakReference<SurfaceData> srcTmp;
|
||||
|
||||
// destination will actually be ArgbPre or Argb
|
||||
MTLSurfaceToSwBlit(final SurfaceType dstType, final int typeval) {
|
||||
super(MTLSurfaceData.MTLSurface,
|
||||
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 MTL surface in two places:
|
||||
// - During MTL 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 == MTLSurfaceData.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;
|
||||
}
|
||||
}
|
||||
|
||||
MTLRenderQueue rq = MTLRenderQueue.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();
|
||||
MTLContext.validateContext((MTLSurfaceData)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 MTLSwToSurfaceBlit extends Blit {
|
||||
|
||||
private int typeval;
|
||||
|
||||
MTLSwToSurfaceBlit(SurfaceType srcType, int typeval) {
|
||||
super(srcType,
|
||||
CompositeType.AnyAlpha,
|
||||
MTLSurfaceData.MTLSurface);
|
||||
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)
|
||||
{
|
||||
MTLBlitLoops.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 MTLSwToSurfaceScale extends ScaledBlit {
|
||||
|
||||
private int typeval;
|
||||
|
||||
MTLSwToSurfaceScale(SurfaceType srcType, int typeval) {
|
||||
super(srcType,
|
||||
CompositeType.AnyAlpha,
|
||||
MTLSurfaceData.MTLSurface);
|
||||
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)
|
||||
{
|
||||
MTLBlitLoops.Blit(src, dst,
|
||||
comp, clip, null,
|
||||
AffineTransformOp.TYPE_NEAREST_NEIGHBOR,
|
||||
sx1, sy1, sx2, sy2,
|
||||
dx1, dy1, dx2, dy2,
|
||||
typeval, false);
|
||||
}
|
||||
}
|
||||
|
||||
class MTLSwToSurfaceTransform extends TransformBlit {
|
||||
|
||||
private int typeval;
|
||||
|
||||
MTLSwToSurfaceTransform(SurfaceType srcType, int typeval) {
|
||||
super(srcType,
|
||||
CompositeType.AnyAlpha,
|
||||
MTLSurfaceData.MTLSurface);
|
||||
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)
|
||||
{
|
||||
MTLBlitLoops.Blit(src, dst,
|
||||
comp, clip, at, hint,
|
||||
sx, sy, sx+w, sy+h,
|
||||
dx, dy, dx+w, dy+h,
|
||||
typeval, false);
|
||||
}
|
||||
}
|
||||
|
||||
class MTLSwToTextureBlit extends Blit {
|
||||
|
||||
private int typeval;
|
||||
|
||||
MTLSwToTextureBlit(SurfaceType srcType, int typeval) {
|
||||
super(srcType,
|
||||
CompositeType.SrcNoEa,
|
||||
MTLSurfaceData.MTLTexture);
|
||||
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)
|
||||
{
|
||||
MTLBlitLoops.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 MTLTextureToSurfaceBlit extends Blit {
|
||||
|
||||
MTLTextureToSurfaceBlit() {
|
||||
super(MTLSurfaceData.MTLTexture,
|
||||
CompositeType.AnyAlpha,
|
||||
MTLSurfaceData.MTLSurface);
|
||||
}
|
||||
|
||||
public void Blit(SurfaceData src, SurfaceData dst,
|
||||
Composite comp, Region clip,
|
||||
int sx, int sy, int dx, int dy, int w, int h)
|
||||
{
|
||||
MTLBlitLoops.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 MTLTextureToSurfaceScale extends ScaledBlit {
|
||||
|
||||
MTLTextureToSurfaceScale() {
|
||||
super(MTLSurfaceData.MTLTexture,
|
||||
CompositeType.AnyAlpha,
|
||||
MTLSurfaceData.MTLSurface);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
MTLBlitLoops.IsoBlit(src, dst,
|
||||
null, null,
|
||||
comp, clip, null,
|
||||
AffineTransformOp.TYPE_NEAREST_NEIGHBOR,
|
||||
sx1, sy1, sx2, sy2,
|
||||
dx1, dy1, dx2, dy2,
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
class MTLTextureToSurfaceTransform extends TransformBlit {
|
||||
|
||||
MTLTextureToSurfaceTransform() {
|
||||
super(MTLSurfaceData.MTLTexture,
|
||||
CompositeType.AnyAlpha,
|
||||
MTLSurfaceData.MTLSurface);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
MTLBlitLoops.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->MTLSurface/Texture loop to get the intermediate
|
||||
* (premultiplied) surface down to OpenGL using simple blit.
|
||||
*/
|
||||
class MTLGeneralBlit extends Blit {
|
||||
|
||||
private final Blit performop;
|
||||
private WeakReference<SurfaceData> srcTmp;
|
||||
|
||||
MTLGeneralBlit(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 OpenGL 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->MTLSurface/Texture loop to get the intermediate
|
||||
* (premultiplied) surface down to OpenGL using simple transformBlit.
|
||||
*/
|
||||
final class MTLGeneralTransformedBlit extends TransformBlit {
|
||||
|
||||
private final TransformBlit performop;
|
||||
private WeakReference<SurfaceData> srcTmp;
|
||||
|
||||
MTLGeneralTransformedBlit(final TransformBlit performop) {
|
||||
super(SurfaceType.Any, CompositeType.AnyAlpha,
|
||||
MTLSurfaceData.MTLSurface);
|
||||
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 OpenGL 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 MTLAnyCompositeBlit 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 OpenGL.
|
||||
*/
|
||||
final class MTLAnyCompositeBlit extends Blit {
|
||||
|
||||
private WeakReference<SurfaceData> dstTmp;
|
||||
private WeakReference<SurfaceData> srcTmp;
|
||||
private final Blit convertsrc;
|
||||
private final Blit convertdst;
|
||||
private final Blit convertresult;
|
||||
|
||||
MTLAnyCompositeBlit(SurfaceType srctype, Blit convertsrc, Blit convertdst,
|
||||
Blit convertresult) {
|
||||
super(srctype, CompositeType.Any, MTLSurfaceData.MTLSurface);
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
package sun.java2d.metal;
|
||||
|
||||
import sun.java2d.SunGraphics2D;
|
||||
import sun.java2d.SurfaceData;
|
||||
import sun.java2d.loops.CompositeType;
|
||||
import sun.java2d.pipe.BufferedBufImgOps;
|
||||
|
||||
import java.awt.image.*;
|
||||
|
||||
import static sun.java2d.metal.MTLContext.MTLContextCaps.CAPS_EXT_BIOP_SHADER;
|
||||
|
||||
class MTLBufImgOps extends BufferedBufImgOps {
|
||||
|
||||
/**
|
||||
* This method is called from MTLDrawImage.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 MTLSurfaceData) ||
|
||||
(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 MTLSurfaceData)) {
|
||||
// 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 MTLSurfaceData)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Verify that the source surface is actually a texture and
|
||||
// that the operation is supported
|
||||
MTLSurfaceData mtlSrc = (MTLSurfaceData)srcData;
|
||||
MTLGraphicsConfig gc = mtlSrc.getMTLGraphicsConfig();
|
||||
if (mtlSrc.getType() != MTLSurfaceData.TEXTURE ||
|
||||
!gc.isCapPresent(CAPS_EXT_BIOP_SHADER))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int sw = img.getWidth();
|
||||
int sh = img.getHeight();
|
||||
MTLBlitLoops.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;
|
||||
}
|
||||
}
|
||||
222
src/java.desktop/macosx/classes/sun/java2d/metal/MTLContext.java
Normal file
222
src/java.desktop/macosx/classes/sun/java2d/metal/MTLContext.java
Normal file
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
package sun.java2d.metal;
|
||||
|
||||
import sun.java2d.pipe.BufferedContext;
|
||||
import sun.java2d.pipe.RenderBuffer;
|
||||
import sun.java2d.pipe.RenderQueue;
|
||||
import sun.java2d.pipe.hw.ContextCapabilities;
|
||||
|
||||
import java.lang.annotation.Native;
|
||||
|
||||
import static sun.java2d.pipe.BufferedOpCodes.*;
|
||||
|
||||
/**
|
||||
* Note that the RenderQueue lock must be acquired before calling any of
|
||||
* the methods in this class.
|
||||
*/
|
||||
public class MTLContext extends BufferedContext {
|
||||
|
||||
private final MTLGraphicsConfig config;
|
||||
|
||||
public MTLContext(RenderQueue rq, MTLGraphicsConfig config) {
|
||||
super(rq);
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method that delegates to setScratchSurface() below.
|
||||
*/
|
||||
static void setScratchSurface(MTLGraphicsConfig gc) {
|
||||
setScratchSurface(gc.getNativeConfigInfo());
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the given GraphicsConfig's context current to its associated
|
||||
* "scratch surface". Each GraphicsConfig maintains a native context
|
||||
* (MTLDevice) as well as a native pbuffer
|
||||
* known as the "scratch surface". By making the context current to the
|
||||
* scratch surface, we are assured that we have a current context for
|
||||
* the relevant GraphicsConfig, and can therefore perform operations
|
||||
* depending on the capabilities of that GraphicsConfig.
|
||||
* This method should be used for operations with an MTL texture
|
||||
* as the destination surface (e.g. a sw->texture blit loop), or in those
|
||||
* situations where we may not otherwise have a current context (e.g.
|
||||
* when disposing a texture-based surface).
|
||||
*/
|
||||
public static void setScratchSurface(long pConfigInfo) {
|
||||
// assert MTLRenderQueue.getInstance().lock.isHeldByCurrentThread();
|
||||
|
||||
// invalidate the current context
|
||||
currentContext = null;
|
||||
|
||||
// set the scratch context
|
||||
MTLRenderQueue rq = MTLRenderQueue.getInstance();
|
||||
RenderBuffer buf = rq.getBuffer();
|
||||
rq.ensureCapacityAndAlignment(12, 4);
|
||||
buf.putInt(SET_SCRATCH_SURFACE);
|
||||
buf.putLong(pConfigInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates the currentContext field to ensure that we properly
|
||||
* revalidate the MTLContext (make it current, etc.) next time through
|
||||
* the validate() method. This is typically invoked from methods
|
||||
* that affect the current context state (e.g. disposing a context or
|
||||
* surface).
|
||||
*/
|
||||
public static void invalidateCurrentContext() {
|
||||
// assert MTLRenderQueue.getInstance().lock.isHeldByCurrentThread();
|
||||
|
||||
// invalidate the current Java-level context so that we
|
||||
// revalidate everything the next time around
|
||||
if (currentContext != null) {
|
||||
currentContext.invalidateContext();
|
||||
currentContext = null;
|
||||
}
|
||||
|
||||
// invalidate the context reference at the native level, and
|
||||
// then flush the queue so that we have no pending operations
|
||||
// dependent on the current context
|
||||
MTLRenderQueue rq = MTLRenderQueue.getInstance();
|
||||
rq.ensureCapacity(4);
|
||||
rq.getBuffer().putInt(INVALIDATE_CONTEXT);
|
||||
rq.flushNow();
|
||||
}
|
||||
|
||||
public RenderQueue getRenderQueue() {
|
||||
return MTLRenderQueue.getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representing adapter id (vendor, renderer, version).
|
||||
* Must be called on the rendering thread.
|
||||
*
|
||||
* @return an id string for the adapter
|
||||
*/
|
||||
public static final native String getMTLIdString();
|
||||
|
||||
@Override
|
||||
public void saveState() {
|
||||
// assert rq.lock.isHeldByCurrentThread();
|
||||
|
||||
// reset all attributes of this and current contexts
|
||||
invalidateContext();
|
||||
invalidateCurrentContext();
|
||||
|
||||
setScratchSurface(config);
|
||||
|
||||
// save the state on the native level
|
||||
rq.ensureCapacity(4);
|
||||
buf.putInt(SAVE_STATE);
|
||||
rq.flushNow();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreState() {
|
||||
// assert rq.lock.isHeldByCurrentThread();
|
||||
|
||||
// reset all attributes of this and current contexts
|
||||
invalidateContext();
|
||||
invalidateCurrentContext();
|
||||
|
||||
setScratchSurface(config);
|
||||
|
||||
// restore the state on the native level
|
||||
rq.ensureCapacity(4);
|
||||
buf.putInt(RESTORE_STATE);
|
||||
rq.flushNow();
|
||||
}
|
||||
|
||||
public static class MTLContextCaps extends ContextCapabilities {
|
||||
/**
|
||||
* This cap will only be set if the fbobject system property has been
|
||||
* enabled and we are able to create an FBO with depth buffer.
|
||||
*/
|
||||
@Native
|
||||
public static final int CAPS_EXT_FBOBJECT =
|
||||
(CAPS_RT_TEXTURE_ALPHA | CAPS_RT_TEXTURE_OPAQUE);
|
||||
/** 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
|
||||
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);
|
||||
/** Indicates the presence of the GL_ARB_texture_rectangle extension. */
|
||||
@Native
|
||||
static final int CAPS_EXT_TEXRECT = (FIRST_PRIVATE_CAP << 4);
|
||||
/** Indicates the presence of the GL_NV_texture_barrier extension. */
|
||||
@Native
|
||||
static final int CAPS_EXT_TEXBARRIER = (FIRST_PRIVATE_CAP << 5);
|
||||
|
||||
|
||||
public MTLContextCaps(int caps, String adapterId) {
|
||||
super(caps, adapterId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(super.toString());
|
||||
if ((caps & CAPS_EXT_FBOBJECT) != 0) {
|
||||
sb.append("CAPS_EXT_FBOBJECT|");
|
||||
}
|
||||
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|");
|
||||
}
|
||||
if ((caps & CAPS_EXT_TEXRECT) != 0) {
|
||||
sb.append("CAPS_EXT_TEXRECT|");
|
||||
}
|
||||
if ((caps & CAPS_EXT_TEXBARRIER) != 0) {
|
||||
sb.append("CAPS_EXT_TEXBARRIER|");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
package sun.java2d.metal;
|
||||
|
||||
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.*;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.image.AffineTransformOp;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.BufferedImageOp;
|
||||
|
||||
public class MTLDrawImage 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() == MTLSurfaceData.MTLTexture ||
|
||||
srcData.getSurfaceType() == MTLSurfaceData.MTLSurfaceRTT ||
|
||||
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 (MTLBufImgOps.renderImageWithOp(sg, img, op, x, y)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
img = op.filter(img, null);
|
||||
}
|
||||
copyImage(sg, img, x, y, null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,439 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
package sun.java2d.metal;
|
||||
|
||||
import sun.awt.CGraphicsConfig;
|
||||
import sun.awt.CGraphicsDevice;
|
||||
import sun.awt.image.OffScreenImage;
|
||||
import sun.awt.image.SunVolatileImage;
|
||||
import sun.awt.image.SurfaceManager;
|
||||
import sun.java2d.Disposer;
|
||||
import sun.java2d.DisposerRecord;
|
||||
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.lwawt.LWComponentPeer;
|
||||
import sun.lwawt.macosx.CFRetainedResource;
|
||||
import sun.lwawt.macosx.CPlatformView;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.color.ColorSpace;
|
||||
import java.awt.image.*;
|
||||
import java.io.File;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.HashMap;
|
||||
|
||||
import static sun.java2d.opengl.OGLSurfaceData.TEXTURE;
|
||||
import static sun.java2d.pipe.hw.AccelSurface.RT_TEXTURE;
|
||||
import static sun.java2d.pipe.hw.ContextCapabilities.*;
|
||||
|
||||
public final class MTLGraphicsConfig extends CGraphicsConfig
|
||||
implements AccelGraphicsConfig, SurfaceManager.ProxiedGraphicsConfig
|
||||
{
|
||||
//private static final int kOpenGLSwapInterval =
|
||||
// RuntimeOptions.getCurrentOptions().OpenGLSwapInterval;
|
||||
private static final int kOpenGLSwapInterval = 0; // TODO
|
||||
private static boolean mtlAvailable;
|
||||
private static ImageCapabilities imageCaps = new MTLImageCaps();
|
||||
|
||||
private static final String mtlShadersLib = AccessController.doPrivileged(
|
||||
(PrivilegedAction<String>) () ->
|
||||
System.getProperty("java.home", "") + File.separator +
|
||||
"lib" + File.separator + "shaders.metallib");
|
||||
|
||||
|
||||
private int pixfmt;
|
||||
private BufferCapabilities bufferCaps;
|
||||
private long pConfigInfo;
|
||||
private ContextCapabilities mtlCaps;
|
||||
private MTLContext context;
|
||||
private final Object disposerReferent = new Object();
|
||||
private final int maxTextureSize;
|
||||
|
||||
private static native boolean initMTL();
|
||||
private static native long getMTLConfigInfo(int displayID, String mtlShadersLib);
|
||||
|
||||
/**
|
||||
* Returns GL_MAX_TEXTURE_SIZE from the shared opengl context. Must be
|
||||
* called under OGLRQ lock, because this method change current context.
|
||||
*
|
||||
* @return GL_MAX_TEXTURE_SIZE
|
||||
*/
|
||||
private static native int nativeGetMaxTextureSize();
|
||||
|
||||
private static final HashMap<Long, Integer> pGCRefCounts = new HashMap<>();
|
||||
|
||||
static {
|
||||
mtlAvailable = initMTL();
|
||||
}
|
||||
|
||||
private MTLGraphicsConfig(CGraphicsDevice device, int pixfmt,
|
||||
long configInfo, int maxTextureSize,
|
||||
ContextCapabilities mtlCaps) {
|
||||
super(device);
|
||||
|
||||
this.pixfmt = pixfmt;
|
||||
this.pConfigInfo = configInfo;
|
||||
this.mtlCaps = mtlCaps;
|
||||
this.maxTextureSize = maxTextureSize;
|
||||
context = new MTLContext(MTLRenderQueue.getInstance(), this);
|
||||
refPConfigInfo(pConfigInfo);
|
||||
// add a record to the Disposer so that we destroy the native
|
||||
// MTLGraphicsConfigInfo data when this object goes away
|
||||
Disposer.addRecord(disposerReferent,
|
||||
new MTLGCDisposerRecord(pConfigInfo));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getProxyKey() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public SurfaceData createManagedSurface(int w, int h, int transparency) {
|
||||
return MTLSurfaceData.createData(this, w, h,
|
||||
getColorModel(transparency),
|
||||
null,
|
||||
MTLSurfaceData.TEXTURE);
|
||||
}
|
||||
|
||||
public static MTLGraphicsConfig getConfig(CGraphicsDevice device,
|
||||
int displayID, int pixfmt)
|
||||
{
|
||||
if (!mtlAvailable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
long cfginfo = 0;
|
||||
int textureSize = 0;
|
||||
final String[] ids = new String[1];
|
||||
MTLRenderQueue rq = MTLRenderQueue.getInstance();
|
||||
rq.lock();
|
||||
try {
|
||||
// getCGLConfigInfo() creates and destroys temporary
|
||||
// surfaces/contexts, so we should first invalidate the current
|
||||
// Java-level context and flush the queue...
|
||||
MTLContext.invalidateCurrentContext();
|
||||
cfginfo = getMTLConfigInfo(displayID, mtlShadersLib);
|
||||
if (cfginfo != 0L) {
|
||||
textureSize = nativeGetMaxTextureSize();
|
||||
// 7160609: GL still fails to create a square texture of this
|
||||
// size. Half should be safe enough.
|
||||
// Explicitly not support a texture more than 2^14, see 8010999.
|
||||
textureSize = textureSize <= 16384 ? textureSize / 2 : 8192;
|
||||
MTLContext.setScratchSurface(cfginfo);
|
||||
rq.flushAndInvokeNow(() -> {
|
||||
ids[0] = MTLContext.getMTLIdString();
|
||||
});
|
||||
}
|
||||
} finally {
|
||||
rq.unlock();
|
||||
}
|
||||
if (cfginfo == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ContextCapabilities caps = new MTLContext.MTLContextCaps(
|
||||
CAPS_PS30 | CAPS_PS20 | CAPS_RT_PLAIN_ALPHA |
|
||||
CAPS_RT_TEXTURE_ALPHA | CAPS_RT_TEXTURE_OPAQUE |
|
||||
CAPS_MULTITEXTURE | CAPS_TEXNONPOW2 | CAPS_TEXNONSQUARE,
|
||||
ids[0]);
|
||||
return new MTLGraphicsConfig(device, pixfmt, cfginfo, textureSize, caps);
|
||||
}
|
||||
|
||||
static void refPConfigInfo(long pConfigInfo) {
|
||||
synchronized (pGCRefCounts) {
|
||||
Integer count = pGCRefCounts.get(pConfigInfo);
|
||||
if (count == null) {
|
||||
count = 1;
|
||||
}
|
||||
else {
|
||||
count++;
|
||||
}
|
||||
pGCRefCounts.put(pConfigInfo, count);
|
||||
}
|
||||
}
|
||||
|
||||
static void deRefPConfigInfo(long pConfigInfo) {
|
||||
synchronized (pGCRefCounts) {
|
||||
Integer count = pGCRefCounts.get(pConfigInfo);
|
||||
if (count != null) {
|
||||
count--;
|
||||
pGCRefCounts.put(pConfigInfo, count);
|
||||
if (count == 0) {
|
||||
MTLRenderQueue.disposeGraphicsConfig(pConfigInfo);
|
||||
pGCRefCounts.remove(pConfigInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the provided capability bit is present for this config.
|
||||
* See MTLContext.java for a list of supported capabilities.
|
||||
*/
|
||||
public boolean isCapPresent(int cap) {
|
||||
return ((mtlCaps.getCaps() & cap) != 0);
|
||||
}
|
||||
|
||||
public long getNativeConfigInfo() {
|
||||
return pConfigInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see sun.java2d.pipe.hw.BufferedContextProvider#getContext
|
||||
*/
|
||||
@Override
|
||||
public MTLContext 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:
|
||||
// REMIND: once the ColorModel spec is changed, this should be
|
||||
// an opaque premultiplied DCM...
|
||||
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;
|
||||
}
|
||||
|
||||
private static class MTLGCDisposerRecord implements DisposerRecord {
|
||||
private long pCfgInfo;
|
||||
public MTLGCDisposerRecord(long pCfgInfo) {
|
||||
this.pCfgInfo = pCfgInfo;
|
||||
}
|
||||
public void dispose() {
|
||||
if (pCfgInfo != 0) {
|
||||
deRefPConfigInfo(pCfgInfo);
|
||||
pCfgInfo = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: CGraphicsConfig doesn't implement displayChanged() yet
|
||||
//@Override
|
||||
public synchronized void displayChanged() {
|
||||
//super.displayChanged();
|
||||
|
||||
// the context could hold a reference to a MTLSurfaceData, which in
|
||||
// turn has a reference back to this MTLGraphicsConfig, so in order
|
||||
// for this instance to be disposed we need to break the connection
|
||||
MTLRenderQueue rq = MTLRenderQueue.getInstance();
|
||||
rq.lock();
|
||||
try {
|
||||
MTLContext.invalidateCurrentContext();
|
||||
} finally {
|
||||
rq.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ("MTLGraphicsConfig[" + getDevice().getIDstring() +
|
||||
",pixfmt="+pixfmt+"]");
|
||||
}
|
||||
|
||||
@Override
|
||||
public SurfaceData createSurfaceData(CPlatformView pView) {
|
||||
return MTLSurfaceData.createData(pView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SurfaceData createSurfaceData(CFRetainedResource layer) {
|
||||
return MTLSurfaceData.createData((MTLLayer) layer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Image createAcceleratedImage(Component target,
|
||||
int width, int height)
|
||||
{
|
||||
ColorModel model = getColorModel(Transparency.OPAQUE);
|
||||
WritableRaster wr = model.createCompatibleWritableRaster(width, height);
|
||||
return new OffScreenImage(target, model, wr,
|
||||
model.isAlphaPremultiplied());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void assertOperationSupported(final int numBuffers,
|
||||
final BufferCapabilities caps)
|
||||
throws AWTException {
|
||||
// Assume this method is never called with numBuffers != 2, as 0 is
|
||||
// unsupported, and 1 corresponds to a SingleBufferStrategy which
|
||||
// doesn't depend on the peer. Screen is considered as a separate
|
||||
// "buffer".
|
||||
if (numBuffers != 2) {
|
||||
throw new AWTException("Only double buffering is supported");
|
||||
}
|
||||
final BufferCapabilities configCaps = getBufferCapabilities();
|
||||
if (!configCaps.isPageFlipping()) {
|
||||
throw new AWTException("Page flipping is not supported");
|
||||
}
|
||||
if (caps.getFlipContents() == BufferCapabilities.FlipContents.PRIOR) {
|
||||
throw new AWTException("FlipContents.PRIOR is not supported");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Image createBackBuffer(final LWComponentPeer<?, ?> peer) {
|
||||
final Rectangle r = peer.getBounds();
|
||||
// It is possible for the component to have size 0x0, adjust it to
|
||||
// be at least 1x1 to avoid IAE
|
||||
final int w = Math.max(1, r.width);
|
||||
final int h = Math.max(1, r.height);
|
||||
final int transparency = peer.isTranslucent() ? Transparency.TRANSLUCENT
|
||||
: Transparency.OPAQUE;
|
||||
return new SunVolatileImage(this, w, h, transparency, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyBackBuffer(final Image backBuffer) {
|
||||
if (backBuffer != null) {
|
||||
backBuffer.flush();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flip(final LWComponentPeer<?, ?> peer, final Image backBuffer,
|
||||
final int x1, final int y1, final int x2, final int y2,
|
||||
final BufferCapabilities.FlipContents flipAction) {
|
||||
final Graphics g = peer.getGraphics();
|
||||
try {
|
||||
g.drawImage(backBuffer, x1, y1, x2, y2, x1, y1, x2, y2, null);
|
||||
} finally {
|
||||
g.dispose();
|
||||
}
|
||||
if (flipAction == BufferCapabilities.FlipContents.BACKGROUND) {
|
||||
final Graphics2D bg = (Graphics2D) backBuffer.getGraphics();
|
||||
try {
|
||||
bg.setBackground(peer.getBackground());
|
||||
bg.clearRect(0, 0, backBuffer.getWidth(null),
|
||||
backBuffer.getHeight(null));
|
||||
} finally {
|
||||
bg.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class MTLBufferCaps extends BufferCapabilities {
|
||||
public MTLBufferCaps(boolean dblBuf) {
|
||||
super(imageCaps, imageCaps,
|
||||
dblBuf ? FlipContents.UNDEFINED : null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferCapabilities getBufferCapabilities() {
|
||||
if (bufferCaps == null) {
|
||||
bufferCaps = new MTLBufferCaps(isDoubleBuffered());
|
||||
}
|
||||
return bufferCaps;
|
||||
}
|
||||
|
||||
private static class MTLImageCaps extends ImageCapabilities {
|
||||
private MTLImageCaps() {
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see sun.java2d.pipe.hw.AccelGraphicsConfig#getContextCapabilities
|
||||
*/
|
||||
@Override
|
||||
public ContextCapabilities getContextCapabilities() {
|
||||
return mtlCaps;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxTextureWidth() {
|
||||
return Math.max(maxTextureSize / getDevice().getScaleFactor(),
|
||||
getBounds().width);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxTextureHeight() {
|
||||
return Math.max(maxTextureSize / getDevice().getScaleFactor(),
|
||||
getBounds().height);
|
||||
}
|
||||
}
|
||||
124
src/java.desktop/macosx/classes/sun/java2d/metal/MTLLayer.java
Normal file
124
src/java.desktop/macosx/classes/sun/java2d/metal/MTLLayer.java
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
package sun.java2d.metal;
|
||||
|
||||
import sun.java2d.NullSurfaceData;
|
||||
import sun.java2d.SurfaceData;
|
||||
import sun.lwawt.LWWindowPeer;
|
||||
import sun.lwawt.macosx.CFRetainedResource;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
public class MTLLayer extends CFRetainedResource {
|
||||
|
||||
private native long nativeCreateLayer();
|
||||
private static native void nativeSetScale(long layerPtr, double scale);
|
||||
private static native void validate(long layerPtr, MTLSurfaceData cglsd);
|
||||
|
||||
private LWWindowPeer peer;
|
||||
private int scale = 1;
|
||||
|
||||
private SurfaceData surfaceData; // represents intermediate buffer (texture)
|
||||
|
||||
public MTLLayer(LWWindowPeer peer) {
|
||||
super(0, true);
|
||||
|
||||
setPtr(nativeCreateLayer());
|
||||
this.peer = peer;
|
||||
}
|
||||
|
||||
public long getPointer() {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
public Rectangle getBounds() {
|
||||
return peer.getBounds();
|
||||
}
|
||||
|
||||
public GraphicsConfiguration getGraphicsConfiguration() {
|
||||
return peer.getGraphicsConfiguration();
|
||||
}
|
||||
|
||||
public boolean isOpaque() {
|
||||
return !peer.isTranslucent();
|
||||
}
|
||||
|
||||
public int getTransparency() {
|
||||
return isOpaque() ? Transparency.OPAQUE : Transparency.TRANSLUCENT;
|
||||
}
|
||||
|
||||
public Object getDestination() {
|
||||
return peer.getTarget();
|
||||
}
|
||||
|
||||
public SurfaceData replaceSurfaceData() {
|
||||
if (getBounds().isEmpty()) {
|
||||
surfaceData = NullSurfaceData.theInstance;
|
||||
return surfaceData;
|
||||
}
|
||||
|
||||
// the layer redirects all painting to the buffer's graphics
|
||||
// and blits the buffer to the layer surface (in drawInCGLContext callback)
|
||||
MTLGraphicsConfig gc = (MTLGraphicsConfig)getGraphicsConfiguration();
|
||||
surfaceData = gc.createSurfaceData(this);
|
||||
setScale(gc.getDevice().getScaleFactor());
|
||||
// the layer holds a reference to the buffer, which in
|
||||
// turn has a reference back to this layer
|
||||
if (surfaceData instanceof MTLSurfaceData) {
|
||||
validate((MTLSurfaceData)surfaceData);
|
||||
}
|
||||
|
||||
return surfaceData;
|
||||
}
|
||||
|
||||
public SurfaceData getSurfaceData() {
|
||||
return surfaceData;
|
||||
}
|
||||
|
||||
public void validate(final MTLSurfaceData cglsd) {
|
||||
MTLRenderQueue rq = MTLRenderQueue.getInstance();
|
||||
rq.lock();
|
||||
try {
|
||||
execute(ptr -> validate(ptr, cglsd));
|
||||
} finally {
|
||||
rq.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
// break the connection between the layer and the buffer
|
||||
validate(null);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
private void setScale(final int _scale) {
|
||||
if (scale != _scale) {
|
||||
scale = _scale;
|
||||
execute(ptr -> nativeSetScale(ptr, scale));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
package sun.java2d.metal;
|
||||
|
||||
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.*;
|
||||
|
||||
import static sun.java2d.loops.CompositeType.SrcNoEa;
|
||||
import static sun.java2d.loops.CompositeType.SrcOver;
|
||||
import static sun.java2d.loops.SurfaceType.*;
|
||||
|
||||
class MTLMaskBlit extends BufferedMaskBlit {
|
||||
|
||||
static void register() {
|
||||
GraphicsPrimitive[] primitives = {
|
||||
new MTLMaskBlit(IntArgb, SrcOver),
|
||||
new MTLMaskBlit(IntArgbPre, SrcOver),
|
||||
new MTLMaskBlit(IntRgb, SrcOver),
|
||||
new MTLMaskBlit(IntRgb, SrcNoEa),
|
||||
new MTLMaskBlit(IntBgr, SrcOver),
|
||||
new MTLMaskBlit(IntBgr, SrcNoEa),
|
||||
};
|
||||
GraphicsPrimitiveMgr.register(primitives);
|
||||
}
|
||||
|
||||
private MTLMaskBlit(SurfaceType srcType,
|
||||
CompositeType compType)
|
||||
{
|
||||
super(MTLRenderQueue.getInstance(),
|
||||
srcType, compType, MTLSurfaceData.MTLSurface);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateContext(SurfaceData dstData,
|
||||
Composite comp, Region clip)
|
||||
{
|
||||
MTLSurfaceData oglDst = (MTLSurfaceData)dstData;
|
||||
MTLContext.validateContext(oglDst, oglDst,
|
||||
clip, comp, null, null, null,
|
||||
MTLContext.NO_CONTEXT_FLAGS);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
package sun.java2d.metal;
|
||||
|
||||
import sun.java2d.InvalidPipeException;
|
||||
import sun.java2d.SunGraphics2D;
|
||||
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.*;
|
||||
|
||||
import static sun.java2d.loops.CompositeType.SrcNoEa;
|
||||
import static sun.java2d.loops.CompositeType.SrcOver;
|
||||
import static sun.java2d.loops.SurfaceType.*;
|
||||
|
||||
class MTLMaskFill extends BufferedMaskFill {
|
||||
|
||||
static void register() {
|
||||
GraphicsPrimitive[] primitives = {
|
||||
new MTLMaskFill(AnyColor, SrcOver),
|
||||
new MTLMaskFill(OpaqueColor, SrcNoEa),
|
||||
new MTLMaskFill(GradientPaint, SrcOver),
|
||||
new MTLMaskFill(OpaqueGradientPaint, SrcNoEa),
|
||||
new MTLMaskFill(LinearGradientPaint, SrcOver),
|
||||
new MTLMaskFill(OpaqueLinearGradientPaint, SrcNoEa),
|
||||
new MTLMaskFill(RadialGradientPaint, SrcOver),
|
||||
new MTLMaskFill(OpaqueRadialGradientPaint, SrcNoEa),
|
||||
new MTLMaskFill(TexturePaint, SrcOver),
|
||||
new MTLMaskFill(OpaqueTexturePaint, SrcNoEa),
|
||||
};
|
||||
GraphicsPrimitiveMgr.register(primitives);
|
||||
}
|
||||
|
||||
protected MTLMaskFill(SurfaceType srcType, CompositeType compType) {
|
||||
super(MTLRenderQueue.getInstance(),
|
||||
srcType, compType, MTLSurfaceData.MTLSurface);
|
||||
}
|
||||
|
||||
@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)
|
||||
{
|
||||
MTLSurfaceData dstData;
|
||||
try {
|
||||
dstData = (MTLSurfaceData) sg2d.surfaceData;
|
||||
} catch (ClassCastException e) {
|
||||
throw new InvalidPipeException("wrong surface data type: " +
|
||||
sg2d.surfaceData);
|
||||
}
|
||||
|
||||
MTLContext.validateContext(dstData, dstData,
|
||||
sg2d.getCompClip(), comp,
|
||||
null, sg2d.paint, sg2d, ctxflags);
|
||||
}
|
||||
}
|
||||
208
src/java.desktop/macosx/classes/sun/java2d/metal/MTLPaints.java
Normal file
208
src/java.desktop/macosx/classes/sun/java2d/metal/MTLPaints.java
Normal file
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
package sun.java2d.metal;
|
||||
|
||||
import sun.java2d.SunGraphics2D;
|
||||
import sun.java2d.SurfaceData;
|
||||
import sun.java2d.loops.CompositeType;
|
||||
|
||||
import java.awt.*;
|
||||
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.metal.MTLContext.MTLContextCaps.CAPS_EXT_GRAD_SHADER;
|
||||
import static sun.java2d.pipe.BufferedPaints.MULTI_MAX_FRACTIONS;
|
||||
|
||||
abstract class MTLPaints {
|
||||
|
||||
/**
|
||||
* Holds all registered implementations, using the corresponding
|
||||
* SunGraphics2D.PAINT_* constant as the hash key.
|
||||
*/
|
||||
private static Map<Integer, MTLPaints> impls =
|
||||
new HashMap<Integer, MTLPaints>(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) {
|
||||
MTLPaints 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 MTLPaints {
|
||||
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 MTLPaints {
|
||||
private Texture() {}
|
||||
|
||||
/**
|
||||
* Returns true if the given TexturePaint instance can be used by the
|
||||
* accelerated MTLPaints.Texture implementation. A TexturePaint is
|
||||
* considered valid if the following conditions are met:
|
||||
* - the texture image dimensions are power-of-two (or the
|
||||
* GL_ARB_texture_non_power_of_two extension is present)
|
||||
* - the texture image can be (or is already) cached in an OpenGL
|
||||
* texture object
|
||||
*/
|
||||
@Override
|
||||
boolean isPaintValid(SunGraphics2D sg2d) {
|
||||
TexturePaint paint = (TexturePaint)sg2d.paint;
|
||||
MTLSurfaceData dstData = (MTLSurfaceData)sg2d.surfaceData;
|
||||
BufferedImage bi = paint.getImage();
|
||||
|
||||
// see if texture-non-pow2 extension is available
|
||||
if (!dstData.isTexNonPow2Available()) {
|
||||
int imgw = bi.getWidth();
|
||||
int imgh = bi.getHeight();
|
||||
|
||||
// verify that the texture image dimensions are pow2
|
||||
if ((imgw & (imgw - 1)) != 0 || (imgh & (imgh - 1)) != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
SurfaceData srcData =
|
||||
dstData.getSourceSurfaceData(bi,
|
||||
SunGraphics2D.TRANSFORM_ISIDENT,
|
||||
CompositeType.SrcOver, null);
|
||||
if (!(srcData instanceof MTLSurfaceData)) {
|
||||
// REMIND: this is a hack that attempts to cache the system
|
||||
// memory image from the TexturePaint instance into an
|
||||
// OpenGL texture...
|
||||
srcData =
|
||||
dstData.getSourceSurfaceData(bi,
|
||||
SunGraphics2D.TRANSFORM_ISIDENT,
|
||||
CompositeType.SrcOver, null);
|
||||
if (!(srcData instanceof MTLSurfaceData)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// verify that the source surface is actually a texture
|
||||
MTLSurfaceData oglData = (MTLSurfaceData)srcData;
|
||||
if (oglData.getType() != MTLSurfaceData.TEXTURE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/****************** Shared MultipleGradientPaint support ********************/
|
||||
|
||||
private abstract static class MultiGradient extends MTLPaints {
|
||||
protected MultiGradient() {}
|
||||
|
||||
/**
|
||||
* Returns true if the given MultipleGradientPaint instance can be
|
||||
* used by the accelerated MTLPaints.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;
|
||||
}
|
||||
|
||||
MTLSurfaceData dstData = (MTLSurfaceData)sg2d.surfaceData;
|
||||
MTLGraphicsConfig gc = dstData.getMTLGraphicsConfig();
|
||||
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() {}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
package sun.java2d.metal;
|
||||
|
||||
import sun.awt.util.ThreadGroupUtils;
|
||||
import sun.java2d.pipe.RenderBuffer;
|
||||
import sun.java2d.pipe.RenderQueue;
|
||||
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
import static sun.java2d.pipe.BufferedOpCodes.DISPOSE_CONFIG;
|
||||
import static sun.java2d.pipe.BufferedOpCodes.SYNC;
|
||||
|
||||
/**
|
||||
* OGL-specific implementation of RenderQueue. This class provides a
|
||||
* single (daemon) thread that is responsible for periodically flushing
|
||||
* the queue, thus ensuring that only one thread communicates with the native
|
||||
* OpenGL libraries for the entire process.
|
||||
*/
|
||||
public class MTLRenderQueue extends RenderQueue {
|
||||
|
||||
private static MTLRenderQueue theInstance;
|
||||
private final QueueFlusher flusher;
|
||||
|
||||
private MTLRenderQueue() {
|
||||
/*
|
||||
* 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 MTLRenderQueue instance. If it has not yet been
|
||||
* initialized, this method will first construct the single instance
|
||||
* before returning it.
|
||||
*/
|
||||
public static synchronized MTLRenderQueue getInstance() {
|
||||
if (theInstance == null) {
|
||||
theInstance = new MTLRenderQueue();
|
||||
}
|
||||
return theInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes the single MTLRenderQueue instance synchronously. If an
|
||||
* MTLRenderQueue 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 OGL pipeline, but only if the OGL pipeline is currently
|
||||
* enabled. Since this class has few external dependencies, callers need
|
||||
* not be concerned that calling this method will trigger initialization
|
||||
* of the OGL pipeline and related classes.
|
||||
*/
|
||||
public static void sync() {
|
||||
if (theInstance != null) {
|
||||
theInstance.lock();
|
||||
try {
|
||||
theInstance.ensureCapacity(4);
|
||||
theInstance.getBuffer().putInt(SYNC);
|
||||
theInstance.flushNow();
|
||||
} finally {
|
||||
theInstance.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disposes the native memory associated with the given native
|
||||
* graphics config info pointer on the single queue flushing thread.
|
||||
*/
|
||||
public static void disposeGraphicsConfig(long pConfigInfo) {
|
||||
MTLRenderQueue rq = getInstance();
|
||||
rq.lock();
|
||||
try {
|
||||
// make sure we make the context associated with the given
|
||||
// GraphicsConfig current before disposing the native resources
|
||||
MTLContext.setScratchSurface(pConfigInfo);
|
||||
|
||||
RenderBuffer buf = rq.getBuffer();
|
||||
rq.ensureCapacityAndAlignment(12, 4);
|
||||
buf.putInt(DISPOSE_CONFIG);
|
||||
buf.putLong(pConfigInfo);
|
||||
|
||||
// this call is expected to complete synchronously, so flush now
|
||||
rq.flushNow();
|
||||
} finally {
|
||||
rq.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the current thread is the OGL QueueFlusher thread.
|
||||
*/
|
||||
public static boolean isQueueFlusherThread() {
|
||||
return (Thread.currentThread() == getInstance().flusher.thread);
|
||||
}
|
||||
|
||||
|
||||
@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() {
|
||||
String name = "Java2D Queue Flusher";
|
||||
thread = new Thread(ThreadGroupUtils.getRootThreadGroup(),
|
||||
this, name, 0, false);
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
package sun.java2d.metal;
|
||||
|
||||
import sun.java2d.InvalidPipeException;
|
||||
import sun.java2d.SunGraphics2D;
|
||||
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.*;
|
||||
import java.awt.geom.Path2D;
|
||||
|
||||
import static sun.java2d.pipe.BufferedOpCodes.COPY_AREA;
|
||||
|
||||
class MTLRenderer extends BufferedRenderPipe {
|
||||
|
||||
MTLRenderer(RenderQueue rq) {
|
||||
super(rq);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateContext(SunGraphics2D sg2d) {
|
||||
int ctxflags =
|
||||
sg2d.paint.getTransparency() == Transparency.OPAQUE ?
|
||||
MTLContext.SRC_IS_OPAQUE : MTLContext.NO_CONTEXT_FLAGS;
|
||||
MTLSurfaceData dstData;
|
||||
try {
|
||||
dstData = (MTLSurfaceData)sg2d.surfaceData;
|
||||
} catch (ClassCastException e) {
|
||||
throw new InvalidPipeException("wrong surface data type: " + sg2d.surfaceData);
|
||||
}
|
||||
MTLContext.validateContext(dstData, dstData,
|
||||
sg2d.getCompClip(), sg2d.composite,
|
||||
null, sg2d.paint, sg2d, ctxflags);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateContextAA(SunGraphics2D sg2d) {
|
||||
int ctxflags = MTLContext.NO_CONTEXT_FLAGS;
|
||||
MTLSurfaceData dstData;
|
||||
try {
|
||||
dstData = (MTLSurfaceData)sg2d.surfaceData;
|
||||
} catch (ClassCastException e) {
|
||||
throw new InvalidPipeException("wrong surface data type: " + sg2d.surfaceData);
|
||||
}
|
||||
MTLContext.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 ?
|
||||
MTLContext.SRC_IS_OPAQUE : MTLContext.NO_CONTEXT_FLAGS;
|
||||
MTLSurfaceData dstData;
|
||||
try {
|
||||
dstData = (MTLSurfaceData)sg2d.surfaceData;
|
||||
} catch (ClassCastException e) {
|
||||
throw new InvalidPipeException("wrong surface data type: " + sg2d.surfaceData);
|
||||
}
|
||||
MTLContext.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 native void drawPoly(int[] xPoints, int[] yPoints,
|
||||
int nPoints, boolean isClosed,
|
||||
int transX, int transY);
|
||||
|
||||
MTLRenderer traceWrap() {
|
||||
return new Tracer(this);
|
||||
}
|
||||
|
||||
private class Tracer extends MTLRenderer {
|
||||
private MTLRenderer mtlr;
|
||||
Tracer(MTLRenderer mtlr) {
|
||||
super(mtlr.rq);
|
||||
this.mtlr = mtlr;
|
||||
}
|
||||
public ParallelogramPipe getAAParallelogramPipe() {
|
||||
final ParallelogramPipe realpipe = mtlr.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("MTLFillAAParallelogram");
|
||||
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("MTLDrawAAParallelogram");
|
||||
realpipe.drawParallelogram(sg2d,
|
||||
ux1, uy1, ux2, uy2,
|
||||
x, y, dx1, dy1, dx2, dy2,
|
||||
lw1, lw2);
|
||||
}
|
||||
};
|
||||
}
|
||||
protected void validateContext(SunGraphics2D sg2d) {
|
||||
mtlr.validateContext(sg2d);
|
||||
}
|
||||
public void drawLine(SunGraphics2D sg2d,
|
||||
int x1, int y1, int x2, int y2)
|
||||
{
|
||||
GraphicsPrimitive.tracePrimitive("MTLDrawLine");
|
||||
mtlr.drawLine(sg2d, x1, y1, x2, y2);
|
||||
}
|
||||
public void drawRect(SunGraphics2D sg2d, int x, int y, int w, int h) {
|
||||
GraphicsPrimitive.tracePrimitive("MTLDrawRect");
|
||||
mtlr.drawRect(sg2d, x, y, w, h);
|
||||
}
|
||||
protected void drawPoly(SunGraphics2D sg2d,
|
||||
int[] xPoints, int[] yPoints,
|
||||
int nPoints, boolean isClosed)
|
||||
{
|
||||
GraphicsPrimitive.tracePrimitive("MTLDrawPoly");
|
||||
mtlr.drawPoly(sg2d, xPoints, yPoints, nPoints, isClosed);
|
||||
}
|
||||
public void fillRect(SunGraphics2D sg2d, int x, int y, int w, int h) {
|
||||
GraphicsPrimitive.tracePrimitive("MTLFillRect");
|
||||
mtlr.fillRect(sg2d, x, y, w, h);
|
||||
}
|
||||
protected void drawPath(SunGraphics2D sg2d,
|
||||
Path2D.Float p2df, int transx, int transy)
|
||||
{
|
||||
GraphicsPrimitive.tracePrimitive("MTLDrawPath");
|
||||
mtlr.drawPath(sg2d, p2df, transx, transy);
|
||||
}
|
||||
protected void fillPath(SunGraphics2D sg2d,
|
||||
Path2D.Float p2df, int transx, int transy)
|
||||
{
|
||||
GraphicsPrimitive.tracePrimitive("MTLFillPath");
|
||||
mtlr.fillPath(sg2d, p2df, transx, transy);
|
||||
}
|
||||
protected void fillSpans(SunGraphics2D sg2d, SpanIterator si,
|
||||
int transx, int transy)
|
||||
{
|
||||
GraphicsPrimitive.tracePrimitive("MTLFillSpans");
|
||||
mtlr.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("MTLFillParallelogram");
|
||||
mtlr.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("MTLDrawParallelogram");
|
||||
mtlr.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("MTLCopyArea");
|
||||
mtlr.copyArea(sg2d, x, y, w, h, dx, dy);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,885 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
package sun.java2d.metal;
|
||||
|
||||
import sun.awt.SunHints;
|
||||
import sun.awt.image.PixelConverter;
|
||||
import sun.java2d.SunGraphics2D;
|
||||
import sun.java2d.SurfaceData;
|
||||
import sun.java2d.SurfaceDataProxy;
|
||||
import sun.java2d.loops.CompositeType;
|
||||
import sun.java2d.loops.GraphicsPrimitive;
|
||||
import sun.java2d.loops.MaskFill;
|
||||
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 sun.lwawt.macosx.CPlatformView;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.Raster;
|
||||
|
||||
import static sun.java2d.metal.MTLContext.MTLContextCaps.CAPS_EXT_LCD_SHADER;
|
||||
import static sun.java2d.metal.MTLContext.MTLContextCaps.CAPS_EXT_TEXRECT;
|
||||
import static sun.java2d.pipe.BufferedOpCodes.FLUSH_SURFACE;
|
||||
import static sun.java2d.pipe.BufferedOpCodes.SWAP_BUFFERS;
|
||||
import static sun.java2d.pipe.hw.ContextCapabilities.*;
|
||||
|
||||
public abstract class MTLSurfaceData 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_MTL_SURFACE = "MTL Surface";
|
||||
private static final String DESC_MTL_SURFACE_RTT =
|
||||
"MTL Surface (render-to-texture)";
|
||||
private static final String DESC_MTL_TEXTURE = "MTL Texture";
|
||||
|
||||
|
||||
static final SurfaceType MTLSurface =
|
||||
SurfaceType.Any.deriveSubType(DESC_MTL_SURFACE,
|
||||
PixelConverter.ArgbPre.instance);
|
||||
static final SurfaceType MTLSurfaceRTT =
|
||||
MTLSurface.deriveSubType(DESC_MTL_SURFACE_RTT);
|
||||
static final SurfaceType MTLTexture =
|
||||
SurfaceType.Any.deriveSubType(DESC_MTL_TEXTURE);
|
||||
|
||||
protected static MTLRenderer mtlRenderPipe;
|
||||
protected static PixelToParallelogramConverter mtlTxRenderPipe;
|
||||
protected static ParallelogramPipe mtlAAPgramPipe;
|
||||
protected static MTLTextRenderer mtlTextPipe;
|
||||
protected static MTLDrawImage mtlImagePipe;
|
||||
/** This will be true if the fbobject system property has been enabled. */
|
||||
private static boolean isFBObjectEnabled;
|
||||
/** This will be true if the lcdshader system property has been enabled.*/
|
||||
private static boolean isLCDShaderEnabled;
|
||||
/** This will be true if the biopshader system property has been enabled.*/
|
||||
private static boolean isBIOpShaderEnabled;
|
||||
/** This will be true if the gradshader system property has been enabled.*/
|
||||
private static boolean isGradShaderEnabled;
|
||||
|
||||
static {
|
||||
if (!GraphicsEnvironment.isHeadless()) {
|
||||
// fbobject currently enabled by default; use "false" to disable
|
||||
String fbo = java.security.AccessController.doPrivileged(
|
||||
new sun.security.action.GetPropertyAction(
|
||||
"java2d.metal.fbobject"));
|
||||
isFBObjectEnabled = !"false".equals(fbo);
|
||||
|
||||
// lcdshader currently enabled by default; use "false" to disable
|
||||
String lcd = java.security.AccessController.doPrivileged(
|
||||
new sun.security.action.GetPropertyAction(
|
||||
"java2d.metal.lcdshader"));
|
||||
isLCDShaderEnabled = !"false".equals(lcd);
|
||||
|
||||
// biopshader currently enabled by default; use "false" to disable
|
||||
String biop = java.security.AccessController.doPrivileged(
|
||||
new sun.security.action.GetPropertyAction(
|
||||
"java2d.metal.biopshader"));
|
||||
isBIOpShaderEnabled = !"false".equals(biop);
|
||||
|
||||
// gradshader currently enabled by default; use "false" to disable
|
||||
String grad = java.security.AccessController.doPrivileged(
|
||||
new sun.security.action.GetPropertyAction(
|
||||
"java2d.metal.gradshader"));
|
||||
isGradShaderEnabled = !"false".equals(grad);
|
||||
|
||||
MTLRenderQueue rq = MTLRenderQueue.getInstance();
|
||||
mtlImagePipe = new MTLDrawImage();
|
||||
mtlTextPipe = new MTLTextRenderer(rq);
|
||||
mtlRenderPipe = new MTLRenderer(rq);
|
||||
if (GraphicsPrimitive.tracingEnabled()) {
|
||||
mtlTextPipe = mtlTextPipe.traceWrap();
|
||||
//The wrapped mtlRenderPipe will wrap the AA pipe as well...
|
||||
//mtlAAPgramPipe = mtlRenderPipe.traceWrap();
|
||||
}
|
||||
mtlAAPgramPipe = mtlRenderPipe.getAAParallelogramPipe();
|
||||
mtlTxRenderPipe =
|
||||
new PixelToParallelogramConverter(mtlRenderPipe,
|
||||
mtlRenderPipe,
|
||||
1.0, 0.25, true);
|
||||
|
||||
MTLBlitLoops.register();
|
||||
MTLMaskFill.register();
|
||||
MTLMaskBlit.register();
|
||||
}
|
||||
}
|
||||
|
||||
protected final int scale;
|
||||
protected final int width;
|
||||
protected final int height;
|
||||
protected CPlatformView pView;
|
||||
protected int type;
|
||||
private MTLGraphicsConfig 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 OpenGL
|
||||
* surface type constant (e.g. TEXTURE -> MTLTexture).
|
||||
*/
|
||||
private static SurfaceType getCustomSurfaceType(int oglType) {
|
||||
switch (oglType) {
|
||||
case TEXTURE:
|
||||
return MTLTexture;
|
||||
case RT_TEXTURE:
|
||||
return MTLSurfaceRTT;
|
||||
default:
|
||||
return MTLSurface;
|
||||
}
|
||||
}
|
||||
|
||||
static void swapBuffers(long window) {
|
||||
MTLRenderQueue rq = MTLRenderQueue.getInstance();
|
||||
rq.lock();
|
||||
try {
|
||||
RenderBuffer buf = rq.getBuffer();
|
||||
rq.ensureCapacityAndAlignment(12, 4);
|
||||
buf.putInt(SWAP_BUFFERS);
|
||||
buf.putLong(window);
|
||||
rq.flushNow();
|
||||
} finally {
|
||||
rq.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
native void validate(int xoff, int yoff, int width, int height, boolean isOpaque);
|
||||
|
||||
private native void initOps(long pConfigInfo, long pPeerData, long layerPtr,
|
||||
int xoff, int yoff, boolean isOpaque);
|
||||
|
||||
protected MTLSurfaceData(MTLGraphicsConfig 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 = type == TEXTURE ? 1 : gc.getDevice().getScaleFactor();
|
||||
this.width = width * scale;
|
||||
this.height = height * scale;
|
||||
}
|
||||
|
||||
protected MTLSurfaceData(CPlatformView pView, MTLGraphicsConfig gc,
|
||||
ColorModel cm, int type, int width, int height)
|
||||
{
|
||||
this(gc, cm, type, width, height);
|
||||
this.pView = pView;
|
||||
this.graphicsConfig = gc;
|
||||
|
||||
long pConfigInfo = gc.getNativeConfigInfo();
|
||||
long pPeerData = 0L;
|
||||
boolean isOpaque = true;
|
||||
if (pView != null) {
|
||||
pPeerData = pView.getAWTView();
|
||||
isOpaque = pView.isOpaque();
|
||||
}
|
||||
MTLGraphicsConfig.refPConfigInfo(pConfigInfo);
|
||||
initOps(pConfigInfo, pPeerData, 0, 0, 0, isOpaque);
|
||||
}
|
||||
|
||||
protected MTLSurfaceData(MTLLayer layer, MTLGraphicsConfig gc,
|
||||
ColorModel cm, int type, int width, int height)
|
||||
{
|
||||
this(gc, cm, type, width, height);
|
||||
this.graphicsConfig = gc;
|
||||
|
||||
long pConfigInfo = gc.getNativeConfigInfo();
|
||||
long layerPtr = 0L;
|
||||
boolean isOpaque = true;
|
||||
if (layer != null) {
|
||||
layerPtr = layer.getPointer();
|
||||
isOpaque = layer.isOpaque();
|
||||
}
|
||||
MTLGraphicsConfig.refPConfigInfo(pConfigInfo);
|
||||
initOps(pConfigInfo, 0, layerPtr, 0, 0, isOpaque);
|
||||
}
|
||||
|
||||
@Override //SurfaceData
|
||||
public GraphicsConfiguration getDeviceConfiguration() {
|
||||
return graphicsConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a SurfaceData object representing the primary (front) buffer of
|
||||
* an on-screen Window.
|
||||
*/
|
||||
public static MTLWindowSurfaceData createData(CPlatformView pView) {
|
||||
MTLGraphicsConfig gc = getGC(pView);
|
||||
return new MTLWindowSurfaceData(pView, gc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a SurfaceData object representing the intermediate buffer
|
||||
* between the Java2D flusher thread and the AppKit thread.
|
||||
*/
|
||||
public static MTLLayerSurfaceData createData(MTLLayer layer) {
|
||||
MTLGraphicsConfig gc = getGC(layer);
|
||||
Rectangle r = layer.getBounds();
|
||||
return new MTLLayerSurfaceData(layer, gc, r.width, r.height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a SurfaceData object representing the back buffer of a
|
||||
* double-buffered on-screen Window.
|
||||
*/
|
||||
public static MTLOffScreenSurfaceData createData(CPlatformView pView,
|
||||
Image image, int type) {
|
||||
MTLGraphicsConfig gc = getGC(pView);
|
||||
Rectangle r = pView.getBounds();
|
||||
if (type == FLIP_BACKBUFFER) {
|
||||
return new MTLOffScreenSurfaceData(pView, gc, r.width, r.height,
|
||||
image, gc.getColorModel(), FLIP_BACKBUFFER);
|
||||
} else {
|
||||
return new MTLVSyncOffScreenSurfaceData(pView, gc, r.width,
|
||||
r.height, image, gc.getColorModel(), type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a SurfaceData object representing an off-screen buffer (either a
|
||||
* FBO or Texture).
|
||||
*/
|
||||
public static MTLOffScreenSurfaceData createData(MTLGraphicsConfig gc,
|
||||
int width, int height, ColorModel cm, Image image, int type) {
|
||||
return new MTLOffScreenSurfaceData(null, gc, width, height, image, cm,
|
||||
type);
|
||||
}
|
||||
|
||||
public static MTLGraphicsConfig getGC(CPlatformView pView) {
|
||||
if (pView != null) {
|
||||
return (MTLGraphicsConfig)pView.getGraphicsConfiguration();
|
||||
} else {
|
||||
// REMIND: this should rarely (never?) happen, but what if
|
||||
// default config is not CGL?
|
||||
GraphicsEnvironment env = GraphicsEnvironment
|
||||
.getLocalGraphicsEnvironment();
|
||||
GraphicsDevice gd = env.getDefaultScreenDevice();
|
||||
return (MTLGraphicsConfig) gd.getDefaultConfiguration();
|
||||
}
|
||||
}
|
||||
|
||||
public static MTLGraphicsConfig getGC(MTLLayer layer) {
|
||||
return (MTLGraphicsConfig)layer.getGraphicsConfiguration();
|
||||
}
|
||||
|
||||
public void validate() {
|
||||
// Overridden in MTLWindowSurfaceData below
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDefaultScaleX() {
|
||||
return scale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDefaultScaleY() {
|
||||
return scale;
|
||||
}
|
||||
|
||||
protected native void clearWindow();
|
||||
|
||||
protected native boolean initTexture(long pData,
|
||||
boolean isOpaque, boolean texNonPow2,
|
||||
boolean texRect,
|
||||
int width, int height);
|
||||
|
||||
protected native boolean initRTexture(long pData,
|
||||
boolean isOpaque, boolean texNonPow2,
|
||||
boolean texRect,
|
||||
int width, int height);
|
||||
|
||||
protected native boolean initFlipBackbuffer(long pData);
|
||||
|
||||
@Override
|
||||
public SurfaceDataProxy makeProxyFor(SurfaceData srcData) {
|
||||
return MTLSurfaceDataProxy.createProxy(srcData, graphicsConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: This should only be called from the QFT under the AWT lock.
|
||||
* This method is kept separate from the initSurface() method below just
|
||||
* to keep the code a bit cleaner.
|
||||
*/
|
||||
private void initSurfaceNow(int width, int height) {
|
||||
boolean isOpaque = (getTransparency() == Transparency.OPAQUE);
|
||||
boolean success = false;
|
||||
|
||||
switch (type) {
|
||||
case TEXTURE:
|
||||
success = initTexture(getNativeOps(),
|
||||
isOpaque, isTexNonPow2Available(),
|
||||
isTexRectAvailable(),
|
||||
width, height);
|
||||
break;
|
||||
|
||||
case RT_TEXTURE:
|
||||
success = initRTexture(getNativeOps(),
|
||||
isOpaque, isTexNonPow2Available(),
|
||||
isTexRectAvailable(),
|
||||
width, height);
|
||||
break;
|
||||
|
||||
case FLIP_BACKBUFFER:
|
||||
success = initFlipBackbuffer(getNativeOps());
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
throw new OutOfMemoryError("can't create offscreen surface");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the appropriate OpenGL offscreen surface based on the value
|
||||
* of the type parameter. If the surface creation fails for any reason,
|
||||
* an OutOfMemoryError will be thrown.
|
||||
*/
|
||||
protected void initSurface(final int width, final int height) {
|
||||
MTLRenderQueue rq = MTLRenderQueue.getInstance();
|
||||
rq.lock();
|
||||
try {
|
||||
switch (type) {
|
||||
case TEXTURE:
|
||||
case RT_TEXTURE:
|
||||
// need to make sure the context is current before
|
||||
// creating the texture or fbobject
|
||||
MTLContext.setScratchSurface(graphicsConfig);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
rq.flushAndInvokeNow(new Runnable() {
|
||||
public void run() {
|
||||
initSurfaceNow(width, height);
|
||||
}
|
||||
});
|
||||
} finally {
|
||||
rq.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the MTLContext for the GraphicsConfig associated with this
|
||||
* surface.
|
||||
*/
|
||||
public final MTLContext getContext() {
|
||||
return graphicsConfig.getContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the MTLGraphicsConfig associated with this surface.
|
||||
*/
|
||||
final MTLGraphicsConfig getMTLGraphicsConfig() {
|
||||
return graphicsConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns one of the surface type constants defined above.
|
||||
*/
|
||||
public final int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* For now, we can only render LCD text if:
|
||||
* - the fragment shader extension is available, and
|
||||
* - the source color is opaque, and
|
||||
* - blending is SrcOverNoEa or disabled
|
||||
* - and the destination is opaque
|
||||
*
|
||||
* Eventually, we could enhance the native OGL text rendering code
|
||||
* and remove the above restrictions, but that would require significantly
|
||||
* more code just to support a few uncommon cases.
|
||||
*/
|
||||
public boolean canRenderLCDText(SunGraphics2D sg2d) {
|
||||
return
|
||||
graphicsConfig.isCapPresent(CAPS_EXT_LCD_SHADER) &&
|
||||
sg2d.surfaceData.getTransparency() == Transparency.OPAQUE &&
|
||||
sg2d.paintState <= SunGraphics2D.PAINT_OPAQUECOLOR &&
|
||||
(sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY ||
|
||||
(sg2d.compositeState <= SunGraphics2D.COMP_ALPHA && canHandleComposite(sg2d.composite)));
|
||||
}
|
||||
|
||||
private boolean canHandleComposite(Composite c) {
|
||||
if (c instanceof AlphaComposite) {
|
||||
AlphaComposite ac = (AlphaComposite)c;
|
||||
|
||||
return ac.getRule() == AlphaComposite.SRC_OVER && ac.getAlpha() >= 1f;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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 = mtlTextPipe;
|
||||
} 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;
|
||||
MTLRenderer nonTxPipe = null;
|
||||
|
||||
if (sg2d.antialiasHint != SunHints.INTVAL_ANTIALIAS_ON) {
|
||||
if (sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR) {
|
||||
if (sg2d.compositeState <= SunGraphics2D.COMP_XOR) {
|
||||
txPipe = mtlTxRenderPipe;
|
||||
nonTxPipe = mtlRenderPipe;
|
||||
}
|
||||
} else if (sg2d.compositeState <= SunGraphics2D.COMP_ALPHA) {
|
||||
if (MTLPaints.isValid(sg2d)) {
|
||||
txPipe = mtlTxRenderPipe;
|
||||
nonTxPipe = mtlRenderPipe;
|
||||
}
|
||||
// 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,
|
||||
mtlAAPgramPipe,
|
||||
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 = mtlTxRenderPipe;
|
||||
nonTxPipe = mtlRenderPipe;
|
||||
}
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
// install the text pipe based on our earlier decision
|
||||
sg2d.textpipe = textpipe;
|
||||
|
||||
// always override the image pipe with the specialized OGL pipe
|
||||
sg2d.imagepipe = mtlImagePipe;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MaskFill getMaskFill(SunGraphics2D sg2d) {
|
||||
if (sg2d.paintState > SunGraphics2D.PAINT_ALPHACOLOR) {
|
||||
/*
|
||||
* We can only accelerate non-Color MaskFill operations if
|
||||
* all of the following conditions hold true:
|
||||
* - there is an implementation for the given paintState
|
||||
* - the current Paint can be accelerated for this destination
|
||||
* - multitexturing is available (since we need to modulate
|
||||
* the alpha mask texture with the paint texture)
|
||||
*
|
||||
* In all other cases, we return null, in which case the
|
||||
* validation code will choose a more general software-based loop.
|
||||
*/
|
||||
if (!MTLPaints.isValid(sg2d) ||
|
||||
!graphicsConfig.isCapPresent(CAPS_MULTITEXTURE))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return super.getMaskFill(sg2d);
|
||||
}
|
||||
|
||||
public void flush() {
|
||||
invalidate();
|
||||
MTLRenderQueue rq = MTLRenderQueue.getInstance();
|
||||
rq.lock();
|
||||
try {
|
||||
// make sure we have a current context before
|
||||
// disposing the native resources (e.g. texture object)
|
||||
MTLContext.setScratchSurface(graphicsConfig);
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if OpenGL textures can have non-power-of-two dimensions
|
||||
* when using the basic GL_TEXTURE_2D target.
|
||||
*/
|
||||
boolean isTexNonPow2Available() {
|
||||
return graphicsConfig.isCapPresent(CAPS_TEXNONPOW2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if OpenGL textures can have non-power-of-two dimensions
|
||||
* when using the GL_TEXTURE_RECTANGLE_ARB target (only available when the
|
||||
* GL_ARB_texture_rectangle extension is present).
|
||||
*/
|
||||
boolean isTexRectAvailable() {
|
||||
return graphicsConfig.isCapPresent(CAPS_EXT_TEXRECT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the surface is an on-screen window surface or
|
||||
* a FBO texture attached to an on-screen CALayer.
|
||||
*
|
||||
* Needed by Mac OS X port.
|
||||
*/
|
||||
public boolean isOnScreen() {
|
||||
return getType() == WINDOW;
|
||||
}
|
||||
|
||||
private native int getTextureTarget(long pData);
|
||||
|
||||
private native int getTextureID(long pData);
|
||||
|
||||
/**
|
||||
* If this surface is backed by a texture object, returns the target
|
||||
* for that texture (either GL_TEXTURE_2D or GL_TEXTURE_RECTANGLE_ARB).
|
||||
* Otherwise, this method will return zero.
|
||||
*/
|
||||
public final int getTextureTarget() {
|
||||
return getTextureTarget(getNativeOps());
|
||||
}
|
||||
|
||||
/**
|
||||
* If this surface is backed by a texture object, returns the texture ID
|
||||
* for that texture.
|
||||
* Otherwise, this method will return zero.
|
||||
*/
|
||||
public final int getTextureID() {
|
||||
return getTextureID(getNativeOps());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns native resource of specified {@code resType} associated with
|
||||
* this surface.
|
||||
*
|
||||
* Specifically, for {@code MTLSurfaceData} this method returns the
|
||||
* the following:
|
||||
* <pre>
|
||||
* TEXTURE - texture id
|
||||
* </pre>
|
||||
*
|
||||
* Note: the resource returned by this method is only valid on the rendering
|
||||
* thread.
|
||||
*
|
||||
* @return native resource of specified type or 0L if
|
||||
* such resource doesn't exist or can not be retrieved.
|
||||
* @see AccelSurface#getNativeResource
|
||||
*/
|
||||
public long getNativeResource(int resType) {
|
||||
if (resType == TEXTURE) {
|
||||
return getTextureID();
|
||||
}
|
||||
return 0L;
|
||||
}
|
||||
|
||||
public Raster getRaster(int x, int y, int w, int h) {
|
||||
throw new InternalError("not implemented yet");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean copyArea(SunGraphics2D sg2d, int x, int y, int w, int h,
|
||||
int dx, int dy) {
|
||||
if (sg2d.compositeState >= SunGraphics2D.COMP_XOR) {
|
||||
return false;
|
||||
}
|
||||
mtlRenderPipe.copyArea(sg2d, x, y, w, h, dx, dy);
|
||||
return true;
|
||||
}
|
||||
|
||||
public Rectangle getNativeBounds() {
|
||||
MTLRenderQueue rq = MTLRenderQueue.getInstance();
|
||||
rq.lock();
|
||||
try {
|
||||
return new Rectangle(nativeWidth, nativeHeight);
|
||||
} finally {
|
||||
rq.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public static class MTLWindowSurfaceData extends MTLSurfaceData {
|
||||
|
||||
public MTLWindowSurfaceData(CPlatformView pView,
|
||||
MTLGraphicsConfig gc) {
|
||||
super(pView, gc, gc.getColorModel(), WINDOW, 0, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SurfaceData getReplacement() {
|
||||
return pView.getSurfaceData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rectangle getBounds() {
|
||||
Rectangle r = pView.getBounds();
|
||||
return new Rectangle(0, 0, r.width, r.height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns destination Component associated with this SurfaceData.
|
||||
*/
|
||||
@Override
|
||||
public Object getDestination() {
|
||||
return pView.getDestination();
|
||||
}
|
||||
|
||||
public void validate() {
|
||||
MTLRenderQueue rq = MTLRenderQueue.getInstance();
|
||||
rq.lock();
|
||||
try {
|
||||
rq.flushAndInvokeNow(() -> {
|
||||
Rectangle peerBounds = pView.getBounds();
|
||||
validate(0, 0, peerBounds.width, peerBounds.height, pView.isOpaque());
|
||||
});
|
||||
} finally {
|
||||
rq.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidate() {
|
||||
super.invalidate();
|
||||
clearWindow();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A surface which implements an intermediate buffer between
|
||||
* the Java2D flusher thread and the AppKit thread.
|
||||
*
|
||||
* This surface serves as a buffer attached to a MTLLayer and
|
||||
* the layer redirects all painting to the buffer's graphics.
|
||||
*/
|
||||
public static class MTLLayerSurfaceData extends MTLSurfaceData {
|
||||
|
||||
private MTLLayer layer;
|
||||
|
||||
public MTLLayerSurfaceData(MTLLayer layer, MTLGraphicsConfig gc,
|
||||
int width, int height) {
|
||||
super(layer, gc, gc.getColorModel(), RT_TEXTURE, width, height);
|
||||
this.layer = layer;
|
||||
initSurface(this.width, this.height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SurfaceData getReplacement() {
|
||||
return layer.getSurfaceData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOnScreen() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rectangle getBounds() {
|
||||
return new Rectangle(width, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getDestination() {
|
||||
return layer.getDestination();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTransparency() {
|
||||
return layer.getTransparency();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidate() {
|
||||
super.invalidate();
|
||||
clearWindow();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A surface which implements a v-synced flip back-buffer with COPIED
|
||||
* FlipContents.
|
||||
*
|
||||
* This surface serves as a back-buffer to the outside world, while it is
|
||||
* actually an offscreen surface. When the BufferStrategy this surface
|
||||
* belongs to is showed, it is first copied to the real private
|
||||
* FLIP_BACKBUFFER, which is then flipped.
|
||||
*/
|
||||
public static class MTLVSyncOffScreenSurfaceData extends
|
||||
MTLOffScreenSurfaceData {
|
||||
private MTLOffScreenSurfaceData flipSurface;
|
||||
|
||||
public MTLVSyncOffScreenSurfaceData(CPlatformView pView,
|
||||
MTLGraphicsConfig gc, int width, int height, Image image,
|
||||
ColorModel cm, int type) {
|
||||
super(pView, gc, width, height, image, cm, type);
|
||||
flipSurface = MTLSurfaceData.createData(pView, image,
|
||||
FLIP_BACKBUFFER);
|
||||
}
|
||||
|
||||
public SurfaceData getFlipSurface() {
|
||||
return flipSurface;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
flipSurface.flush();
|
||||
super.flush();
|
||||
}
|
||||
}
|
||||
|
||||
public static class MTLOffScreenSurfaceData extends MTLSurfaceData {
|
||||
private Image offscreenImage;
|
||||
|
||||
public MTLOffScreenSurfaceData(CPlatformView pView,
|
||||
MTLGraphicsConfig gc, int width, int height, Image image,
|
||||
ColorModel cm, int type) {
|
||||
super(pView, gc, cm, type, width, height);
|
||||
offscreenImage = image;
|
||||
initSurface(this.width, this.height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SurfaceData getReplacement() {
|
||||
return restoreContents(offscreenImage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rectangle getBounds() {
|
||||
if (type == FLIP_BACKBUFFER) {
|
||||
Rectangle r = pView.getBounds();
|
||||
return new Rectangle(0, 0, r.width, r.height);
|
||||
} else {
|
||||
return new Rectangle(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns destination Image associated with this SurfaceData.
|
||||
*/
|
||||
@Override
|
||||
public Object getDestination() {
|
||||
return offscreenImage;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// additional cleanup
|
||||
private static native void destroyCGLContext(long ctx);
|
||||
|
||||
public static void destroyOGLContext(long ctx) {
|
||||
if (ctx != 0L) {
|
||||
destroyCGLContext(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
public static void dispose(long pData, long pConfigInfo) {
|
||||
MTLGraphicsConfig.deRefPConfigInfo(pConfigInfo);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
package sun.java2d.metal;
|
||||
|
||||
import sun.java2d.SurfaceData;
|
||||
import sun.java2d.SurfaceDataProxy;
|
||||
import sun.java2d.loops.CompositeType;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* The proxy class contains the logic for when to replace a
|
||||
* SurfaceData with a cached OGL Texture and the code to create
|
||||
* the accelerated surfaces.
|
||||
*/
|
||||
public class MTLSurfaceDataProxy extends SurfaceDataProxy {
|
||||
public static SurfaceDataProxy createProxy(SurfaceData srcData,
|
||||
MTLGraphicsConfig dstConfig)
|
||||
{
|
||||
if (srcData instanceof MTLSurfaceData) {
|
||||
// srcData must be a VolatileImage which either matches
|
||||
// our pixel format or not - either way we do not cache it...
|
||||
return UNCACHED;
|
||||
}
|
||||
|
||||
return new MTLSurfaceDataProxy(dstConfig, srcData.getTransparency());
|
||||
}
|
||||
|
||||
MTLGraphicsConfig oglgc;
|
||||
int transparency;
|
||||
|
||||
public MTLSurfaceDataProxy(MTLGraphicsConfig oglgc, int transparency) {
|
||||
this.oglgc = oglgc;
|
||||
this.transparency = transparency;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SurfaceData validateSurfaceData(SurfaceData srcData,
|
||||
SurfaceData cachedData,
|
||||
int w, int h)
|
||||
{
|
||||
if (cachedData == null) {
|
||||
try {
|
||||
cachedData = oglgc.createManagedSurface(w, h, transparency);
|
||||
} catch (OutOfMemoryError er) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return cachedData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupportedOperation(SurfaceData srcData,
|
||||
int txtype,
|
||||
CompositeType comp,
|
||||
Color bgColor)
|
||||
{
|
||||
return comp.isDerivedFrom(CompositeType.AnyAlpha) &&
|
||||
(bgColor == null || transparency == Transparency.OPAQUE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2019, 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.
|
||||
*/
|
||||
|
||||
package sun.java2d.metal;
|
||||
|
||||
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.*;
|
||||
|
||||
class MTLTextRenderer extends BufferedTextPipe {
|
||||
|
||||
MTLTextRenderer(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();
|
||||
MTLSurfaceData oglDst = (MTLSurfaceData)sg2d.surfaceData;
|
||||
MTLContext.validateContext(oglDst, oglDst,
|
||||
sg2d.getCompClip(), comp,
|
||||
null, sg2d.paint, sg2d,
|
||||
MTLContext.NO_CONTEXT_FLAGS);
|
||||
}
|
||||
|
||||
MTLTextRenderer traceWrap() {
|
||||
return new Tracer(this);
|
||||
}
|
||||
|
||||
private static class Tracer extends MTLTextRenderer {
|
||||
Tracer(MTLTextRenderer mtltr) {
|
||||
super(mtltr.rq);
|
||||
}
|
||||
protected void drawGlyphList(SunGraphics2D sg2d, GlyphList gl) {
|
||||
GraphicsPrimitive.tracePrimitive("MTLDrawGlyphs");
|
||||
super.drawGlyphList(sg2d, gl);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,326 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2019, 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.
|
||||
*/
|
||||
|
||||
package sun.java2d.metal;
|
||||
|
||||
import sun.java2d.SunGraphics2D;
|
||||
import sun.java2d.SurfaceData;
|
||||
import sun.java2d.pipe.Region;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* This class contains a number of static utility methods that may be
|
||||
* called (via reflection) by a third-party library in order
|
||||
* to interoperate with the metal-based Java 2D pipeline.
|
||||
*
|
||||
*/
|
||||
class MTLUtilities {
|
||||
|
||||
/**
|
||||
* These OGL-specific surface type constants are the same as those
|
||||
* defined in the MTLSurfaceData class and are duplicated here so that
|
||||
* clients of this API can access them more easily via reflection.
|
||||
*/
|
||||
public static final int UNDEFINED = MTLSurfaceData.UNDEFINED;
|
||||
public static final int WINDOW = MTLSurfaceData.WINDOW;
|
||||
public static final int TEXTURE = MTLSurfaceData.TEXTURE;
|
||||
public static final int FLIP_BACKBUFFER = MTLSurfaceData.FLIP_BACKBUFFER;
|
||||
public static final int RT_TEXTURE = MTLSurfaceData.RT_TEXTURE;
|
||||
|
||||
private MTLUtilities() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the current thread is the OGL QueueFlusher thread.
|
||||
*/
|
||||
public static boolean isQueueFlusherThread() {
|
||||
return MTLRenderQueue.isQueueFlusherThread();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the given Runnable on the MTL QueueFlusher thread with the
|
||||
* MTL context corresponding to the given Graphics object made
|
||||
* current. It is legal for MTL code executed in the given
|
||||
* Runnable to change the current MTL context; it will be reset
|
||||
* once the Runnable completes. No guarantees are made as to the
|
||||
* state of the MTL context of the Graphics object; for
|
||||
*
|
||||
* In order to avoid deadlock, it is important that the given Runnable
|
||||
* does not attempt to acquire the AWT lock, as that will be handled
|
||||
* automatically as part of the {@code rq.flushAndInvokeNow()} step.
|
||||
*
|
||||
* @param g the Graphics object for the corresponding destination surface;
|
||||
* if null, the step making a context current to the destination surface
|
||||
* will be skipped
|
||||
* @param r the action to be performed on the QFT; cannot be null
|
||||
* @return true if the operation completed successfully, or false if
|
||||
* there was any problem making a context current to the surface
|
||||
* associated with the given Graphics object
|
||||
*/
|
||||
public static boolean invokeWithMTLContextCurrent(Graphics g, Runnable r) {
|
||||
MTLRenderQueue rq = MTLRenderQueue.getInstance();
|
||||
rq.lock();
|
||||
try {
|
||||
if (g != null) {
|
||||
if (!(g instanceof SunGraphics2D)) {
|
||||
return false;
|
||||
}
|
||||
SurfaceData sData = ((SunGraphics2D)g).surfaceData;
|
||||
if (!(sData instanceof MTLSurfaceData)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// make a context current to the destination surface
|
||||
MTLContext.validateContext((MTLSurfaceData)sData);
|
||||
}
|
||||
|
||||
// invoke the given runnable on the QFT
|
||||
rq.flushAndInvokeNow(r);
|
||||
|
||||
// invalidate the current context so that the next time we render
|
||||
// with Java 2D, the context state will be completely revalidated
|
||||
MTLContext.invalidateCurrentContext();
|
||||
} finally {
|
||||
rq.unlock();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the given Runnable on the MTL QueueFlusher thread with the
|
||||
* "shared" MTL context (corresponding to the given
|
||||
* GraphicsConfiguration object) made current. This method is typically
|
||||
* used when the Runnable needs a current context to complete its
|
||||
* operation, but does not require that the context be made current to
|
||||
* a particular surface. For example, an application may call this
|
||||
* method so that the given Runnable can query the OpenGL capabilities
|
||||
* of the given GraphicsConfiguration, without making a context current
|
||||
* to a dummy surface (or similar hacky techniques).
|
||||
*
|
||||
* In order to avoid deadlock, it is important that the given Runnable
|
||||
* does not attempt to acquire the AWT lock, as that will be handled
|
||||
* automatically as part of the {@code rq.flushAndInvokeNow()} step.
|
||||
*
|
||||
* @param config the GraphicsConfiguration object whose "shared"
|
||||
* context will be made current during this operation; if this value is
|
||||
* null or if MTL is not enabled for the GraphicsConfiguration, this
|
||||
* method will return false
|
||||
* @param r the action to be performed on the QFT; cannot be null
|
||||
* @return true if the operation completed successfully, or false if
|
||||
* there was any problem making the shared context current
|
||||
*/
|
||||
public static boolean
|
||||
invokeWithMTLSharedContextCurrent(GraphicsConfiguration config,
|
||||
Runnable r)
|
||||
{
|
||||
if (!(config instanceof MTLGraphicsConfig)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MTLRenderQueue rq = MTLRenderQueue.getInstance();
|
||||
rq.lock();
|
||||
try {
|
||||
// make the "shared" context current for the given GraphicsConfig
|
||||
MTLContext.setScratchSurface((MTLGraphicsConfig)config);
|
||||
|
||||
// invoke the given runnable on the QFT
|
||||
rq.flushAndInvokeNow(r);
|
||||
|
||||
// invalidate the current context so that the next time we render
|
||||
// with Java 2D, the context state will be completely revalidated
|
||||
MTLContext.invalidateCurrentContext();
|
||||
} finally {
|
||||
rq.unlock();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Rectangle describing the MTL viewport on the
|
||||
* Java 2D surface associated with the given Graphics object and
|
||||
* component width and height. When a third-party library is
|
||||
* performing MTL rendering directly into the visible region of
|
||||
* the associated surface, this viewport helps the application
|
||||
* position the MTL output correctly on that surface.
|
||||
*
|
||||
* Note that the x/y values in the returned Rectangle object represent
|
||||
* the lower-left corner of the viewport region, relative to the
|
||||
* lower-left corner of the given surface.
|
||||
*
|
||||
* @param g the Graphics object for the corresponding destination surface;
|
||||
* cannot be null
|
||||
* @param componentWidth width of the component to be painted
|
||||
* @param componentHeight height of the component to be painted
|
||||
* @return a Rectangle describing the MTL viewport for the given
|
||||
* destination surface and component dimensions, or null if the given
|
||||
* Graphics object is invalid
|
||||
*/
|
||||
public static Rectangle getMTLViewport(Graphics g,
|
||||
int componentWidth,
|
||||
int componentHeight)
|
||||
{
|
||||
if (!(g instanceof SunGraphics2D)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
SunGraphics2D sg2d = (SunGraphics2D)g;
|
||||
SurfaceData sData = sg2d.surfaceData;
|
||||
|
||||
// this is the upper-left origin of the region to be painted,
|
||||
// relative to the upper-left origin of the surface
|
||||
// (in Java2D coordinates)
|
||||
int x0 = sg2d.transX;
|
||||
int y0 = sg2d.transY;
|
||||
|
||||
// this is the lower-left origin of the region to be painted,
|
||||
// relative to the lower-left origin of the surface
|
||||
// (in OpenGL coordinates)
|
||||
Rectangle surfaceBounds = sData.getBounds();
|
||||
int x1 = x0;
|
||||
int y1 = surfaceBounds.height - (y0 + componentHeight);
|
||||
|
||||
return new Rectangle(x1, y1, componentWidth, componentHeight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Rectangle describing the MTL scissor box on the
|
||||
* Java 2D surface associated with the given Graphics object. When a
|
||||
* third-party library is performing MTL rendering directly
|
||||
* into the visible region of the associated surface, this scissor box
|
||||
* must be set to avoid drawing over existing rendering results.
|
||||
*
|
||||
* Note that the x/y values in the returned Rectangle object represent
|
||||
* the lower-left corner of the scissor region, relative to the
|
||||
* lower-left corner of the given surface.
|
||||
*
|
||||
* @param g the Graphics object for the corresponding destination surface;
|
||||
* cannot be null
|
||||
* @return a Rectangle describing the MTL scissor box for the given
|
||||
* Graphics object and corresponding destination surface, or null if the
|
||||
* given Graphics object is invalid or the clip region is non-rectangular
|
||||
*/
|
||||
public static Rectangle getOGLScissorBox(Graphics g) {
|
||||
if (!(g instanceof SunGraphics2D)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
SunGraphics2D sg2d = (SunGraphics2D)g;
|
||||
SurfaceData sData = sg2d.surfaceData;
|
||||
Region r = sg2d.getCompClip();
|
||||
if (!r.isRectangular()) {
|
||||
// caller probably doesn't know how to handle shape clip
|
||||
// appropriately, so just return null (Swing currently never
|
||||
// sets a shape clip, but that could change in the future)
|
||||
return null;
|
||||
}
|
||||
|
||||
// this is the upper-left origin of the scissor box relative to the
|
||||
// upper-left origin of the surface (in Java 2D coordinates)
|
||||
int x0 = r.getLoX();
|
||||
int y0 = r.getLoY();
|
||||
|
||||
// this is the width and height of the scissor region
|
||||
int w = r.getWidth();
|
||||
int h = r.getHeight();
|
||||
|
||||
// this is the lower-left origin of the scissor box relative to the
|
||||
// lower-left origin of the surface (in OpenGL coordinates)
|
||||
Rectangle surfaceBounds = sData.getBounds();
|
||||
int x1 = x0;
|
||||
int y1 = surfaceBounds.height - (y0 + h);
|
||||
|
||||
return new Rectangle(x1, y1, w, h);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an Object identifier for the Java 2D surface associated with
|
||||
* the given Graphics object. This identifier may be used to determine
|
||||
* whether the surface has changed since the last invocation of this
|
||||
* operation, and thereby whether the MTL state corresponding to the
|
||||
* old surface must be destroyed and recreated.
|
||||
*
|
||||
* @param g the Graphics object for the corresponding destination surface;
|
||||
* cannot be null
|
||||
* @return an identifier for the surface associated with the given
|
||||
* Graphics object, or null if the given Graphics object is invalid
|
||||
*/
|
||||
public static Object getMTLSurfaceIdentifier(Graphics g) {
|
||||
if (!(g instanceof SunGraphics2D)) {
|
||||
return null;
|
||||
}
|
||||
return ((SunGraphics2D)g).surfaceData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns one of the MTL-specific surface type constants (defined in
|
||||
* this class), which describes the surface associated with the given
|
||||
* Graphics object.
|
||||
*
|
||||
* @param g the Graphics object for the corresponding destination surface;
|
||||
* cannot be null
|
||||
* @return a constant that describes the surface associated with the
|
||||
* given Graphics object; if the given Graphics object is invalid (i.e.
|
||||
* is not associated with an OpenGL surface) this method will return
|
||||
* {@code MTLUtilities.UNDEFINED}
|
||||
*/
|
||||
public static int getMTLSurfaceType(Graphics g) {
|
||||
if (!(g instanceof SunGraphics2D)) {
|
||||
return UNDEFINED;
|
||||
}
|
||||
SurfaceData sData = ((SunGraphics2D)g).surfaceData;
|
||||
if (!(sData instanceof MTLSurfaceData)) {
|
||||
return UNDEFINED;
|
||||
}
|
||||
return ((MTLSurfaceData)sData).getType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the MTL texture target constant (either GL_TEXTURE_2D
|
||||
* or GL_TEXTURE_RECTANGLE_ARB) for the surface associated with the
|
||||
* given Graphics object. This method is only useful for those surface
|
||||
* types that are backed by an MTL texture, namely {@code TEXTURE},
|
||||
* {@code RT_TEXTURE}, and (on Windows only) {@code PBUFFER}.
|
||||
*
|
||||
* @param g the Graphics object for the corresponding destination surface;
|
||||
* cannot be null
|
||||
* @return the texture target constant for the surface associated with the
|
||||
* given Graphics object; if the given Graphics object is invalid (i.e.
|
||||
* is not associated with an MTL surface), or the associated surface
|
||||
* is not backed by an OpenGL texture, this method will return zero.
|
||||
*/
|
||||
public static int getMTLTextureType(Graphics g) {
|
||||
if (!(g instanceof SunGraphics2D)) {
|
||||
return 0;
|
||||
}
|
||||
SurfaceData sData = ((SunGraphics2D)g).surfaceData;
|
||||
if (!(sData instanceof MTLSurfaceData)) {
|
||||
return 0;
|
||||
}
|
||||
return ((MTLSurfaceData)sData).getTextureTarget();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
package sun.java2d.metal;
|
||||
|
||||
import sun.awt.AWTAccessor;
|
||||
import sun.awt.AWTAccessor.ComponentAccessor;
|
||||
import sun.awt.image.SunVolatileImage;
|
||||
import sun.awt.image.VolatileSurfaceManager;
|
||||
import sun.java2d.BackBufferCapsProvider;
|
||||
import sun.java2d.SurfaceData;
|
||||
import sun.java2d.opengl.OGLSurfaceData;
|
||||
import sun.java2d.pipe.hw.ExtendedBufferCapabilities;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.peer.ComponentPeer;
|
||||
|
||||
import static java.awt.BufferCapabilities.FlipContents.COPIED;
|
||||
import static sun.java2d.opengl.OGLContext.OGLContextCaps.CAPS_EXT_FBOBJECT;
|
||||
import static sun.java2d.pipe.hw.ExtendedBufferCapabilities.VSyncType.VSYNC_ON;
|
||||
|
||||
public class MTLVolatileSurfaceManager extends VolatileSurfaceManager {
|
||||
|
||||
private final boolean accelerationEnabled;
|
||||
|
||||
public MTLVolatileSurfaceManager(SunVolatileImage vImg, Object context) {
|
||||
super(vImg, context);
|
||||
|
||||
/*
|
||||
* We will attempt to accelerate this image only under the
|
||||
* following conditions:
|
||||
* - the image is not bitmask AND the GraphicsConfig supports the FBO
|
||||
* extension
|
||||
*/
|
||||
int transparency = vImg.getTransparency();
|
||||
MTLGraphicsConfig gc = (MTLGraphicsConfig) vImg.getGraphicsConfig();
|
||||
accelerationEnabled = true;
|
||||
//gc.isCapPresent(CAPS_EXT_FBOBJECT)
|
||||
//&& transparency != Transparency.BITMASK;
|
||||
}
|
||||
|
||||
protected boolean isAccelerationEnabled() {
|
||||
return accelerationEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a FBO-based SurfaceData object (or init the backbuffer
|
||||
* of an existing window if this is a double buffered GraphicsConfig)
|
||||
*/
|
||||
protected SurfaceData initAcceleratedSurface() {
|
||||
SurfaceData sData = null;
|
||||
Component comp = vImg.getComponent();
|
||||
final ComponentAccessor acc = AWTAccessor.getComponentAccessor();
|
||||
final ComponentPeer peer = (comp != null) ? acc.getPeer(comp) : null;
|
||||
|
||||
try {
|
||||
boolean createVSynced = false;
|
||||
boolean forceback = false;
|
||||
if (context instanceof Boolean) {
|
||||
forceback = ((Boolean)context).booleanValue();
|
||||
if (forceback && peer instanceof BackBufferCapsProvider) {
|
||||
BackBufferCapsProvider provider =
|
||||
(BackBufferCapsProvider)peer;
|
||||
BufferCapabilities caps = provider.getBackBufferCaps();
|
||||
if (caps instanceof ExtendedBufferCapabilities) {
|
||||
ExtendedBufferCapabilities ebc =
|
||||
(ExtendedBufferCapabilities)caps;
|
||||
if (ebc.getVSync() == VSYNC_ON &&
|
||||
ebc.getFlipContents() == COPIED)
|
||||
{
|
||||
createVSynced = true;
|
||||
forceback = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (forceback) {
|
||||
// peer must be non-null in this case
|
||||
// TODO: modify parameter to delegate
|
||||
// sData = MTLSurfaceData.createData(peer, vImg, FLIP_BACKBUFFER);
|
||||
} else {
|
||||
MTLGraphicsConfig gc =
|
||||
(MTLGraphicsConfig)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 == OGLSurfaceData.UNDEFINED) {
|
||||
type = OGLSurfaceData.FBOBJECT;
|
||||
}
|
||||
if (createVSynced) {
|
||||
// TODO: modify parameter to delegate
|
||||
// sData = MTLSurfaceData.createData(peer, vImg, type);
|
||||
} else {
|
||||
sData = MTLSurfaceData.createData(gc,
|
||||
vImg.getWidth(),
|
||||
vImg.getHeight(),
|
||||
cm, vImg, type);
|
||||
}
|
||||
}
|
||||
} catch (NullPointerException ex) {
|
||||
sData = null;
|
||||
} catch (OutOfMemoryError er) {
|
||||
sData = null;
|
||||
}
|
||||
|
||||
return sData;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isConfigValid(GraphicsConfiguration gc) {
|
||||
return ((gc == null) || (gc == vImg.getGraphicsConfig()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initContents() {
|
||||
if (vImg.getForcedAccelSurfaceType() != OGLSurfaceData.TEXTURE) {
|
||||
super.initContents();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@ import sun.java2d.pipe.hw.AccelSurface;
|
||||
import sun.java2d.pipe.hw.AccelTypedVolatileImage;
|
||||
import sun.java2d.pipe.hw.ContextCapabilities;
|
||||
import sun.lwawt.LWComponentPeer;
|
||||
import sun.lwawt.macosx.CFRetainedResource;
|
||||
import sun.lwawt.macosx.CPlatformView;
|
||||
|
||||
import static sun.java2d.opengl.OGLContext.OGLContextCaps.CAPS_DOUBLEBUFFERED;
|
||||
@@ -264,8 +265,8 @@ public final class CGLGraphicsConfig extends CGraphicsConfig
|
||||
}
|
||||
|
||||
@Override
|
||||
public SurfaceData createSurfaceData(CGLLayer layer) {
|
||||
return CGLSurfaceData.createData(layer);
|
||||
public SurfaceData createSurfaceData(CFRetainedResource layer) {
|
||||
return CGLSurfaceData.createData((CGLLayer) layer);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -249,7 +249,7 @@ public abstract class CGLSurfaceData extends OGLSurfaceData {
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isOnScreen() {
|
||||
public boolean isOnScreen() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -54,9 +54,12 @@ import sun.awt.image.SunVolatileImage;
|
||||
import sun.awt.image.ToolkitImage;
|
||||
|
||||
import sun.java2d.SunGraphics2D;
|
||||
import sun.java2d.macos.MacOSFlags;
|
||||
import sun.java2d.metal.MTLRenderQueue;
|
||||
import sun.java2d.opengl.OGLRenderQueue;
|
||||
import sun.java2d.pipe.Region;
|
||||
|
||||
import sun.java2d.pipe.RenderQueue;
|
||||
import sun.util.logging.PlatformLogger;
|
||||
|
||||
import javax.swing.JComponent;
|
||||
@@ -1418,7 +1421,8 @@ public abstract class LWComponentPeer<T extends Component, D extends JComponent>
|
||||
}
|
||||
|
||||
protected static final void flushOnscreenGraphics(){
|
||||
final OGLRenderQueue rq = OGLRenderQueue.getInstance();
|
||||
RenderQueue rq = MacOSFlags.isMetalEnabled() ?
|
||||
MTLRenderQueue.getInstance() : OGLRenderQueue.getInstance();
|
||||
rq.lock();
|
||||
try {
|
||||
rq.flushNow();
|
||||
|
||||
@@ -33,6 +33,9 @@ import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import sun.awt.CGraphicsConfig;
|
||||
import sun.awt.CGraphicsEnvironment;
|
||||
import sun.java2d.macos.MacOSFlags;
|
||||
import sun.java2d.metal.MTLLayer;
|
||||
import sun.java2d.metal.MTLSurfaceData;
|
||||
import sun.lwawt.LWWindowPeer;
|
||||
|
||||
import sun.java2d.SurfaceData;
|
||||
@@ -48,7 +51,7 @@ public class CPlatformView extends CFRetainedResource {
|
||||
|
||||
private LWWindowPeer peer;
|
||||
private SurfaceData surfaceData;
|
||||
private CGLLayer windowLayer;
|
||||
private CFRetainedResource windowLayer;
|
||||
private CPlatformResponder responder;
|
||||
|
||||
public CPlatformView() {
|
||||
@@ -59,7 +62,7 @@ public class CPlatformView extends CFRetainedResource {
|
||||
initializeBase(peer, responder);
|
||||
|
||||
if (!LWCToolkit.getSunAwtDisableCALayers()) {
|
||||
this.windowLayer = createCGLayer();
|
||||
this.windowLayer = MacOSFlags.isMetalEnabled()? createMTLLayer() : createCGLayer();
|
||||
}
|
||||
setPtr(nativeCreateView(0, 0, 0, 0, getWindowLayerPtr()));
|
||||
}
|
||||
@@ -68,6 +71,11 @@ public class CPlatformView extends CFRetainedResource {
|
||||
return new CGLLayer(peer);
|
||||
}
|
||||
|
||||
public MTLLayer createMTLLayer() {
|
||||
return new MTLLayer(peer);
|
||||
}
|
||||
|
||||
|
||||
protected void initializeBase(LWWindowPeer peer, CPlatformResponder responder) {
|
||||
this.peer = peer;
|
||||
this.responder = responder;
|
||||
@@ -107,7 +115,10 @@ public class CPlatformView extends CFRetainedResource {
|
||||
// ----------------------------------------------------------------------
|
||||
public SurfaceData replaceSurfaceData() {
|
||||
if (!LWCToolkit.getSunAwtDisableCALayers()) {
|
||||
surfaceData = windowLayer.replaceSurfaceData();
|
||||
surfaceData = (MacOSFlags.isMetalEnabled()) ?
|
||||
((MTLLayer)windowLayer).replaceSurfaceData() :
|
||||
((CGLLayer)windowLayer).replaceSurfaceData()
|
||||
;
|
||||
} else {
|
||||
if (surfaceData == null) {
|
||||
CGraphicsConfig graphicsConfig = (CGraphicsConfig)getGraphicsConfiguration();
|
||||
@@ -121,7 +132,11 @@ public class CPlatformView extends CFRetainedResource {
|
||||
|
||||
private void validateSurface() {
|
||||
if (surfaceData != null) {
|
||||
((CGLSurfaceData)surfaceData).validate();
|
||||
if (MacOSFlags.isMetalEnabled()) {
|
||||
((MTLSurfaceData) surfaceData).validate();
|
||||
} else {
|
||||
((CGLSurfaceData) surfaceData).validate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,7 +158,9 @@ public class CPlatformView extends CFRetainedResource {
|
||||
|
||||
public long getWindowLayerPtr() {
|
||||
if (!LWCToolkit.getSunAwtDisableCALayers()) {
|
||||
return windowLayer.getPointer();
|
||||
return MacOSFlags.isMetalEnabled() ?
|
||||
((MTLLayer)windowLayer).getPointer() :
|
||||
((CGLLayer)windowLayer).getPointer();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ import sun.awt.AWTAccessor;
|
||||
import sun.awt.AWTAccessor.ComponentAccessor;
|
||||
import sun.awt.AWTAccessor.WindowAccessor;
|
||||
import sun.java2d.SurfaceData;
|
||||
import sun.java2d.metal.MTLSurfaceData;
|
||||
import sun.java2d.opengl.CGLSurfaceData;
|
||||
import sun.lwawt.LWLightweightFramePeer;
|
||||
import sun.lwawt.LWToolkit;
|
||||
@@ -1056,6 +1057,8 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo
|
||||
SurfaceData surfaceData = getSurfaceData();
|
||||
if (surfaceData instanceof CGLSurfaceData) {
|
||||
((CGLSurfaceData)surfaceData).validate();
|
||||
} else if (surfaceData instanceof MTLSurfaceData) {
|
||||
((MTLSurfaceData)surfaceData).validate();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ import sun.awt.AWTAccessor;
|
||||
import sun.awt.IconInfo;
|
||||
import sun.java2d.SunGraphics2D;
|
||||
import sun.java2d.SurfaceData;
|
||||
import sun.java2d.metal.MTLLayer;
|
||||
import sun.java2d.opengl.CGLLayer;
|
||||
import sun.lwawt.LWWindowPeer;
|
||||
import sun.lwawt.PlatformEventNotifier;
|
||||
@@ -300,6 +301,23 @@ public final class CWarningWindow extends CPlatformWindow
|
||||
}
|
||||
};
|
||||
}
|
||||
public MTLLayer createMTLLayer() {
|
||||
return new MTLLayer(null) {
|
||||
public Rectangle getBounds() {
|
||||
return CWarningWindow.this.getBounds();
|
||||
}
|
||||
|
||||
public GraphicsConfiguration getGraphicsConfiguration() {
|
||||
LWWindowPeer peer = ownerPeer.get();
|
||||
return peer.getGraphicsConfiguration();
|
||||
}
|
||||
|
||||
public boolean isOpaque() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -108,6 +108,8 @@ import sun.awt.LightweightFrame;
|
||||
import sun.awt.SunToolkit;
|
||||
import sun.awt.datatransfer.DataTransferer;
|
||||
import sun.awt.util.ThreadGroupUtils;
|
||||
import sun.java2d.macos.MacOSFlags;
|
||||
import sun.java2d.metal.MTLRenderQueue;
|
||||
import sun.java2d.opengl.OGLRenderQueue;
|
||||
import sun.lwawt.LWComponentPeer;
|
||||
import sun.lwawt.LWCursorManager;
|
||||
@@ -476,7 +478,11 @@ public final class LWCToolkit extends LWToolkit {
|
||||
@Override
|
||||
public void sync() {
|
||||
// flush the OGL pipeline (this is a no-op if OGL is not enabled)
|
||||
OGLRenderQueue.sync();
|
||||
if (MacOSFlags.isMetalEnabled()) {
|
||||
MTLRenderQueue.sync();
|
||||
} else {
|
||||
OGLRenderQueue.sync();
|
||||
}
|
||||
// setNeedsDisplay() selector was sent to the appropriate CALayer so now
|
||||
// we have to flush the native selectors queue.
|
||||
flushNativeSelectors();
|
||||
|
||||
@@ -24,7 +24,8 @@
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#import <Metal/Metal.h>
|
||||
#import <MetalKit/MetalKit.h>
|
||||
#import "CDragSource.h"
|
||||
#import "CDropTarget.h"
|
||||
|
||||
|
||||
@@ -37,6 +37,8 @@
|
||||
#import <Carbon/Carbon.h>
|
||||
#import <JavaNativeFoundation/JavaNativeFoundation.h>
|
||||
|
||||
jboolean metalEnabled = JNI_FALSE;
|
||||
|
||||
@interface AWTView()
|
||||
@property (retain) CDropTarget *_dropTarget;
|
||||
@property (retain) CDragSource *_dragSource;
|
||||
@@ -52,6 +54,8 @@
|
||||
//#define IM_DEBUG TRUE
|
||||
//#define EXTRA_DEBUG
|
||||
|
||||
#define METAL_DEBUG
|
||||
|
||||
static BOOL shouldUsePressAndHold() {
|
||||
static int shouldUsePressAndHold = -1;
|
||||
if (shouldUsePressAndHold != -1) return shouldUsePressAndHold;
|
||||
@@ -1498,3 +1502,19 @@ JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_CPlatformView_nativeIsViewUnder
|
||||
|
||||
return underMouse;
|
||||
}
|
||||
|
||||
jboolean GetStaticBoolean(JNIEnv *env, jclass fClass, const char *fieldName)
|
||||
{
|
||||
jfieldID fieldID = (*env)->GetStaticFieldID(env, fClass, fieldName, "Z");
|
||||
return (*env)->GetStaticBooleanField(env, fClass, fieldID);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_java2d_macos_MacOSFlags_initNativeFlags(JNIEnv *env,
|
||||
jclass flagsClass)
|
||||
{
|
||||
metalEnabled = GetStaticBoolean(env, flagsClass, "metalEnabled");
|
||||
#ifdef METAL_DEBUG
|
||||
fprintf(stderr, "metalEnabled=%d\n", metalEnabled);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1171,6 +1171,8 @@ JNF_COCOA_ENTER(env);
|
||||
JNF_COCOA_EXIT(env);
|
||||
}
|
||||
|
||||
extern jboolean metalEnabled;
|
||||
|
||||
/*
|
||||
* Class: sun_lwawt_macosx_CPlatformWindow
|
||||
* Method: nativeGetNSWindowInsets
|
||||
@@ -1197,6 +1199,10 @@ JNF_COCOA_ENTER(env);
|
||||
jint left = (jint)(contentRect.origin.x - frame.origin.x);
|
||||
jint bottom = (jint)(contentRect.origin.y - frame.origin.y);
|
||||
jint right = (jint)(frame.size.width - (contentRect.size.width + left));
|
||||
if (metalEnabled == JNI_TRUE) {
|
||||
bottom -= top;
|
||||
top = 0;
|
||||
}
|
||||
|
||||
static JNF_CLASS_CACHE(jc_Insets, "java/awt/Insets");
|
||||
static JNF_CTOR_CACHE(jc_Insets_ctor, jc_Insets, "(IIII)V");
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
#import "LWCToolkit.h"
|
||||
#import "ThreadUtilities.h"
|
||||
#include "GeomUtilities.h"
|
||||
#import <Metal/Metal.h>
|
||||
#import <MetalKit/MetalKit.h>
|
||||
|
||||
#import <JavaNativeFoundation/JavaNativeFoundation.h>
|
||||
|
||||
@@ -383,4 +385,4 @@ JNF_COCOA_ENTER(env);
|
||||
|
||||
JNF_COCOA_EXIT(env);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
60
src/java.desktop/macosx/native/libawt_lwawt/awt/common.h
Normal file
60
src/java.desktop/macosx/native/libawt_lwawt/awt/common.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
#ifndef COMMON_H
|
||||
#define COMMON_H
|
||||
|
||||
#include <simd/SIMD.h>
|
||||
|
||||
#define PGRAM_VERTEX_COUNT 6
|
||||
|
||||
enum VertexAttributes {
|
||||
VertexAttributePosition = 0,
|
||||
VertexAttributeTexPos = 1
|
||||
};
|
||||
|
||||
enum BufferIndex {
|
||||
MeshVertexBuffer = 0,
|
||||
FrameUniformBuffer = 1,
|
||||
};
|
||||
|
||||
struct FrameUniforms {
|
||||
vector_float4 color;
|
||||
};
|
||||
|
||||
struct FrameUniformsTransform {
|
||||
matrix_float4x4 transformMatrix;
|
||||
};
|
||||
|
||||
struct Vertex {
|
||||
float position[3];
|
||||
};
|
||||
|
||||
struct TxtVertex {
|
||||
float position[3];
|
||||
float txtpos[2];
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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 <simd/simd.h>
|
||||
#include <metal_stdlib>
|
||||
#include "common.h"
|
||||
|
||||
using namespace metal;
|
||||
|
||||
struct VertexInput {
|
||||
float3 position [[attribute(VertexAttributePosition)]];
|
||||
};
|
||||
|
||||
struct TxtVertexInput {
|
||||
float3 position [[attribute(VertexAttributePosition)]];
|
||||
float2 texCoords [[attribute(VertexAttributeTexPos)]];
|
||||
};
|
||||
|
||||
struct ColShaderInOut {
|
||||
float4 position [[position]];
|
||||
half4 color;
|
||||
};
|
||||
|
||||
struct TxtShaderInOut {
|
||||
float4 position [[position]];
|
||||
float2 texCoords;
|
||||
};
|
||||
|
||||
vertex ColShaderInOut vert_col(VertexInput in [[stage_in]],
|
||||
constant FrameUniforms& uniforms [[buffer(FrameUniformBuffer)]]) {
|
||||
ColShaderInOut out;
|
||||
out.position = float4(in.position, 1.0);
|
||||
out.color = half4(uniforms.color.r, uniforms.color.g, uniforms.color.b, uniforms.color.a);
|
||||
return out;
|
||||
}
|
||||
|
||||
vertex TxtShaderInOut vert_txt(TxtVertexInput in [[stage_in]],
|
||||
constant FrameUniforms& uniforms [[buffer(FrameUniformBuffer)]]) {
|
||||
TxtShaderInOut out;
|
||||
out.position = float4(in.position, 1.0);
|
||||
out.texCoords = in.texCoords;
|
||||
return out;
|
||||
}
|
||||
|
||||
vertex TxtShaderInOut vert_txt_matrix(TxtVertexInput in [[stage_in]],
|
||||
constant FrameUniformsTransform& uniforms [[buffer(FrameUniformBuffer)]]) {
|
||||
TxtShaderInOut out;
|
||||
float4 pos4 = float4(in.position, 1.0);
|
||||
out.position = simd::operator*(uniforms.transformMatrix, pos4);
|
||||
out.position[2] = 0;
|
||||
out.position[3] = 1.f;
|
||||
out.texCoords = in.texCoords;
|
||||
return out;
|
||||
}
|
||||
|
||||
fragment half4 frag_col(ColShaderInOut in [[stage_in]]) {
|
||||
return in.color;
|
||||
}
|
||||
|
||||
fragment half4 frag_txt(
|
||||
TxtShaderInOut vert [[stage_in]],
|
||||
texture2d<float, access::sample> renderTexture [[texture(0)]]
|
||||
)
|
||||
{
|
||||
constexpr sampler textureSampler (mag_filter::linear,
|
||||
min_filter::linear);
|
||||
float4 pixelColor = renderTexture.sample(textureSampler, vert.texCoords);
|
||||
return half4(pixelColor.r, pixelColor.g, pixelColor.b , pixelColor.a);
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
#ifndef MTLBlitLoops_h_Included
|
||||
#define MTLBlitLoops_h_Included
|
||||
|
||||
#include "sun_java2d_metal_MTLBlitLoops.h"
|
||||
#include "MTLSurfaceDataBase.h"
|
||||
#include "MTLContext.h"
|
||||
|
||||
#define OFFSET_SRCTYPE sun_java2d_metal_MTLBlitLoops_OFFSET_SRCTYPE
|
||||
#define OFFSET_HINT sun_java2d_metal_MTLBlitLoops_OFFSET_HINT
|
||||
#define OFFSET_TEXTURE sun_java2d_metal_MTLBlitLoops_OFFSET_TEXTURE
|
||||
#define OFFSET_RTT sun_java2d_metal_MTLBlitLoops_OFFSET_RTT
|
||||
#define OFFSET_XFORM sun_java2d_metal_MTLBlitLoops_OFFSET_XFORM
|
||||
#define OFFSET_ISOBLIT sun_java2d_metal_MTLBlitLoops_OFFSET_ISOBLIT
|
||||
|
||||
void MTLBlitLoops_IsoBlit(JNIEnv *env,
|
||||
MTLContext *mtlc, jlong pSrcOps, jlong pDstOps,
|
||||
jboolean xform, jint hint,
|
||||
jboolean texture, jboolean rtt,
|
||||
jint sx1, jint sy1,
|
||||
jint sx2, jint sy2,
|
||||
jdouble dx1, jdouble dy1,
|
||||
jdouble dx2, jdouble dy2);
|
||||
|
||||
void MTLBlitLoops_Blit(JNIEnv *env,
|
||||
MTLContext *mtlc, jlong pSrcOps, jlong pDstOps,
|
||||
jboolean xform, jint hint,
|
||||
jint srctype, jboolean texture,
|
||||
jint sx1, jint sy1,
|
||||
jint sx2, jint sy2,
|
||||
jdouble dx1, jdouble dy1,
|
||||
jdouble dx2, jdouble dy2);
|
||||
|
||||
void MTLBlitLoops_SurfaceToSwBlit(JNIEnv *env, MTLContext *mtlc,
|
||||
jlong pSrcOps, jlong pDstOps, jint dsttype,
|
||||
jint srcx, jint srcy,
|
||||
jint dstx, jint dsty,
|
||||
jint width, jint height);
|
||||
|
||||
void MTLBlitLoops_CopyArea(JNIEnv *env,
|
||||
MTLContext *mtlc, BMTLSDOps *dstOps,
|
||||
jint x, jint y,
|
||||
jint width, jint height,
|
||||
jint dx, jint dy);
|
||||
|
||||
void MTLBlitTex2Tex(MTLContext *mtlc, id<MTLTexture> src, id<MTLTexture> dest);
|
||||
|
||||
#endif /* MTLBlitLoops_h_Included */
|
||||
@@ -0,0 +1,506 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
#ifndef HEADLESS
|
||||
|
||||
#include <jni.h>
|
||||
#include <jlong.h>
|
||||
|
||||
#include "SurfaceData.h"
|
||||
#include "MTLBlitLoops.h"
|
||||
#include "MTLRenderQueue.h"
|
||||
#include "MTLSurfaceData.h"
|
||||
#include "MTLUtils.h"
|
||||
#include "GraphicsPrimitiveMgr.h"
|
||||
|
||||
#include <stdlib.h> // malloc
|
||||
#include <string.h> // memcpy
|
||||
#include "IntArgbPre.h"
|
||||
|
||||
extern MTLPixelFormat PixelFormats[];
|
||||
extern void J2dTraceImpl(int level, jboolean cr, const char *string, ...);
|
||||
|
||||
void _fillTxQuad(
|
||||
struct TxtVertex * txQuadVerts, jboolean normalizeDst,
|
||||
jint sx1, jint sy1, jint sx2, jint sy2, jint sw, jint sh,
|
||||
jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2, jdouble dw, jdouble dh
|
||||
) {
|
||||
const float nsx1 = sx1/(float)sw;
|
||||
const float nsy1 = sy1/(float)sh;
|
||||
const float nsx2 = sx2/(float)sw;
|
||||
const float nsy2 = sy2/(float)sh;
|
||||
|
||||
if (normalizeDst) {
|
||||
dx1 = (2.0*dx1/dw) - 1.0;
|
||||
dy1 = 2.0*(1.0 - dy1/dh) - 1.0;
|
||||
dx2 = (2.0*dx2/dw) - 1.0;
|
||||
dy2 = 2.0*(1.0 - dy2/dh) - 1.0;
|
||||
}
|
||||
|
||||
txQuadVerts[0].position[0] = dx1;
|
||||
txQuadVerts[0].position[1] = dy1;
|
||||
txQuadVerts[0].position[2] = 0;
|
||||
txQuadVerts[0].txtpos[0] = nsx1;
|
||||
txQuadVerts[0].txtpos[1] = nsy1;
|
||||
|
||||
txQuadVerts[1].position[0] = dx2;
|
||||
txQuadVerts[1].position[1] = dy1;
|
||||
txQuadVerts[1].position[2] = 0;
|
||||
txQuadVerts[1].txtpos[0] = nsx2;
|
||||
txQuadVerts[1].txtpos[1] = nsy1;
|
||||
|
||||
txQuadVerts[2].position[0] = dx2;
|
||||
txQuadVerts[2].position[1] = dy2;
|
||||
txQuadVerts[2].position[2] = 0;
|
||||
txQuadVerts[2].txtpos[0] = nsx2;
|
||||
txQuadVerts[2].txtpos[1] = nsy2;
|
||||
|
||||
txQuadVerts[3].position[0] = dx2;
|
||||
txQuadVerts[3].position[1] = dy2;
|
||||
txQuadVerts[3].position[2] = 0;
|
||||
txQuadVerts[3].txtpos[0] = nsx2;
|
||||
txQuadVerts[3].txtpos[1] = nsy2;
|
||||
|
||||
txQuadVerts[4].position[0] = dx1;
|
||||
txQuadVerts[4].position[1] = dy2;
|
||||
txQuadVerts[4].position[2] = 0;
|
||||
txQuadVerts[4].txtpos[0] = nsx1;
|
||||
txQuadVerts[4].txtpos[1] = nsy2;
|
||||
|
||||
txQuadVerts[5].position[0] = dx1;
|
||||
txQuadVerts[5].position[1] = dy1;
|
||||
txQuadVerts[5].position[2] = 0;
|
||||
txQuadVerts[5].txtpos[0] = nsx1;
|
||||
txQuadVerts[5].txtpos[1] = nsy1;
|
||||
}
|
||||
|
||||
//
|
||||
// DEBUG funcs, will be removed later
|
||||
//
|
||||
|
||||
void _traceRaster(SurfaceDataRasInfo *srcInfo, int width, int height) {
|
||||
char * p = srcInfo->rasBase;
|
||||
for (int y = 0; y < height; ++y) {
|
||||
for (int x = 0; x < width; ++x) {
|
||||
char pix0 = p[y*srcInfo->scanStride + x*4];
|
||||
char pix1 = p[y*srcInfo->scanStride + x*4 + 1];
|
||||
char pix2 = p[y*srcInfo->scanStride + x*4 + 2];
|
||||
char pix3 = p[y*srcInfo->scanStride + x*4 + 3];
|
||||
J2dTrace4(J2D_TRACE_INFO, "[%d,%d,%d,%d], ", pix0, pix1, pix2, pix3);
|
||||
}
|
||||
J2dTraceLn(J2D_TRACE_INFO, "");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inner loop used for copying a source MTL "Surface" (window, pbuffer,
|
||||
* etc.) to a destination OpenGL "Surface". Note that the same surface can
|
||||
* be used as both the source and destination, as is the case in a copyArea()
|
||||
* operation. This method is invoked from MTLBlitLoops_IsoBlit() as well as
|
||||
* MTLBlitLoops_CopyArea().
|
||||
*
|
||||
* The standard glCopyPixels() mechanism is used to copy the source region
|
||||
* into the destination region. If the regions have different dimensions,
|
||||
* the source will be scaled into the destination as appropriate (only
|
||||
* nearest neighbor filtering will be applied for simple scale operations).
|
||||
*/
|
||||
static void
|
||||
MTLBlitSurfaceToSurface(MTLContext *mtlc, BMTLSDOps *srcOps, BMTLSDOps *dstOps,
|
||||
jint sx1, jint sy1, jint sx2, jint sy2,
|
||||
jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLBlitSurfaceToSurface");
|
||||
}
|
||||
|
||||
static void _drawTex2Tex(MTLContext *mtlc,
|
||||
id<MTLTexture> src, id<MTLTexture> dst,
|
||||
jboolean rtt, jint hint,
|
||||
jint sx1, jint sy1, jint sx2, jint sy2,
|
||||
jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
|
||||
{
|
||||
if (mtlc == NULL || src == nil || dst == nil)
|
||||
return;
|
||||
|
||||
// J2dTraceLn2(J2D_TRACE_VERBOSE, "_drawTex2Tex: src tex=%p, dst tex=%p", src, dst);
|
||||
// J2dTraceLn4(J2D_TRACE_VERBOSE, " sw=%d sh=%d dw=%d dh=%d", src.width, src.height, dst.width, dst.height);
|
||||
// J2dTraceLn4(J2D_TRACE_VERBOSE, " sx1=%d sy1=%d sx2=%d sy2=%d", sx1, sy1, sx2, sy2);
|
||||
// J2dTraceLn4(J2D_TRACE_VERBOSE, " dx1=%f dy1=%f dx2=%f dy2=%f", dx1, dy1, dx2, dy2);
|
||||
|
||||
id<MTLRenderCommandEncoder> encoder = MTLContext_CreateSamplingEncoder(mtlc, dst);
|
||||
|
||||
|
||||
const jboolean normalize = !mtlc->useTransform;
|
||||
struct TxtVertex quadTxVerticesBuffer[6];
|
||||
_fillTxQuad(quadTxVerticesBuffer, normalize, sx1, sy1, sx2, sy2, src.width, src.height, dx1, dy1, dx2, dy2, dst.width, dst.height);
|
||||
|
||||
[encoder setVertexBytes:quadTxVerticesBuffer length:sizeof(quadTxVerticesBuffer) atIndex:MeshVertexBuffer];
|
||||
[encoder setFragmentTexture:src atIndex: 0];
|
||||
[encoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:6];
|
||||
[encoder endEncoding];
|
||||
}
|
||||
|
||||
/**
|
||||
* Inner loop used for copying a source MTL "Texture" to a destination
|
||||
* MTL "Surface". This method is invoked from MTLBlitLoops_IsoBlit().
|
||||
*
|
||||
* This method will copy, scale, or transform the source texture into the
|
||||
* destination depending on the transform state, as established in
|
||||
* and MTLContext_SetTransform(). If the source texture is
|
||||
* transformed in any way when rendered into the destination, the filtering
|
||||
* method applied is determined by the hint parameter (can be GL_NEAREST or
|
||||
* GL_LINEAR).
|
||||
*/
|
||||
static void
|
||||
MTLBlitTextureToSurface(MTLContext *mtlc,
|
||||
BMTLSDOps *srcOps, BMTLSDOps *dstOps,
|
||||
jboolean rtt, jint hint,
|
||||
jint sx1, jint sy1, jint sx2, jint sy2,
|
||||
jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
|
||||
{
|
||||
id<MTLTexture> srcTex = srcOps->pTexture;
|
||||
|
||||
#ifdef DEBUG
|
||||
J2dTraceImpl(J2D_TRACE_VERBOSE, JNI_TRUE, "MTLBlitLoops_IsoBlit [via sampling]: bsrc=%p [tex=%p], bdst=%p [tex=%p] | s (%dx%d) -> d (%dx%d) | src (%d, %d, %d, %d) -> dst (%1.2f, %1.2f, %1.2f, %1.2f)", srcOps, srcOps->pTexture, dstOps, dstOps->pTexture, srcTex.width, srcTex.height, dstOps->width, dstOps->height, sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2);
|
||||
#endif //DEBUG
|
||||
|
||||
_drawTex2Tex(mtlc, srcOps->pTexture, dstOps->pTexture, rtt, hint, sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inner loop used for copying a source system memory ("Sw") surface to a
|
||||
* destination MTL "Surface". This method is invoked from
|
||||
* MTLBlitLoops_Blit().
|
||||
*
|
||||
* The standard glDrawPixels() mechanism is used to copy the source region
|
||||
* into the destination region. If the regions have different
|
||||
* dimensions, the source will be scaled into the destination
|
||||
* as appropriate (only nearest neighbor filtering will be applied for simple
|
||||
* scale operations).
|
||||
*/
|
||||
|
||||
static void
|
||||
MTLBlitSwToSurfaceViaTexture(MTLContext *ctx, SurfaceDataRasInfo *srcInfo, BMTLSDOps * bmtlsdOps,
|
||||
MTPixelFormat *pf,
|
||||
jint sx1, jint sy1, jint sx2, jint sy2,
|
||||
jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
|
||||
{
|
||||
if (bmtlsdOps == NULL || bmtlsdOps->pTexture == NULL) {
|
||||
J2dTraceLn(J2D_TRACE_ERROR, "MTLBlitSwToSurfaceViaTexture: dest is null");
|
||||
return;
|
||||
}
|
||||
|
||||
const int sw = sx2 - sx1;
|
||||
const int sh = sy2 - sy1;
|
||||
id<MTLTexture> dest = bmtlsdOps->pTexture;
|
||||
|
||||
#ifdef DEBUG
|
||||
J2dTraceImpl(J2D_TRACE_VERBOSE, JNI_TRUE, "MTLBlitLoops_Blit [via pooled texture]: bdst=%p [tex=%p], sw=%d, sh=%d | src (%d, %d, %d, %d) -> dst (%1.2f, %1.2f, %1.2f, %1.2f)", bmtlsdOps, dest, sw, sh, sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2);
|
||||
#endif //DEBUG
|
||||
|
||||
id<MTLTexture> texBuff = [ctx->mtlTexturePool getTexture:sw height:sh format:MTLPixelFormatBGRA8Unorm];
|
||||
if (texBuff == nil) {
|
||||
J2dTraceLn(J2D_TRACE_ERROR, "MTLBlitSwToSurfaceViaTexture: can't obtain temporary texture object from pool");
|
||||
return;
|
||||
}
|
||||
MTLRegion region = MTLRegionMake2D(0, 0, sw, sh);
|
||||
[texBuff replaceRegion:region mipmapLevel:0 withBytes:srcInfo->rasBase bytesPerRow:srcInfo->scanStride]; // texBuff is locked for current frame
|
||||
|
||||
_drawTex2Tex(ctx, texBuff, dest, 0, 0, 0, 0, sw, sh, dx1, dy1, dx2, dy2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inner loop used for copying a source system memory ("Sw") surface or
|
||||
* MTL "Surface" to a destination OpenGL "Surface", using an MTL texture
|
||||
* tile as an intermediate surface. This method is invoked from
|
||||
* MTLBlitLoops_Blit() for "Sw" surfaces and MTLBlitLoops_IsoBlit() for
|
||||
* "Surface" surfaces.
|
||||
*
|
||||
* This method is used to transform the source surface into the destination.
|
||||
* Pixel rectangles cannot be arbitrarily transformed (without the
|
||||
* GL_EXT_pixel_transform extension, which is not supported on most modern
|
||||
* hardware). However, texture mapped quads do respect the GL_MODELVIEW
|
||||
* transform matrix, so we use textures here to perform the transform
|
||||
* operation. This method uses a tile-based approach in which a small
|
||||
* subregion of the source surface is copied into a cached texture tile. The
|
||||
* texture tile is then mapped into the appropriate location in the
|
||||
* destination surface.
|
||||
*
|
||||
* REMIND: this only works well using GL_NEAREST for the filtering mode
|
||||
* (GL_LINEAR causes visible stitching problems between tiles,
|
||||
* but this can be fixed by making use of texture borders)
|
||||
*/
|
||||
static void
|
||||
MTLBlitToSurfaceViaTexture(MTLContext *mtlc, SurfaceDataRasInfo *srcInfo,
|
||||
MTPixelFormat *pf, MTLSDOps *srcOps,
|
||||
jboolean swsurface, jint hint,
|
||||
jint sx1, jint sy1, jint sx2, jint sy2,
|
||||
jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLBlitToSurfaceViaTexture");
|
||||
}
|
||||
|
||||
/**
|
||||
* Inner loop used for copying a source system memory ("Sw") surface to a
|
||||
* destination OpenGL "Texture". This method is invoked from
|
||||
* MTLBlitLoops_Blit().
|
||||
*
|
||||
* The source surface is effectively loaded into the MTL texture object,
|
||||
* which must have already been initialized by MTLSD_initTexture(). Note
|
||||
* that this method is only capable of copying the source surface into the
|
||||
* destination surface (i.e. no scaling or general transform is allowed).
|
||||
* This restriction should not be an issue as this method is only used
|
||||
* currently to cache a static system memory image into an MTL texture in
|
||||
* a hidden-acceleration situation.
|
||||
*/
|
||||
static void
|
||||
MTLBlitSwToTexture(SurfaceDataRasInfo *srcInfo, MTPixelFormat *pf,
|
||||
MTLSDOps *dstOps,
|
||||
jint dx1, jint dy1, jint dx2, jint dy2)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLBlitSwToTexture");
|
||||
}
|
||||
|
||||
/**
|
||||
* General blit method for copying a native MTL surface (of type "Surface"
|
||||
* or "Texture") to another MTL "Surface". If texture is JNI_TRUE, this
|
||||
* method will invoke the Texture->Surface inner loop; otherwise, one of the
|
||||
* Surface->Surface inner loops will be invoked, depending on the transform
|
||||
* state.
|
||||
*
|
||||
* REMIND: we can trick these blit methods into doing XOR simply by passing
|
||||
* in the (pixel ^ xorpixel) as the pixel value and preceding the
|
||||
* blit with a fillrect...
|
||||
*/
|
||||
void
|
||||
MTLBlitLoops_IsoBlit(JNIEnv *env,
|
||||
MTLContext *mtlc, jlong pSrcOps, jlong pDstOps,
|
||||
jboolean xform, jint hint,
|
||||
jboolean texture, jboolean rtt,
|
||||
jint sx1, jint sy1, jint sx2, jint sy2,
|
||||
jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
|
||||
{
|
||||
BMTLSDOps *srcOps = (BMTLSDOps *)jlong_to_ptr(pSrcOps);
|
||||
BMTLSDOps *dstOps = (BMTLSDOps *)jlong_to_ptr(pDstOps);
|
||||
|
||||
RETURN_IF_NULL(srcOps);
|
||||
RETURN_IF_NULL(dstOps);
|
||||
|
||||
id<MTLTexture> srcTex = srcOps->pTexture;
|
||||
id<MTLTexture> dstTex = dstOps->pTexture;
|
||||
if (mtlc == NULL || srcTex == nil || srcTex == nil) {
|
||||
J2dTraceLn2(J2D_TRACE_ERROR, "MTLBlitLoops_IsoBlit: surface is null (stex=%p, dtex=%p)", srcTex, dstTex);
|
||||
return;
|
||||
}
|
||||
|
||||
const jint sw = sx2 - sx1;
|
||||
const jint sh = sy2 - sy1;
|
||||
const jdouble dw = dx2 - dx1;
|
||||
const jdouble dh = dy2 - dy1;
|
||||
|
||||
if (sw <= 0 || sh <= 0 || dw <= 0 || dh <= 0) {
|
||||
J2dTraceLn4(J2D_TRACE_WARNING, "MTLBlitLoops_IsoBlit: invalid dimensions: sw=%d, sh%d, dw=%d, dh=%d", sw, sh, dw, dh);
|
||||
return;
|
||||
}
|
||||
|
||||
SurfaceDataRasInfo srcInfo;
|
||||
srcInfo.bounds.x1 = sx1;
|
||||
srcInfo.bounds.y1 = sy1;
|
||||
srcInfo.bounds.x2 = sx2;
|
||||
srcInfo.bounds.y2 = sy2;
|
||||
SurfaceData_IntersectBoundsXYXY(&srcInfo.bounds, 0, 0, srcOps->width, srcOps->height);
|
||||
|
||||
if (srcInfo.bounds.x2 <= srcInfo.bounds.x1 || srcInfo.bounds.y2 <= srcInfo.bounds.y1) {
|
||||
J2dTraceLn(J2D_TRACE_VERBOSE, "MTLBlitLoops_IsoBlit: source rectangle doesn't intersect with source surface bounds");
|
||||
J2dTraceLn6(J2D_TRACE_VERBOSE, " sx1=%d sy1=%d sx2=%d sy2=%d sw=%d sh=%d", sx1, sy1, sx2, sy2, srcOps->width, srcOps->height);
|
||||
J2dTraceLn4(J2D_TRACE_VERBOSE, " dx1=%f dy1=%f dx2=%f dy2=%f", dx1, dy1, dx2, dy2);
|
||||
return;
|
||||
}
|
||||
|
||||
if (srcInfo.bounds.x1 != sx1) {
|
||||
dx1 += (srcInfo.bounds.x1 - sx1) * (dw / sw);
|
||||
sx1 = srcInfo.bounds.x1;
|
||||
}
|
||||
if (srcInfo.bounds.y1 != sy1) {
|
||||
dy1 += (srcInfo.bounds.y1 - sy1) * (dh / sh);
|
||||
sy1 = srcInfo.bounds.y1;
|
||||
}
|
||||
if (srcInfo.bounds.x2 != sx2) {
|
||||
dx2 += (srcInfo.bounds.x2 - sx2) * (dw / sw);
|
||||
sx2 = srcInfo.bounds.x2;
|
||||
}
|
||||
if (srcInfo.bounds.y2 != sy2) {
|
||||
dy2 += (srcInfo.bounds.y2 - sy2) * (dh / sh);
|
||||
sy2 = srcInfo.bounds.y2;
|
||||
}
|
||||
|
||||
const jboolean useBlitEncoder =
|
||||
MTLContext_IsBlendingDisabled(mtlc)
|
||||
&& fabs(dx2 - dx1 - sx2 + sx1) < 0.001f && fabs(dy2 - dy1 - sy2 + sy1) < 0.001f // dimensions are equal (TODO: check that dx1,dy1 is integer)
|
||||
&& !mtlc->useTransform; // TODO: check whether transform is simple translate (and use blitEncoder in this case)
|
||||
if (useBlitEncoder) {
|
||||
#ifdef DEBUG
|
||||
J2dTraceImpl(J2D_TRACE_VERBOSE, JNI_TRUE, "MTLBlitLoops_IsoBlit [via blitEncoder]: bdst=%p [tex=%p] %dx%d | src (%d, %d, %d, %d) -> dst (%1.2f, %1.2f, %1.2f, %1.2f)", dstOps, dstTex, dstTex.width, dstTex.height, sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2);
|
||||
#endif //DEBUG
|
||||
id <MTLBlitCommandEncoder> blitEncoder = MTLContext_CreateBlitEncoder(mtlc);
|
||||
[blitEncoder copyFromTexture:srcTex sourceSlice:0 sourceLevel:0 sourceOrigin:MTLOriginMake(sx1, sy1, 0) sourceSize:MTLSizeMake(sx2 - sx1, sy2 - sy1, 1) toTexture:dstTex destinationSlice:0 destinationLevel:0 destinationOrigin:MTLOriginMake(dx1, dy1, 0)];
|
||||
[blitEncoder endEncoding];
|
||||
} else {
|
||||
// TODO: support other flags
|
||||
MTLBlitTextureToSurface(mtlc, srcOps, dstOps, rtt, hint, sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* General blit method for copying a system memory ("Sw") surface to a native
|
||||
* MTL surface (of type "Surface" or "Texture"). If texture is JNI_TRUE,
|
||||
* this method will invoke the Sw->Texture inner loop; otherwise, one of the
|
||||
* Sw->Surface inner loops will be invoked, depending on the transform state.
|
||||
*/
|
||||
void
|
||||
MTLBlitLoops_Blit(JNIEnv *env,
|
||||
MTLContext *mtlc, jlong pSrcOps, jlong pDstOps,
|
||||
jboolean xform, jint hint,
|
||||
jint srctype, jboolean texture,
|
||||
jint sx1, jint sy1, jint sx2, jint sy2,
|
||||
jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
|
||||
{
|
||||
RETURN_IF_NULL(jlong_to_ptr(pSrcOps));
|
||||
RETURN_IF_NULL(jlong_to_ptr(pDstOps));
|
||||
|
||||
SurfaceDataOps *srcOps = (SurfaceDataOps *)jlong_to_ptr(pSrcOps);
|
||||
BMTLSDOps *dstOps = (BMTLSDOps *)jlong_to_ptr(pDstOps);
|
||||
SurfaceDataRasInfo srcInfo;
|
||||
MTLPixelFormat pf = MTLPixelFormatBGRA8Unorm;//PixelFormats[srctype];
|
||||
|
||||
if (dstOps == NULL || dstOps->pTexture == NULL) {
|
||||
J2dTraceLn(J2D_TRACE_ERROR, "MTLBlitLoops_Blit: dest is null");
|
||||
return;
|
||||
}
|
||||
id<MTLTexture> dest = dstOps->pTexture;
|
||||
if (dx1 < 0) {
|
||||
sx1 += dx1;
|
||||
dx1 = 0;
|
||||
}
|
||||
if (dx2 > dest.width) {
|
||||
sx2 -= dx2 - dest.width;
|
||||
dx2 = dest.width;
|
||||
}
|
||||
if (dy1 < 0) {
|
||||
sy1 += dy1;
|
||||
dy1 = 0;
|
||||
}
|
||||
if (dy2 > dest.height) {
|
||||
sy2 -= dy2 - dest.height;
|
||||
dy2 = dest.height;
|
||||
}
|
||||
jint sw = sx2 - sx1;
|
||||
jint sh = sy2 - sy1;
|
||||
jdouble dw = dx2 - dx1;
|
||||
jdouble dh = dy2 - dy1;
|
||||
|
||||
if (sw <= 0 || sh <= 0 || dw <= 0 || dh <= 0 || srctype < 0) {
|
||||
J2dTraceLn(J2D_TRACE_WARNING, "MTLBlitLoops_Blit: invalid dimensions or srctype");
|
||||
return;
|
||||
}
|
||||
|
||||
srcInfo.bounds.x1 = sx1;
|
||||
srcInfo.bounds.y1 = sy1;
|
||||
srcInfo.bounds.x2 = sx2;
|
||||
srcInfo.bounds.y2 = sy2;
|
||||
|
||||
if (srcOps->Lock(env, srcOps, &srcInfo, SD_LOCK_READ) != SD_SUCCESS) {
|
||||
J2dTraceLn(J2D_TRACE_WARNING, "MTLBlitLoops_Blit: could not acquire lock");
|
||||
return;
|
||||
}
|
||||
|
||||
J2dTraceLn5(J2D_TRACE_VERBOSE, "MTLBlitLoops_Blit: pf=%d texture=%d srctype=%d xform=%d hint=%d", pf, texture, srctype, xform, hint);
|
||||
|
||||
if (srcInfo.bounds.x2 > srcInfo.bounds.x1 && srcInfo.bounds.y2 > srcInfo.bounds.y1) {
|
||||
srcOps->GetRasInfo(env, srcOps, &srcInfo);
|
||||
if (srcInfo.rasBase) {
|
||||
if (srcInfo.bounds.x1 != sx1) {
|
||||
dx1 += (srcInfo.bounds.x1 - sx1) * (dw / sw);
|
||||
sx1 = srcInfo.bounds.x1;
|
||||
}
|
||||
if (srcInfo.bounds.y1 != sy1) {
|
||||
dy1 += (srcInfo.bounds.y1 - sy1) * (dh / sh);
|
||||
sy1 = srcInfo.bounds.y1;
|
||||
}
|
||||
if (srcInfo.bounds.x2 != sx2) {
|
||||
dx2 += (srcInfo.bounds.x2 - sx2) * (dw / sw);
|
||||
sx2 = srcInfo.bounds.x2;
|
||||
}
|
||||
if (srcInfo.bounds.y2 != sy2) {
|
||||
dy2 += (srcInfo.bounds.y2 - sy2) * (dh / sh);
|
||||
sy2 = srcInfo.bounds.y2;
|
||||
}
|
||||
|
||||
const jboolean useReplaceRegion =
|
||||
MTLContext_IsBlendingDisabled(mtlc)
|
||||
&& fabs(dx2 - dx1 - sx2 + sx1) < 0.001f && fabs(dy2 - dy1 - sy2 + sy1) < 0.001f // dimensions are equal (TODO: check that dx1,dy1 is integer)
|
||||
&& !mtlc->useTransform; // TODO: check whether transform is simple translate (and use replaceRegion in this case)
|
||||
if (useReplaceRegion) {
|
||||
MTLRegion region = MTLRegionMake2D(dx1, dy1, dx2 - dx1, dy2 - dy1);
|
||||
#ifdef DEBUG
|
||||
J2dTraceImpl(J2D_TRACE_VERBOSE, JNI_TRUE, "MTLBlitLoops_Blit [replaceRegion]: bdst=%p [tex=%p] %dx%d | src (%d, %d, %d, %d) -> dst (%1.2f, %1.2f, %1.2f, %1.2f)", dstOps, dest, dest.width, dest.height, sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2);
|
||||
#endif //DEBUG
|
||||
[dest replaceRegion:region mipmapLevel:0 withBytes:srcInfo.rasBase bytesPerRow:srcInfo.scanStride]; // executed at CPU (sync), TODO: lock dest for current frame
|
||||
} else {
|
||||
MTLBlitSwToSurfaceViaTexture(mtlc, &srcInfo, dstOps, &pf, sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2);
|
||||
}
|
||||
}
|
||||
SurfaceData_InvokeRelease(env, srcOps, &srcInfo);
|
||||
}
|
||||
SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialized blit method for copying a native MTL "Surface" (pbuffer,
|
||||
* window, etc.) to a system memory ("Sw") surface.
|
||||
*/
|
||||
void
|
||||
MTLBlitLoops_SurfaceToSwBlit(JNIEnv *env, MTLContext *mtlc,
|
||||
jlong pSrcOps, jlong pDstOps, jint dsttype,
|
||||
jint srcx, jint srcy, jint dstx, jint dsty,
|
||||
jint width, jint height)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLBlitLoops_SurfaceToSwBlit");
|
||||
}
|
||||
|
||||
void
|
||||
MTLBlitLoops_CopyArea(JNIEnv *env,
|
||||
MTLContext *mtlc, BMTLSDOps *dstOps,
|
||||
jint x, jint y, jint width, jint height,
|
||||
jint dx, jint dy)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLBlitLoops_CopyArea");
|
||||
}
|
||||
|
||||
#endif /* !HEADLESS */
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
#ifndef MTLBufImgOps_h_Included
|
||||
#define MTLBufImgOps_h_Included
|
||||
|
||||
#include "MTLContext.h"
|
||||
|
||||
void MTLBufImgOps_EnableConvolveOp(MTLContext *mtlc, jlong pSrcOps,
|
||||
jboolean edgeZeroFill,
|
||||
jint kernelWidth, jint KernelHeight,
|
||||
unsigned char *kernelVals);
|
||||
void MTLBufImgOps_DisableConvolveOp(MTLContext *mtlc);
|
||||
void MTLBufImgOps_EnableRescaleOp(MTLContext *mtlc, jlong pSrcOps,
|
||||
jboolean nonPremult,
|
||||
unsigned char *scaleFactors,
|
||||
unsigned char *offsets);
|
||||
void MTLBufImgOps_DisableRescaleOp(MTLContext *mtlc);
|
||||
void MTLBufImgOps_EnableLookupOp(MTLContext *mtlc, jlong pSrcOps,
|
||||
jboolean nonPremult, jboolean shortData,
|
||||
jint numBands, jint bandLength, jint offset,
|
||||
void *tableValues);
|
||||
void MTLBufImgOps_DisableLookupOp(MTLContext *mtlc);
|
||||
|
||||
#endif /* MTLBufImgOps_h_Included */
|
||||
@@ -0,0 +1,378 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
#ifndef HEADLESS
|
||||
|
||||
#include <jlong.h>
|
||||
|
||||
#include "MTLBufImgOps.h"
|
||||
#include "MTLContext.h"
|
||||
#include "MTLRenderQueue.h"
|
||||
#include "MTLSurfaceDataBase.h"
|
||||
#include "GraphicsPrimitiveMgr.h"
|
||||
|
||||
/** Evaluates to true if the given bit is set on the local flags variable. */
|
||||
#define IS_SET(flagbit) \
|
||||
(((flags) & (flagbit)) != 0)
|
||||
|
||||
/**************************** ConvolveOp support ****************************/
|
||||
|
||||
/**
|
||||
* The ConvolveOp shader is fairly straightforward. For each texel in
|
||||
* the source texture, the shader samples the MxN texels in the surrounding
|
||||
* area, multiplies each by its corresponding kernel value, and then sums
|
||||
* them all together to produce a single color result. Finally, the
|
||||
* resulting value is multiplied by the current OpenGL color, which contains
|
||||
* the extra alpha value.
|
||||
*
|
||||
* Note that this shader source code includes some "holes" marked by "%s".
|
||||
* This allows us to build different shader programs (e.g. one for
|
||||
* 3x3, one for 5x5, and so on) simply by filling in these "holes" with
|
||||
* a call to sprintf(). See the MTLBufImgOps_CreateConvolveProgram() method
|
||||
* for more details.
|
||||
*
|
||||
* REMIND: Currently this shader (and the supporting code in the
|
||||
* EnableConvolveOp() method) only supports 3x3 and 5x5 filters.
|
||||
* Early shader-level hardware did not support non-constant sized
|
||||
* arrays but modern hardware should support them (although I
|
||||
* don't know of any simple way to find out, other than to compile
|
||||
* the shader at runtime and see if the drivers complain).
|
||||
*/
|
||||
static const char *convolveShaderSource =
|
||||
// maximum size supported by this shader
|
||||
"const int MAX_KERNEL_SIZE = %s;"
|
||||
// image to be convolved
|
||||
"uniform sampler%s baseImage;"
|
||||
// image edge limits:
|
||||
// imgEdge.xy = imgMin.xy (anything < will be treated as edge case)
|
||||
// imgEdge.zw = imgMax.xy (anything > will be treated as edge case)
|
||||
"uniform vec4 imgEdge;"
|
||||
// value for each location in the convolution kernel:
|
||||
// kernelVals[i].x = offsetX[i]
|
||||
// kernelVals[i].y = offsetY[i]
|
||||
// kernelVals[i].z = kernel[i]
|
||||
"uniform vec3 kernelVals[MAX_KERNEL_SIZE];"
|
||||
""
|
||||
"void main(void)"
|
||||
"{"
|
||||
" int i;"
|
||||
" vec4 sum;"
|
||||
""
|
||||
" if (any(lessThan(gl_TexCoord[0].st, imgEdge.xy)) ||"
|
||||
" any(greaterThan(gl_TexCoord[0].st, imgEdge.zw)))"
|
||||
" {"
|
||||
// (placeholder for edge condition code)
|
||||
" %s"
|
||||
" } else {"
|
||||
" sum = vec4(0.0);"
|
||||
" for (i = 0; i < MAX_KERNEL_SIZE; i++) {"
|
||||
" sum +="
|
||||
" kernelVals[i].z *"
|
||||
" texture%s(baseImage,"
|
||||
" gl_TexCoord[0].st + kernelVals[i].xy);"
|
||||
" }"
|
||||
" }"
|
||||
""
|
||||
// modulate with gl_Color in order to apply extra alpha
|
||||
" gl_FragColor = sum * gl_Color;"
|
||||
"}";
|
||||
|
||||
/**
|
||||
* Flags that can be bitwise-or'ed together to control how the shader
|
||||
* source code is generated.
|
||||
*/
|
||||
#define CONVOLVE_RECT (1 << 0)
|
||||
#define CONVOLVE_EDGE_ZERO_FILL (1 << 1)
|
||||
#define CONVOLVE_5X5 (1 << 2)
|
||||
|
||||
/**
|
||||
* The handles to the ConvolveOp fragment program objects. The index to
|
||||
* the array should be a bitwise-or'ing of the CONVOLVE_* flags defined
|
||||
* above. Note that most applications will likely need to initialize one
|
||||
* or two of these elements, so the array is usually sparsely populated.
|
||||
*/
|
||||
static GLhandleARB convolvePrograms[8];
|
||||
|
||||
/**
|
||||
* The maximum kernel size supported by the ConvolveOp shader.
|
||||
*/
|
||||
#define MAX_KERNEL_SIZE 25
|
||||
|
||||
/**
|
||||
* Compiles and links the ConvolveOp shader program. If successful, this
|
||||
* function returns a handle to the newly created shader program; otherwise
|
||||
* returns 0.
|
||||
*/
|
||||
static GLhandleARB
|
||||
MTLBufImgOps_CreateConvolveProgram(jint flags)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLBufImgOps_CreateConvolveProgram");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
MTLBufImgOps_EnableConvolveOp(MTLContext *mtlc, jlong pSrcOps,
|
||||
jboolean edgeZeroFill,
|
||||
jint kernelWidth, jint kernelHeight,
|
||||
unsigned char *kernel)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLBufImgOps_EnableConvolveOp");
|
||||
}
|
||||
|
||||
void
|
||||
MTLBufImgOps_DisableConvolveOp(MTLContext *mtlc)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLBufImgOps_EnableConvolveOp");
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLBufImgOps_DisableConvolveOp");
|
||||
}
|
||||
|
||||
/**************************** RescaleOp support *****************************/
|
||||
|
||||
/**
|
||||
* The RescaleOp shader is one of the simplest possible. Each fragment
|
||||
* from the source image is multiplied by the user's scale factor and added
|
||||
* to the user's offset value (these are component-wise operations).
|
||||
* Finally, the resulting value is multiplied by the current OpenGL color,
|
||||
* which contains the extra alpha value.
|
||||
*
|
||||
* The RescaleOp spec says that the operation is performed regardless of
|
||||
* whether the source data is premultiplied or non-premultiplied. This is
|
||||
* a problem for the OpenGL pipeline in that a non-premultiplied
|
||||
* BufferedImage will have already been converted into premultiplied
|
||||
* when uploaded to an OpenGL texture. Therefore, we have a special mode
|
||||
* called RESCALE_NON_PREMULT (used only for source images that were
|
||||
* originally non-premultiplied) that un-premultiplies the source color
|
||||
* prior to the rescale operation, then re-premultiplies the resulting
|
||||
* color before returning from the fragment shader.
|
||||
*
|
||||
* Note that this shader source code includes some "holes" marked by "%s".
|
||||
* This allows us to build different shader programs (e.g. one for
|
||||
* GL_TEXTURE_2D targets, one for GL_TEXTURE_RECTANGLE_ARB targets, and so on)
|
||||
* simply by filling in these "holes" with a call to sprintf(). See the
|
||||
* MTLBufImgOps_CreateRescaleProgram() method for more details.
|
||||
*/
|
||||
static const char *rescaleShaderSource =
|
||||
// image to be rescaled
|
||||
"uniform sampler%s baseImage;"
|
||||
// vector containing scale factors
|
||||
"uniform vec4 scaleFactors;"
|
||||
// vector containing offsets
|
||||
"uniform vec4 offsets;"
|
||||
""
|
||||
"void main(void)"
|
||||
"{"
|
||||
" vec4 srcColor = texture%s(baseImage, gl_TexCoord[0].st);"
|
||||
// (placeholder for un-premult code)
|
||||
" %s"
|
||||
// rescale source value
|
||||
" vec4 result = (srcColor * scaleFactors) + offsets;"
|
||||
// (placeholder for re-premult code)
|
||||
" %s"
|
||||
// modulate with gl_Color in order to apply extra alpha
|
||||
" gl_FragColor = result * gl_Color;"
|
||||
"}";
|
||||
|
||||
/**
|
||||
* Flags that can be bitwise-or'ed together to control how the shader
|
||||
* source code is generated.
|
||||
*/
|
||||
#define RESCALE_RECT (1 << 0)
|
||||
#define RESCALE_NON_PREMULT (1 << 1)
|
||||
|
||||
/**
|
||||
* The handles to the RescaleOp fragment program objects. The index to
|
||||
* the array should be a bitwise-or'ing of the RESCALE_* flags defined
|
||||
* above. Note that most applications will likely need to initialize one
|
||||
* or two of these elements, so the array is usually sparsely populated.
|
||||
*/
|
||||
static GLhandleARB rescalePrograms[4];
|
||||
|
||||
/**
|
||||
* Compiles and links the RescaleOp shader program. If successful, this
|
||||
* function returns a handle to the newly created shader program; otherwise
|
||||
* returns 0.
|
||||
*/
|
||||
static GLhandleARB
|
||||
MTLBufImgOps_CreateRescaleProgram(jint flags)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLBufImgOps_CreateRescaleProgram");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
MTLBufImgOps_EnableRescaleOp(MTLContext *mtlc, jlong pSrcOps,
|
||||
jboolean nonPremult,
|
||||
unsigned char *scaleFactors,
|
||||
unsigned char *offsets)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLBufImgOps_EnableRescaleOp");
|
||||
}
|
||||
|
||||
void
|
||||
MTLBufImgOps_DisableRescaleOp(MTLContext *mtlc)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLBufImgOps_DisableRescaleOp");
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLBufImgOps_DisableRescaleOp");
|
||||
RETURN_IF_NULL(mtlc);
|
||||
}
|
||||
|
||||
/**************************** LookupOp support ******************************/
|
||||
|
||||
/**
|
||||
* The LookupOp shader takes a fragment color (from the source texture) as
|
||||
* input, subtracts the optional user offset value, and then uses the
|
||||
* resulting value to index into the lookup table texture to provide
|
||||
* a new color result. Finally, the resulting value is multiplied by
|
||||
* the current OpenGL color, which contains the extra alpha value.
|
||||
*
|
||||
* The lookup step requires 3 texture accesses (or 4, when alpha is included),
|
||||
* which is somewhat unfortunate because it's not ideal from a performance
|
||||
* standpoint, but that sort of thing is getting faster with newer hardware.
|
||||
* In the 3-band case, we could consider using a three-dimensional texture
|
||||
* and performing the lookup with a single texture access step. We already
|
||||
* use this approach in the LCD text shader, and it works well, but for the
|
||||
* purposes of this LookupOp shader, it's probably overkill. Also, there's
|
||||
* a difference in that the LCD text shader only needs to populate the 3D LUT
|
||||
* once, but here we would need to populate it on every invocation, which
|
||||
* would likely be a waste of VRAM and CPU/GPU cycles.
|
||||
*
|
||||
* The LUT texture is currently hardcoded as 4 rows/bands, each containing
|
||||
* 256 elements. This means that we currently only support user-provided
|
||||
* tables with no more than 256 elements in each band (this is checked at
|
||||
* at the Java level). If the user provides a table with less than 256
|
||||
* elements per band, our shader will still work fine, but if elements are
|
||||
* accessed with an index >= the size of the LUT, then the shader will simply
|
||||
* produce undefined values. Typically the user would provide an offset
|
||||
* value that would prevent this from happening, but it's worth pointing out
|
||||
* this fact because the software LookupOp implementation would usually
|
||||
* throw an ArrayIndexOutOfBoundsException in this scenario (although it is
|
||||
* not something demanded by the spec).
|
||||
*
|
||||
* The LookupOp spec says that the operation is performed regardless of
|
||||
* whether the source data is premultiplied or non-premultiplied. This is
|
||||
* a problem for the OpenGL pipeline in that a non-premultiplied
|
||||
* BufferedImage will have already been converted into premultiplied
|
||||
* when uploaded to an OpenGL texture. Therefore, we have a special mode
|
||||
* called LOOKUP_NON_PREMULT (used only for source images that were
|
||||
* originally non-premultiplied) that un-premultiplies the source color
|
||||
* prior to the lookup operation, then re-premultiplies the resulting
|
||||
* color before returning from the fragment shader.
|
||||
*
|
||||
* Note that this shader source code includes some "holes" marked by "%s".
|
||||
* This allows us to build different shader programs (e.g. one for
|
||||
* GL_TEXTURE_2D targets, one for GL_TEXTURE_RECTANGLE_ARB targets, and so on)
|
||||
* simply by filling in these "holes" with a call to sprintf(). See the
|
||||
* MTLBufImgOps_CreateLookupProgram() method for more details.
|
||||
*/
|
||||
static const char *lookupShaderSource =
|
||||
// source image (bound to texture unit 0)
|
||||
"uniform sampler%s baseImage;"
|
||||
// lookup table (bound to texture unit 1)
|
||||
"uniform sampler2D lookupTable;"
|
||||
// offset subtracted from source index prior to lookup step
|
||||
"uniform vec4 offset;"
|
||||
""
|
||||
"void main(void)"
|
||||
"{"
|
||||
" vec4 srcColor = texture%s(baseImage, gl_TexCoord[0].st);"
|
||||
// (placeholder for un-premult code)
|
||||
" %s"
|
||||
// subtract offset from original index
|
||||
" vec4 srcIndex = srcColor - offset;"
|
||||
// use source value as input to lookup table (note that
|
||||
// "v" texcoords are hardcoded to hit texel centers of
|
||||
// each row/band in texture)
|
||||
" vec4 result;"
|
||||
" result.r = texture2D(lookupTable, vec2(srcIndex.r, 0.125)).r;"
|
||||
" result.g = texture2D(lookupTable, vec2(srcIndex.g, 0.375)).r;"
|
||||
" result.b = texture2D(lookupTable, vec2(srcIndex.b, 0.625)).r;"
|
||||
// (placeholder for alpha store code)
|
||||
" %s"
|
||||
// (placeholder for re-premult code)
|
||||
" %s"
|
||||
// modulate with gl_Color in order to apply extra alpha
|
||||
" gl_FragColor = result * gl_Color;"
|
||||
"}";
|
||||
|
||||
/**
|
||||
* Flags that can be bitwise-or'ed together to control how the shader
|
||||
* source code is generated.
|
||||
*/
|
||||
#define LOOKUP_RECT (1 << 0)
|
||||
#define LOOKUP_USE_SRC_ALPHA (1 << 1)
|
||||
#define LOOKUP_NON_PREMULT (1 << 2)
|
||||
|
||||
/**
|
||||
* The handles to the LookupOp fragment program objects. The index to
|
||||
* the array should be a bitwise-or'ing of the LOOKUP_* flags defined
|
||||
* above. Note that most applications will likely need to initialize one
|
||||
* or two of these elements, so the array is usually sparsely populated.
|
||||
*/
|
||||
static GLhandleARB lookupPrograms[8];
|
||||
|
||||
/**
|
||||
* The handle to the lookup table texture object used by the shader.
|
||||
*/
|
||||
static GLuint lutTextureID = 0;
|
||||
|
||||
/**
|
||||
* Compiles and links the LookupOp shader program. If successful, this
|
||||
* function returns a handle to the newly created shader program; otherwise
|
||||
* returns 0.
|
||||
*/
|
||||
static GLhandleARB
|
||||
MTLBufImgOps_CreateLookupProgram(jint flags)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLBufImgOps_CreateLookupProgram");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
MTLBufImgOps_EnableLookupOp(MTLContext *mtlc, jlong pSrcOps,
|
||||
jboolean nonPremult, jboolean shortData,
|
||||
jint numBands, jint bandLength, jint offset,
|
||||
void *tableValues)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLBufImgOps_EnableLookupOp");
|
||||
}
|
||||
|
||||
void
|
||||
MTLBufImgOps_DisableLookupOp(MTLContext *mtlc)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLBufImgOps_DisableLookupOp");
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLBufImgOps_DisableLookupOp");
|
||||
}
|
||||
|
||||
#endif /* !HEADLESS */
|
||||
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
#ifndef MTLContext_h_Included
|
||||
#define MTLContext_h_Included
|
||||
|
||||
#include <simd/simd.h>
|
||||
|
||||
#include "sun_java2d_pipe_BufferedContext.h"
|
||||
#include "sun_java2d_metal_MTLContext.h"
|
||||
#include "sun_java2d_metal_MTLContext_MTLContextCaps.h"
|
||||
|
||||
#import <Metal/Metal.h>
|
||||
#include "j2d_md.h"
|
||||
#include "MTLSurfaceDataBase.h"
|
||||
#include "MTLTexturePool.h"
|
||||
|
||||
/**
|
||||
* The MTLBlendRule structure encapsulates the two enumerated values that
|
||||
* comprise a given Porter-Duff blending (compositing) rule. For example,
|
||||
* the "SrcOver" rule can be represented by:
|
||||
* rule.src = GL_ONE;
|
||||
* rule.dst = GL_ONE_MINUS_SRC_ALPHA;
|
||||
*
|
||||
* GLenum src;
|
||||
* The constant representing the source factor in this Porter-Duff rule.
|
||||
*
|
||||
* GLenum dst;
|
||||
* The constant representing the destination factor in this Porter-Duff rule.
|
||||
*/
|
||||
typedef struct {
|
||||
jint src;
|
||||
jint dst;
|
||||
} MTLBlendRule;
|
||||
|
||||
/**
|
||||
* The MTLContext structure contains cached state relevant to the native
|
||||
* OpenGL context stored within the native ctxInfo field. Each Java-level
|
||||
* MTLContext object is associated with a native-level MTLContext structure.
|
||||
* The caps field is a bitfield that expresses the capabilities of the
|
||||
* GraphicsConfig associated with this context (see MTLContext.java for
|
||||
* the definitions of each capability bit). The other fields are
|
||||
* simply cached values of various elements of the context state, typically
|
||||
* used in the MTLContext.set*() methods.
|
||||
*
|
||||
* Note that the textureFunction field is implicitly set to zero when the
|
||||
* MTLContext is created. The acceptable values (e.g. GL_MODULATE,
|
||||
* GL_REPLACE) for this field are never zero, which means we will always
|
||||
* validate the texture function state upon the first call to the
|
||||
* MTLC_UPDATE_TEXTURE_FUNCTION() macro.
|
||||
*/
|
||||
typedef struct {
|
||||
jint compState;
|
||||
jfloat extraAlpha;
|
||||
jint alphaCompositeRule;
|
||||
jint xorPixel;
|
||||
jint pixel;
|
||||
jubyte r;
|
||||
jubyte g;
|
||||
jubyte b;
|
||||
jubyte a;
|
||||
jint paintState;
|
||||
jboolean useMask;
|
||||
jboolean useTransform;
|
||||
simd_float4x4 transform4x4;
|
||||
jint blitTextureID;
|
||||
jint textureFunction;
|
||||
jboolean vertexCacheEnabled;
|
||||
|
||||
id<MTLDevice> mtlDevice;
|
||||
id<MTLLibrary> mtlLibrary;
|
||||
id<MTLRenderPipelineState> mtlPipelineState;
|
||||
id<MTLRenderPipelineState> mtlBlitPipelineState;
|
||||
id<MTLRenderPipelineState> mtlBlitMatrixPipelineState;
|
||||
id<MTLRenderPipelineState> mtlBlitSrcOverPipelineState;
|
||||
id<MTLRenderPipelineState> mtlBlitMatrixSrcOverPipelineState; // TODO: implement PipelineStateFactory
|
||||
id<MTLCommandQueue> mtlCommandQueue;
|
||||
id<MTLCommandBuffer> mtlCommandBuffer;
|
||||
id<MTLBuffer> mtlVertexBuffer;
|
||||
jint mtlColor;
|
||||
MTLScissorRect mtlClipRect;
|
||||
jboolean useClip;
|
||||
|
||||
MTLTexturePool* mtlTexturePool;
|
||||
} MTLContext;
|
||||
|
||||
/**
|
||||
* See BufferedContext.java for more on these flags...
|
||||
*/
|
||||
#define MTLC_NO_CONTEXT_FLAGS \
|
||||
sun_java2d_pipe_BufferedContext_NO_CONTEXT_FLAGS
|
||||
#define MTLC_SRC_IS_OPAQUE \
|
||||
sun_java2d_pipe_BufferedContext_SRC_IS_OPAQUE
|
||||
#define MTLC_USE_MASK \
|
||||
sun_java2d_pipe_BufferedContext_USE_MASK
|
||||
|
||||
/**
|
||||
* See MTLContext.java for more on these flags.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Exported methods.
|
||||
*/
|
||||
MTLContext *MTLContext_SetSurfaces(JNIEnv *env, jlong pSrc, jlong pDst);
|
||||
void MTLContext_ResetClip(MTLContext *mtlc);
|
||||
void MTLContext_SetRectClip(MTLContext *mtlc, BMTLSDOps *dstOps,
|
||||
jint x1, jint y1, jint x2, jint y2);
|
||||
void MTLContext_BeginShapeClip(MTLContext *mtlc);
|
||||
void MTLContext_EndShapeClip(MTLContext *mtlc, BMTLSDOps *dstOps);
|
||||
void MTLContext_SetExtraAlpha(jfloat ea);
|
||||
void MTLContext_ResetComposite(MTLContext *mtlc);
|
||||
void MTLContext_SetAlphaComposite(MTLContext *mtlc,
|
||||
jint rule, jfloat extraAlpha, jint flags);
|
||||
void MTLContext_SetXorComposite(MTLContext *mtlc, jint xorPixel);
|
||||
jboolean MTLContext_IsBlendingDisabled(MTLContext *mtlc);
|
||||
void MTLContext_ResetTransform(MTLContext *mtlc);
|
||||
void MTLContext_SetTransform(MTLContext *mtlc,
|
||||
jdouble m00, jdouble m10,
|
||||
jdouble m01, jdouble m11,
|
||||
jdouble m02, jdouble m12);
|
||||
|
||||
jboolean MTLContext_InitBlitTileTexture(MTLContext *mtlc);
|
||||
jint MTLContext_CreateBlitTexture(jint internalFormat, jint pixelFormat,
|
||||
jint width, jint height);
|
||||
|
||||
void MTLContext_DestroyContextResources(MTLContext *mtlc);
|
||||
|
||||
void MTLContext_SetColor(MTLContext *ctx, int r, int g, int b, int a);
|
||||
void MTLContext_SetColorInt(MTLContext *ctx, int pixel);
|
||||
|
||||
id<MTLRenderCommandEncoder> MTLContext_CreateRenderEncoder(MTLContext *mtlc, id<MTLTexture> dest);
|
||||
id<MTLRenderCommandEncoder> MTLContext_CreateSamplingEncoder(MTLContext *mtlc, id<MTLTexture> dest);
|
||||
id<MTLBlitCommandEncoder> MTLContext_CreateBlitEncoder(MTLContext *mtlc);
|
||||
|
||||
#endif /* MTLContext_h_Included */
|
||||
@@ -0,0 +1,604 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
#ifndef HEADLESS
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "sun_java2d_SunGraphics2D.h"
|
||||
|
||||
#include "jlong.h"
|
||||
#include "jni_util.h"
|
||||
#include "MTLContext.h"
|
||||
#include "MTLRenderQueue.h"
|
||||
#include "MTLSurfaceDataBase.h"
|
||||
#include "GraphicsPrimitiveMgr.h"
|
||||
#include "Region.h"
|
||||
|
||||
#include "jvm.h"
|
||||
|
||||
extern jboolean MTLSD_InitMTLWindow(JNIEnv *env, MTLSDOps *mtlsdo);
|
||||
extern MTLContext *MTLSD_MakeMTLContextCurrent(JNIEnv *env,
|
||||
MTLSDOps *srcOps,
|
||||
MTLSDOps *dstOps);
|
||||
|
||||
/**
|
||||
* This table contains the standard blending rules (or Porter-Duff compositing
|
||||
* factors) used in glBlendFunc(), indexed by the rule constants from the
|
||||
* AlphaComposite class.
|
||||
*/
|
||||
MTLBlendRule MTStdBlendRules[] = {
|
||||
};
|
||||
|
||||
/** Evaluates to "front" or "back", depending on the value of buf. */
|
||||
//#define MTLC_ACTIVE_BUFFER_NAME(buf) \
|
||||
// (buf == GL_FRONT || buf == GL_COLOR_ATTACHMENT0_EXT) ? "front" : "back"
|
||||
|
||||
/**
|
||||
* Initializes the viewport and projection matrix, effectively positioning
|
||||
* the origin at the top-left corner of the surface. This allows Java 2D
|
||||
* coordinates to be passed directly to OpenGL, which is typically based on
|
||||
* a bottom-right coordinate system. This method also sets the appropriate
|
||||
* read and draw buffers.
|
||||
*/
|
||||
static void
|
||||
MTLContext_SetViewport(BMTLSDOps *srcOps,BMTLSDOps *dstOps)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLContext_SetViewport");
|
||||
jint width = dstOps->width;
|
||||
jint height = dstOps->height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the alpha channel of the current surface so that it contains
|
||||
* fully opaque alpha values.
|
||||
*/
|
||||
static void
|
||||
MTLContext_InitAlphaChannel()
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLContext_InitAlphaChannel");
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLContext_InitAlphaChannel");
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the MTLContext associated with the given destination surface,
|
||||
* makes the context current for those surfaces, updates the destination
|
||||
* viewport, and then returns a pointer to the MTLContext.
|
||||
*/
|
||||
MTLContext *
|
||||
MTLContext_SetSurfaces(JNIEnv *env, jlong pSrc, jlong pDst)
|
||||
{
|
||||
BMTLSDOps *srcOps = (BMTLSDOps *)jlong_to_ptr(pSrc);
|
||||
BMTLSDOps *dstOps = (BMTLSDOps *)jlong_to_ptr(pDst);
|
||||
MTLContext *mtlc = NULL;
|
||||
|
||||
if (srcOps == NULL || dstOps == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLContext_SetSurfaces: ops are null");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
J2dTraceLn6(J2D_TRACE_VERBOSE, "MTLContext_SetSurfaces: bsrc=%p (tex=%p type=%d), bdst=%p (tex=%p type=%d)", srcOps, srcOps->pTexture, srcOps->drawableType, dstOps, dstOps->pTexture, dstOps->drawableType);
|
||||
|
||||
if (dstOps->drawableType == MTLSD_TEXTURE) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR,
|
||||
"MTLContext_SetSurfaces: texture cannot be used as destination");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (dstOps->drawableType == MTLSD_UNDEFINED) {
|
||||
// initialize the surface as an OGLSD_WINDOW
|
||||
if (!MTLSD_InitMTLWindow(env, dstOps)) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR,
|
||||
"MTLContext_SetSurfaces: could not init OGL window");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// make the context current
|
||||
MTLSDOps *dstCGLOps = (MTLSDOps *)dstOps->privOps;
|
||||
mtlc = dstCGLOps->configInfo->context;
|
||||
|
||||
if (mtlc == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR,
|
||||
"MTLContext_SetSurfaces: could not make context current");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// update the viewport
|
||||
MTLContext_SetViewport(srcOps, dstOps);
|
||||
|
||||
// perform additional one-time initialization, if necessary
|
||||
if (dstOps->needsInit) {
|
||||
if (dstOps->isOpaque) {
|
||||
// in this case we are treating the destination as opaque, but
|
||||
// to do so, first we need to ensure that the alpha channel
|
||||
// is filled with fully opaque values (see 6319663)
|
||||
MTLContext_InitAlphaChannel();
|
||||
}
|
||||
dstOps->needsInit = JNI_FALSE;
|
||||
}
|
||||
|
||||
return mtlc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the current clip state (disables both scissor and depth tests).
|
||||
*/
|
||||
void
|
||||
MTLContext_ResetClip(MTLContext *mtlc)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLContext_ResetClip");
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLContext_ResetClip");
|
||||
mtlc->useClip = JNI_FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Metal scissor bounds to the provided rectangular clip bounds.
|
||||
*/
|
||||
void
|
||||
MTLContext_SetRectClip(MTLContext *mtlc, BMTLSDOps *dstOps,
|
||||
jint x1, jint y1, jint x2, jint y2)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLContext_SetRectClip");
|
||||
jint width = x2 - x1;
|
||||
jint height = y2 - y1;
|
||||
|
||||
J2dTraceLn4(J2D_TRACE_INFO, "MTLContext_SetRectClip: x=%d y=%d w=%d h=%d", x1, y1, width, height);
|
||||
|
||||
mtlc->mtlClipRect.x = x1;
|
||||
mtlc->mtlClipRect.y = y1;
|
||||
mtlc->mtlClipRect.width = width;
|
||||
mtlc->mtlClipRect.height = height;
|
||||
mtlc->useClip = JNI_TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up a complex (shape) clip using the OpenGL depth buffer. This
|
||||
* method prepares the depth buffer so that the clip Region spans can
|
||||
* be "rendered" into it. The depth buffer is first cleared, then the
|
||||
* depth func is setup so that when we render the clip spans,
|
||||
* nothing is rendered into the color buffer, but for each pixel that would
|
||||
* be rendered, a non-zero value is placed into that location in the depth
|
||||
* buffer. With depth test enabled, pixels will only be rendered into the
|
||||
* color buffer if the corresponding value at that (x,y) location in the
|
||||
* depth buffer differs from the incoming depth value.
|
||||
*/
|
||||
void
|
||||
MTLContext_BeginShapeClip(MTLContext *mtlc)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLContext_BeginShapeClip");
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLContext_BeginShapeClip");
|
||||
}
|
||||
|
||||
/**
|
||||
* Finishes setting up the shape clip by resetting the depth func
|
||||
* so that future rendering operations will once again be written into the
|
||||
* color buffer (while respecting the clip set up in the depth buffer).
|
||||
*/
|
||||
void
|
||||
MTLContext_EndShapeClip(MTLContext *mtlc, BMTLSDOps *dstOps)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLContext_EndShapeClip");
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLContext_EndShapeClip");
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the OpenGL state responsible for applying extra alpha. This
|
||||
* step is only necessary for any operation that uses glDrawPixels() or
|
||||
* glCopyPixels() with a non-1.0f extra alpha value. Since the source is
|
||||
* always premultiplied, we apply the extra alpha value to both alpha and
|
||||
* color components using GL_*_SCALE.
|
||||
*/
|
||||
void
|
||||
MTLContext_SetExtraAlpha(jfloat ea)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLContext_SetExtraAlpha");
|
||||
J2dTraceLn1(J2D_TRACE_INFO, "MTLContext_SetExtraAlpha: ea=%f", ea);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets all OpenGL compositing state (disables blending and logic
|
||||
* operations).
|
||||
*/
|
||||
void
|
||||
MTLContext_ResetComposite(MTLContext *mtlc)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLContext_ResetComposite");
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLContext_ResetComposite");
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the OpenGL blending state. XOR mode is disabled and the
|
||||
* appropriate blend functions are setup based on the AlphaComposite rule
|
||||
* constant.
|
||||
*/
|
||||
void MTLContext_SetAlphaComposite(MTLContext *mtlc, jint rule, jfloat extraAlpha, jint flags) {
|
||||
J2dTracePrimitive("MTLContext_SetAlphaComposite");
|
||||
J2dTraceLn3(J2D_TRACE_INFO, "MTLContext_SetAlphaComposite: rule=%d, extraAlpha=%1.2f, flags=%d", rule, extraAlpha, flags);
|
||||
|
||||
mtlc->extraAlpha = extraAlpha;
|
||||
mtlc->alphaCompositeRule = rule;
|
||||
}
|
||||
|
||||
jboolean MTLContext_IsBlendingDisabled(MTLContext *mtlc) {
|
||||
// TODO: hold case mtlc->alphaCompositeRule == RULE_SrcOver && sun_java2d_pipe_BufferedContext_SRC_IS_OPAQUE
|
||||
return mtlc->alphaCompositeRule == RULE_Src && (mtlc->extraAlpha - 1.0f < 0.001f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the OpenGL logic op state to XOR mode. Blending is disabled
|
||||
* before enabling logic op mode. The XOR pixel value will be applied
|
||||
* later in the MTLContext_SetColor() method.
|
||||
*/
|
||||
void
|
||||
MTLContext_SetXorComposite(MTLContext *mtlc, jint xorPixel)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLContext_SetXorComposite");
|
||||
J2dTraceLn1(J2D_TRACE_INFO,
|
||||
"MTLContext_SetXorComposite: xorPixel=%08x", xorPixel);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the OpenGL transform state back to the identity matrix.
|
||||
*/
|
||||
void
|
||||
MTLContext_ResetTransform(MTLContext *mtlc)
|
||||
{
|
||||
J2dTracePrimitive("MTLContext_ResetTransform");
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLContext_ResetTransform");
|
||||
mtlc->useTransform = JNI_FALSE;
|
||||
}
|
||||
|
||||
static void _traceMatrix(simd_float4x4 * mtx) {
|
||||
for (int row = 0; row < 4; ++row) {
|
||||
J2dTraceLn4(J2D_TRACE_VERBOSE, " [%lf %lf %lf %lf]",
|
||||
mtx->columns[0][row], mtx->columns[1][row], mtx->columns[2][row], mtx->columns[3][row]);
|
||||
}
|
||||
}
|
||||
|
||||
static void _setTransform(MTLContext *mtlc, id<MTLTexture> dest,
|
||||
jdouble m00, jdouble m10,
|
||||
jdouble m01, jdouble m11,
|
||||
jdouble m02, jdouble m12
|
||||
) {
|
||||
if (dest == nil) {
|
||||
J2dTraceLn(J2D_TRACE_ERROR, "MTLContext_SetTransformMetal: current dest is null");
|
||||
return;
|
||||
}
|
||||
|
||||
const double dw = dest.width;
|
||||
const double dh = dest.height;
|
||||
|
||||
simd_float4x4 transform;
|
||||
memset(&transform, 0, sizeof(transform));
|
||||
transform.columns[0][0] = m00;
|
||||
transform.columns[0][1] = m10;
|
||||
transform.columns[1][0] = m01;
|
||||
transform.columns[1][1] = m11;
|
||||
transform.columns[3][0] = m02;
|
||||
transform.columns[3][1] = m12;
|
||||
transform.columns[3][3] = 1.0;
|
||||
transform.columns[4][4] = 1.0;
|
||||
|
||||
|
||||
simd_float4x4 normalize;
|
||||
memset(&normalize, 0, sizeof(normalize));
|
||||
normalize.columns[0][0] = 2/dw;
|
||||
normalize.columns[1][1] = -2/dh;
|
||||
normalize.columns[3][0] = -1.f;
|
||||
normalize.columns[3][1] = 1.f;
|
||||
normalize.columns[3][3] = 1.0;
|
||||
normalize.columns[4][4] = 1.0;
|
||||
|
||||
mtlc->transform4x4 = simd_mul(normalize, transform);
|
||||
mtlc->useTransform = JNI_TRUE;
|
||||
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLContext_SetTransform");
|
||||
// _traceMatrix(&(transform));
|
||||
// _traceMatrix(&(normalize));
|
||||
// _traceMatrix(&(mtlc->transform4x4));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the OpenGL transform state by setting the modelview transform
|
||||
* using the given matrix parameters.
|
||||
*
|
||||
* REMIND: it may be worthwhile to add serial id to AffineTransform, so we
|
||||
* could do a quick check to see if the xform has changed since
|
||||
* last time... a simple object compare won't suffice...
|
||||
*/
|
||||
void
|
||||
MTLContext_SetTransform(MTLContext *mtlc,
|
||||
jdouble m00, jdouble m10,
|
||||
jdouble m01, jdouble m11,
|
||||
jdouble m02, jdouble m12)
|
||||
{
|
||||
J2dTracePrimitive("MTLContext_SetTransform");
|
||||
|
||||
const BMTLSDOps * bmtlsdOps = MTLRenderQueue_GetCurrentDestination();
|
||||
if (bmtlsdOps == NULL) {
|
||||
J2dTraceLn(J2D_TRACE_ERROR, "MTLContext_SetTransform: current dest is null");
|
||||
return;
|
||||
}
|
||||
|
||||
_setTransform(mtlc, bmtlsdOps->pTexture, m00, m10, m01, m11, m02, m12);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a 2D texture of the given format and dimensions and returns the
|
||||
* texture object identifier. This method is typically used to create a
|
||||
* temporary texture for intermediate work, such as in the
|
||||
* MTLContext_InitBlitTileTexture() method below.
|
||||
*/
|
||||
jint
|
||||
MTLContext_CreateBlitTexture(jint internalFormat, jint pixelFormat,
|
||||
jint width, jint height)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLContext_CreateBlitTexture");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a small texture tile for use with tiled blit operations (see
|
||||
* MTLBlitLoops.c and MTLMaskBlit.c for usage examples). The texture ID for
|
||||
* the tile is stored in the given MTLContext. The tile is initially filled
|
||||
* with garbage values, but the tile is updated as needed (via
|
||||
* glTexSubImage2D()) with real RGBA values used in tiled blit situations.
|
||||
* The internal format for the texture is GL_RGBA8, which should be sufficient
|
||||
* for storing system memory surfaces of any known format (see PixelFormats
|
||||
* for a list of compatible surface formats).
|
||||
*/
|
||||
jboolean
|
||||
MTLContext_InitBlitTileTexture(MTLContext *mtlc)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLContext_InitBlitTileTexture");
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLContext_InitBlitTileTexture");
|
||||
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys the OpenGL resources associated with the given MTLContext.
|
||||
* It is required that the native context associated with the MTLContext
|
||||
* be made current prior to calling this method.
|
||||
*/
|
||||
void
|
||||
MTLContext_DestroyContextResources(MTLContext *mtlc)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLContext_DestroyContextResources");
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLContext_DestroyContextResources");
|
||||
|
||||
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
|
||||
[mtlc->mtlTexturePool release];
|
||||
[mtlc->mtlDevice release];
|
||||
mtlc->mtlDevice = nil;
|
||||
|
||||
[pool drain];
|
||||
//if (mtlc->blitTextureID != 0) {
|
||||
//}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_java2d_metal_MTLContext
|
||||
* Method: getMTLIdString
|
||||
* Signature: ()Ljava/lang/String;
|
||||
*/
|
||||
JNIEXPORT jstring JNICALL Java_sun_java2d_metal_MTLContext_getMTLIdString
|
||||
(JNIEnv *env, jclass mtlcc)
|
||||
{
|
||||
char *vendor, *renderer, *version;
|
||||
char *pAdapterId;
|
||||
jobject ret = NULL;
|
||||
int len;
|
||||
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MTLRenderPassDescriptor * _createRenderPassDesc(id<MTLTexture> dest) {
|
||||
MTLRenderPassDescriptor * result = [MTLRenderPassDescriptor renderPassDescriptor];
|
||||
if (result == nil)
|
||||
return nil;
|
||||
|
||||
if (dest == nil) {
|
||||
J2dTraceLn(J2D_TRACE_ERROR, "_createRenderPassDesc: destination texture is null");
|
||||
return nil;
|
||||
}
|
||||
|
||||
MTLRenderPassColorAttachmentDescriptor * ca = result.colorAttachments[0];
|
||||
ca.texture = dest;
|
||||
ca.loadAction = MTLLoadActionLoad;
|
||||
ca.clearColor = MTLClearColorMake(0.0f, 0.9f, 0.0f, 1.0f);
|
||||
ca.storeAction = MTLStoreActionStore;
|
||||
return result;
|
||||
}
|
||||
|
||||
void MTLContext_SetColor(MTLContext *mtlc, int r, int g, int b, int a) {
|
||||
mtlc->mtlColor = 0;
|
||||
mtlc->mtlColor |= (r & (0xFF)) << 16;
|
||||
mtlc->mtlColor |= (g & (0xFF)) << 8;
|
||||
mtlc->mtlColor |= b & (0xFF);
|
||||
mtlc->mtlColor |= (a & (0xFF)) << 24;
|
||||
J2dTraceLn4(J2D_TRACE_INFO, "MTLContext_SetColor (%d, %d, %d) %d", r,g,b,a);
|
||||
}
|
||||
|
||||
void MTLContext_SetColorInt(MTLContext *mtlc, int pixel) {
|
||||
mtlc->mtlColor = pixel;
|
||||
J2dTraceLn5(J2D_TRACE_INFO, "MTLContext_SetColorInt: pixel=%08x [r=%d g=%d b=%d a=%d]", pixel, (pixel >> 16) & (0xFF), (pixel >> 8) & 0xFF, (pixel) & 0xFF, (pixel >> 24) & 0xFF);
|
||||
}
|
||||
|
||||
static id<MTLCommandBuffer> _getCommandBuffer(MTLContext *mtlc) {
|
||||
if (mtlc == NULL)
|
||||
return nil;
|
||||
if (mtlc->mtlCommandBuffer == nil) {
|
||||
// NOTE: Command queues are thread-safe and allow multiple outstanding command buffers to be encoded simultaneously.
|
||||
mtlc->mtlCommandBuffer = [[mtlc->mtlCommandQueue commandBuffer] retain];// released in [layer blitTexture]
|
||||
}
|
||||
return mtlc->mtlCommandBuffer;
|
||||
}
|
||||
|
||||
// NOTE: debug parameners will be removed soon
|
||||
id<MTLRenderCommandEncoder> _createRenderEncoder(MTLContext *mtlc, id<MTLTexture> dest, int clearRed/*debug param*/) {
|
||||
id<MTLCommandBuffer> cb = _getCommandBuffer(mtlc);
|
||||
if (cb == nil)
|
||||
return nil;
|
||||
|
||||
MTLRenderPassDescriptor * rpd = _createRenderPassDesc(dest);
|
||||
if (rpd == nil)
|
||||
return nil;
|
||||
|
||||
if (clearRed > 0) {//dbg
|
||||
MTLRenderPassColorAttachmentDescriptor * ca = rpd.colorAttachments[0];
|
||||
ca.loadAction = MTLLoadActionClear;
|
||||
ca.clearColor = MTLClearColorMake(clearRed/255.0f, 0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
// J2dTraceLn1(J2D_TRACE_VERBOSE, "MTLContext: created render encoder to draw on tex=%p", dest);
|
||||
|
||||
id <MTLRenderCommandEncoder> mtlEncoder = [cb renderCommandEncoderWithDescriptor:rpd];
|
||||
|
||||
// set viewport and pipeline state
|
||||
dest = rpd.colorAttachments[0].texture;
|
||||
MTLViewport vp = {0, 0, dest.width, dest.height, 0, 1};
|
||||
[mtlEncoder setViewport:vp];
|
||||
[mtlEncoder setRenderPipelineState:mtlc->mtlPipelineState];
|
||||
|
||||
if (mtlc->useClip)
|
||||
[mtlEncoder setScissorRect:mtlc->mtlClipRect];
|
||||
|
||||
// set color from ctx
|
||||
int r = (mtlc->mtlColor >> 16) & (0xFF);
|
||||
int g = (mtlc->mtlColor >> 8) & 0xFF;
|
||||
int b = (mtlc->mtlColor) & 0xFF;
|
||||
int a = (mtlc->mtlColor >> 24) & 0xFF;
|
||||
|
||||
vector_float4 color = {r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f};
|
||||
struct FrameUniforms uf = {color};
|
||||
[mtlEncoder setVertexBytes:&uf length:sizeof(uf) atIndex:FrameUniformBuffer];
|
||||
|
||||
return mtlEncoder;
|
||||
}
|
||||
|
||||
id<MTLRenderCommandEncoder> MTLContext_CreateRenderEncoder(MTLContext *mtlc, id<MTLTexture> dest) {
|
||||
return _createRenderEncoder(mtlc, dest, -1);
|
||||
}
|
||||
|
||||
// NOTE: debug parameners will be removed soon
|
||||
id<MTLRenderCommandEncoder> _createSamplingEncoder(MTLContext * mtlc, id<MTLTexture> dest, int clearRed/*debug param*/) {
|
||||
id<MTLCommandBuffer> cb = _getCommandBuffer(mtlc);
|
||||
if (cb == nil)
|
||||
return nil;
|
||||
|
||||
MTLRenderPassDescriptor * rpd = _createRenderPassDesc(dest);
|
||||
if (rpd == nil)
|
||||
return nil;
|
||||
|
||||
if (clearRed > 0) {//dbg
|
||||
MTLRenderPassColorAttachmentDescriptor *ca = rpd.colorAttachments[0];
|
||||
ca.loadAction = MTLLoadActionClear;
|
||||
ca.clearColor = MTLClearColorMake(clearRed/255.f, 0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
id <MTLRenderCommandEncoder> mtlEncoder = [cb renderCommandEncoderWithDescriptor:rpd];
|
||||
//J2dTraceLn1(J2D_TRACE_VERBOSE, "MTLContext: created sampling encoder to draw on tex=%p", dest);
|
||||
|
||||
// set viewport and pipeline state
|
||||
MTLViewport vp = {0, 0, dest.width, dest.height, 0, 1};
|
||||
[mtlEncoder setViewport:vp];
|
||||
if (mtlc->alphaCompositeRule == RULE_Src)
|
||||
[mtlEncoder setRenderPipelineState:mtlc->mtlBlitPipelineState];
|
||||
else if (mtlc->alphaCompositeRule == RULE_SrcOver)
|
||||
[mtlEncoder setRenderPipelineState:mtlc->mtlBlitSrcOverPipelineState];
|
||||
else {
|
||||
J2dTraceLn2(J2D_TRACE_ERROR, "MTLContext: alpha-composite rule %d isn't implemented (draw on %p)", mtlc->alphaCompositeRule, dest);
|
||||
[mtlEncoder setRenderPipelineState:mtlc->mtlBlitPipelineState];
|
||||
}
|
||||
|
||||
return mtlEncoder;
|
||||
}
|
||||
|
||||
// NOTE: debug parameners will be removed soon
|
||||
id<MTLRenderCommandEncoder> _createSamplingTransformEncoder(MTLContext * mtlc, id<MTLTexture> dest, int clearRed/*debug param*/) {
|
||||
id<MTLCommandBuffer> cb = _getCommandBuffer(mtlc);
|
||||
if (cb == nil)
|
||||
return nil;
|
||||
|
||||
MTLRenderPassDescriptor * rpd = _createRenderPassDesc(dest);
|
||||
if (rpd == nil)
|
||||
return nil;
|
||||
|
||||
if (clearRed > 0) {//dbg
|
||||
MTLRenderPassColorAttachmentDescriptor *ca = rpd.colorAttachments[0];
|
||||
ca.loadAction = MTLLoadActionClear;
|
||||
ca.clearColor = MTLClearColorMake(clearRed/255.f, 0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
id <MTLRenderCommandEncoder> mtlEncoder = [cb renderCommandEncoderWithDescriptor:rpd];
|
||||
//J2dTraceLn1(J2D_TRACE_VERBOSE, "MTLContext: created sampling-transform encoder to draw on tex=%p", dest);
|
||||
|
||||
// set viewport and pipeline state
|
||||
MTLViewport vp = {0, 0, dest.width, dest.height, 0, 1};
|
||||
[mtlEncoder setViewport:vp];
|
||||
if (mtlc->alphaCompositeRule == RULE_Src)
|
||||
[mtlEncoder setRenderPipelineState:mtlc->mtlBlitMatrixPipelineState];
|
||||
else if (mtlc->alphaCompositeRule == RULE_SrcOver)
|
||||
[mtlEncoder setRenderPipelineState:mtlc->mtlBlitMatrixSrcOverPipelineState];
|
||||
else {
|
||||
J2dTraceLn2(J2D_TRACE_ERROR, "MTLContext: alpha-composite rule %d isn't implemented (draw on %p with transform)", mtlc->alphaCompositeRule, dest);
|
||||
[mtlEncoder setRenderPipelineState:mtlc->mtlBlitMatrixPipelineState];
|
||||
}
|
||||
|
||||
[mtlEncoder setVertexBytes:&(mtlc->transform4x4) length:sizeof(mtlc->transform4x4) atIndex:FrameUniformBuffer];
|
||||
|
||||
return mtlEncoder;
|
||||
}
|
||||
|
||||
id<MTLRenderCommandEncoder> MTLContext_CreateSamplingEncoder(MTLContext * mtlc, id<MTLTexture> dest) {
|
||||
if (mtlc->useTransform)
|
||||
return _createSamplingTransformEncoder(mtlc, dest, -1);
|
||||
return _createSamplingEncoder(mtlc, dest, -1);
|
||||
}
|
||||
|
||||
id<MTLBlitCommandEncoder> MTLContext_CreateBlitEncoder(MTLContext *mtlc) {
|
||||
id<MTLCommandBuffer> cb = _getCommandBuffer(mtlc);
|
||||
return cb == nil ? nil : [cb blitCommandEncoder];
|
||||
}
|
||||
|
||||
#endif /* !HEADLESS */
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
#ifndef MTLFuncs_h_Included
|
||||
#define MTLFuncs_h_Included
|
||||
|
||||
#ifdef MACOSX
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
#include "jni.h"
|
||||
#include "Trace.h"
|
||||
|
||||
jboolean MTLFuncs_OpenLibrary();
|
||||
void MTLFuncs_CloseLibrary();
|
||||
jboolean MTLFuncs_InitPlatformFuncs();
|
||||
jboolean MTLFuncs_InitBaseFuncs();
|
||||
jboolean MTLFuncs_InitExtFuncs();
|
||||
|
||||
#endif /* MTLFuncs_h_Included */
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
#ifndef HEADLESS
|
||||
|
||||
#include "MTLFuncs.h"
|
||||
|
||||
|
||||
jboolean
|
||||
MTLFuncs_OpenLibrary()
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLFuncs_OpenLibrary");
|
||||
|
||||
J2dRlsTraceLn(J2D_TRACE_INFO, "MTLFuncs_OpenLibrary");
|
||||
|
||||
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
MTLFuncs_CloseLibrary()
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLFuncs_CloseLibrary");
|
||||
J2dRlsTraceLn(J2D_TRACE_INFO, "MTLFuncs_CloseLibrary");
|
||||
|
||||
}
|
||||
|
||||
jboolean
|
||||
MTLFuncs_InitPlatformFuncs()
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLFuncs_InitPlatformFuncs");
|
||||
J2dRlsTraceLn(J2D_TRACE_INFO, "MTLFuncs_InitPlatformFuncs");
|
||||
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
jboolean
|
||||
MTLFuncs_InitBaseFuncs()
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLFuncs_InitBaseFuncs");
|
||||
J2dRlsTraceLn(J2D_TRACE_INFO, "MTLFuncs_InitBaseFuncs");
|
||||
|
||||
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
jboolean
|
||||
MTLFuncs_InitExtFuncs()
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLFuncs_InitExtFuncs");
|
||||
J2dRlsTraceLn(J2D_TRACE_INFO, "MTLFuncs_InitExtFuncs");
|
||||
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
#endif /* !HEADLESS */
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
#ifndef MTLGraphicsConfig_h_Included
|
||||
#define MTLGraphicsConfig_h_Included
|
||||
|
||||
#import "jni.h"
|
||||
#import "MTLSurfaceDataBase.h"
|
||||
#import "MTLContext.h"
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <Metal/Metal.h>
|
||||
#import <MetalKit/MetalKit.h>
|
||||
|
||||
|
||||
@interface MTLGraphicsConfigUtil : NSObject {}
|
||||
+ (void) _getMTLConfigInfo: (NSMutableArray *)argValue;
|
||||
@end
|
||||
|
||||
// REMIND: Using an NSOpenGLPixelBuffer as the scratch surface has been
|
||||
// problematic thus far (seeing garbage and flickering when switching
|
||||
// between an NSView and the scratch surface), so the following enables
|
||||
// an alternate codepath that uses a hidden NSWindow/NSView as the scratch
|
||||
// surface, for the purposes of making a context current in certain
|
||||
// situations. It appears that calling [NSOpenGLContext setView] too
|
||||
// frequently contributes to the bad behavior, so we should try to avoid
|
||||
// switching to the scratch surface whenever possible.
|
||||
|
||||
/* Do we need this if we are using all off-screen drawing ? */
|
||||
#define USE_NSVIEW_FOR_SCRATCH 1
|
||||
|
||||
/* Uncomment to have an additional CAOGLLayer instance tied to
|
||||
* each instance, which can be used to test remoting the layer
|
||||
* to an out of process window. The additional layer is needed
|
||||
* because a layer can only be attached to one context (view/window).
|
||||
* This is only for testing purposes and can be removed if/when no
|
||||
* longer needed.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* The MTLGraphicsConfigInfo structure contains information specific to a
|
||||
* given CGLGraphicsConfig (pixel format).
|
||||
*
|
||||
* jint screen;
|
||||
* The screen and PixelFormat for the associated CGLGraphicsConfig.
|
||||
*
|
||||
* NSOpenGLPixelFormat *pixfmt;
|
||||
* The pixel format of the native NSOpenGL context.
|
||||
*
|
||||
* MTLContext *context;
|
||||
* The context associated with this CGLGraphicsConfig.
|
||||
*/
|
||||
typedef struct _MTLGraphicsConfigInfo {
|
||||
jint screen;
|
||||
NSOpenGLPixelFormat *pixfmt;
|
||||
MTLContext *context;
|
||||
} MTLGraphicsConfigInfo;
|
||||
|
||||
#endif /* MTLGraphicsConfig_h_Included */
|
||||
@@ -0,0 +1,327 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
#import "sun_java2d_metal_MTLGraphicsConfig.h"
|
||||
|
||||
#import "MTLGraphicsConfig.h"
|
||||
#import "MTLSurfaceData.h"
|
||||
#import "ThreadUtilities.h"
|
||||
|
||||
#import <stdlib.h>
|
||||
#import <string.h>
|
||||
#import <ApplicationServices/ApplicationServices.h>
|
||||
#import <JavaNativeFoundation/JavaNativeFoundation.h>
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark "--- Mac OS X specific methods for GL pipeline ---"
|
||||
|
||||
/**
|
||||
* Disposes all memory and resources associated with the given
|
||||
* CGLGraphicsConfigInfo (including its native MTLContext data).
|
||||
*/
|
||||
void
|
||||
MTLGC_DestroyMTLGraphicsConfig(jlong pConfigInfo)
|
||||
{
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLGC_DestroyMTLGraphicsConfig");
|
||||
|
||||
MTLGraphicsConfigInfo *mtlinfo =
|
||||
(MTLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo);
|
||||
if (mtlinfo == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR,
|
||||
"MTLGC_DestroyMTLGraphicsConfig: info is null");
|
||||
return;
|
||||
}
|
||||
|
||||
MTLContext *mtlc = (MTLContext*)mtlinfo->context;
|
||||
if (mtlc != NULL) {
|
||||
MTLContext_DestroyContextResources(mtlc);
|
||||
mtlinfo->context = NULL;
|
||||
}
|
||||
free(mtlinfo);
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark "--- MTLGraphicsConfig methods ---"
|
||||
|
||||
|
||||
/**
|
||||
* Attempts to initialize CGL and the core OpenGL library.
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_sun_java2d_metal_MTLGraphicsConfig_initMTL
|
||||
(JNIEnv *env, jclass cglgc)
|
||||
{
|
||||
J2dRlsTraceLn(J2D_TRACE_INFO, "MTLGraphicsConfig_initMTL");
|
||||
|
||||
if (!MTLFuncs_OpenLibrary()) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
if (!MTLFuncs_InitPlatformFuncs() ||
|
||||
!MTLFuncs_InitBaseFuncs() ||
|
||||
!MTLFuncs_InitExtFuncs())
|
||||
{
|
||||
MTLFuncs_CloseLibrary();
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determines whether the CGL pipeline can be used for a given GraphicsConfig
|
||||
* provided its screen number and visual ID. If the minimum requirements are
|
||||
* met, the native CGLGraphicsConfigInfo structure is initialized for this
|
||||
* GraphicsConfig with the necessary information (pixel format, etc.)
|
||||
* and a pointer to this structure is returned as a jlong. If
|
||||
* initialization fails at any point, zero is returned, indicating that CGL
|
||||
* cannot be used for this GraphicsConfig (we should fallback on an existing
|
||||
* 2D pipeline).
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_sun_java2d_metal_MTLGraphicsConfig_getMTLConfigInfo
|
||||
(JNIEnv *env, jclass cglgc, jint displayID, jstring mtlShadersLib)
|
||||
{
|
||||
jlong ret = 0L;
|
||||
JNF_COCOA_ENTER(env);
|
||||
NSMutableArray * retArray = [NSMutableArray arrayWithCapacity:3];
|
||||
[retArray addObject: [NSNumber numberWithInt: (int)displayID]];
|
||||
[retArray addObject: [NSString stringWithUTF8String: JNU_GetStringPlatformChars(env, mtlShadersLib, 0)]];
|
||||
if ([NSThread isMainThread]) {
|
||||
[MTLGraphicsConfigUtil _getMTLConfigInfo: retArray];
|
||||
} else {
|
||||
[MTLGraphicsConfigUtil performSelectorOnMainThread: @selector(_getMTLConfigInfo:) withObject: retArray waitUntilDone: YES];
|
||||
}
|
||||
NSNumber * num = (NSNumber *)[retArray objectAtIndex: 0];
|
||||
ret = (jlong)[num longValue];
|
||||
JNF_COCOA_EXIT(env);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static struct TxtVertex verts[PGRAM_VERTEX_COUNT] = {
|
||||
{{-1.0, 1.0, 0.0}, {0.0, 0.0}},
|
||||
{{1.0, 1.0, 0.0}, {1.0, 0.0}},
|
||||
{{1.0, -1.0, 0.0}, {1.0, 1.0}},
|
||||
{{1.0, -1.0, 0.0}, {1.0, 1.0}},
|
||||
{{-1.0, -1.0, 0.0}, {0.0, 1.0}},
|
||||
{{-1.0, 1.0, 0.0}, {0.0, 0.0}}
|
||||
};
|
||||
|
||||
|
||||
@implementation MTLGraphicsConfigUtil
|
||||
+ (void) _getMTLConfigInfo: (NSMutableArray *)argValue {
|
||||
AWT_ASSERT_APPKIT_THREAD;
|
||||
|
||||
jint displayID = (jint)[(NSNumber *)[argValue objectAtIndex: 0] intValue];
|
||||
NSString *mtlShadersLib = (NSString *)[argValue objectAtIndex: 1];
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
|
||||
[argValue removeAllObjects];
|
||||
|
||||
J2dRlsTraceLn(J2D_TRACE_INFO, "MTLGraphicsConfig_getMTLConfigInfo");
|
||||
|
||||
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
|
||||
NSRect contentRect = NSMakeRect(0, 0, 64, 64);
|
||||
NSWindow *window =
|
||||
[[NSWindow alloc]
|
||||
initWithContentRect: contentRect
|
||||
styleMask: NSBorderlessWindowMask
|
||||
backing: NSBackingStoreBuffered
|
||||
defer: false];
|
||||
if (window == nil) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLGraphicsConfig_getMTLConfigInfo: NSWindow is NULL");
|
||||
[argValue addObject: [NSNumber numberWithLong: 0L]];
|
||||
return;
|
||||
}
|
||||
|
||||
NSView *scratchSurface =
|
||||
[[NSView alloc]
|
||||
initWithFrame: contentRect];
|
||||
if (scratchSurface == nil) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLGraphicsConfig_getMTLConfigInfo: NSView is NULL");
|
||||
[argValue addObject: [NSNumber numberWithLong: 0L]];
|
||||
return;
|
||||
}
|
||||
[window setContentView: scratchSurface];
|
||||
|
||||
MTLContext *mtlc = (MTLContext *)malloc(sizeof(MTLContext));
|
||||
if (mtlc == 0L) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLGC_InitMTLContext: could not allocate memory for mtlc");
|
||||
[argValue addObject: [NSNumber numberWithLong: 0L]];
|
||||
return;
|
||||
}
|
||||
memset(mtlc, 0, sizeof(MTLContext));
|
||||
|
||||
|
||||
mtlc->mtlDevice = [CGDirectDisplayCopyCurrentMetalDevice(displayID) retain];
|
||||
mtlc->mtlTexturePool = [[[MTLTexturePool alloc] initWithDevice:mtlc->mtlDevice] retain];
|
||||
|
||||
mtlc->mtlVertexBuffer = [[mtlc->mtlDevice newBufferWithBytes:verts
|
||||
length:sizeof(verts)
|
||||
options:MTLResourceCPUCacheModeDefaultCache] retain];
|
||||
|
||||
NSError *error = nil;
|
||||
|
||||
mtlc->mtlLibrary = [mtlc->mtlDevice newLibraryWithFile: mtlShadersLib error:&error];
|
||||
if (!mtlc->mtlLibrary) {
|
||||
NSLog(@"Failed to load library. error %@", error);
|
||||
exit(0);
|
||||
}
|
||||
id <MTLFunction> vertColFunc = [mtlc->mtlLibrary newFunctionWithName:@"vert_col"];
|
||||
id <MTLFunction> vertTxtFunc = [mtlc->mtlLibrary newFunctionWithName:@"vert_txt"];
|
||||
id <MTLFunction> vertTxtMatrixFunc = [mtlc->mtlLibrary newFunctionWithName:@"vert_txt_matrix"];
|
||||
id <MTLFunction> fragColFunc = [mtlc->mtlLibrary newFunctionWithName:@"frag_col"];
|
||||
id <MTLFunction> fragTxtFunc = [mtlc->mtlLibrary newFunctionWithName:@"frag_txt"];
|
||||
|
||||
// Create depth state.
|
||||
MTLDepthStencilDescriptor *depthDesc = [MTLDepthStencilDescriptor new];
|
||||
depthDesc.depthCompareFunction = MTLCompareFunctionLess;
|
||||
depthDesc.depthWriteEnabled = YES;
|
||||
|
||||
MTLVertexDescriptor *vertDesc = [MTLVertexDescriptor new];
|
||||
vertDesc.attributes[VertexAttributePosition].format = MTLVertexFormatFloat3;
|
||||
vertDesc.attributes[VertexAttributePosition].offset = 0;
|
||||
vertDesc.attributes[VertexAttributePosition].bufferIndex = MeshVertexBuffer;
|
||||
vertDesc.layouts[MeshVertexBuffer].stride = sizeof(struct Vertex);
|
||||
vertDesc.layouts[MeshVertexBuffer].stepRate = 1;
|
||||
vertDesc.layouts[MeshVertexBuffer].stepFunction = MTLVertexStepFunctionPerVertex;
|
||||
|
||||
// Create pipeline state.
|
||||
MTLRenderPipelineDescriptor *pipelineDesc = [MTLRenderPipelineDescriptor new];
|
||||
pipelineDesc.sampleCount = 1;
|
||||
pipelineDesc.vertexFunction = vertColFunc;
|
||||
pipelineDesc.fragmentFunction = fragColFunc;
|
||||
pipelineDesc.vertexDescriptor = vertDesc;
|
||||
pipelineDesc.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;
|
||||
mtlc->mtlPipelineState = [mtlc->mtlDevice newRenderPipelineStateWithDescriptor:pipelineDesc error:&error];
|
||||
if (!mtlc->mtlPipelineState) {
|
||||
NSLog(@"Failed to create pipeline state, error %@", error);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
vertDesc = [MTLVertexDescriptor new];
|
||||
vertDesc.attributes[VertexAttributePosition].format = MTLVertexFormatFloat3;
|
||||
vertDesc.attributes[VertexAttributePosition].offset = 0;
|
||||
vertDesc.attributes[VertexAttributePosition].bufferIndex = MeshVertexBuffer;
|
||||
vertDesc.attributes[VertexAttributeTexPos].format = MTLVertexFormatFloat2;
|
||||
vertDesc.attributes[VertexAttributeTexPos].offset = 3*sizeof(float);
|
||||
vertDesc.attributes[VertexAttributeTexPos].bufferIndex = MeshVertexBuffer;
|
||||
vertDesc.layouts[MeshVertexBuffer].stride = sizeof(struct TxtVertex);
|
||||
vertDesc.layouts[MeshVertexBuffer].stepRate = 1;
|
||||
vertDesc.layouts[MeshVertexBuffer].stepFunction = MTLVertexStepFunctionPerVertex;
|
||||
// Create pipeline state.
|
||||
pipelineDesc = [MTLRenderPipelineDescriptor new];
|
||||
pipelineDesc.sampleCount = 1;
|
||||
pipelineDesc.vertexFunction = vertTxtFunc;
|
||||
pipelineDesc.fragmentFunction = fragTxtFunc;
|
||||
pipelineDesc.vertexDescriptor = vertDesc;
|
||||
pipelineDesc.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;
|
||||
mtlc->mtlBlitPipelineState = [mtlc->mtlDevice newRenderPipelineStateWithDescriptor:pipelineDesc error:&error];
|
||||
if (!mtlc->mtlBlitPipelineState) {
|
||||
NSLog(@"Failed to create blit pipeline state, error %@", error);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
pipelineDesc = [MTLRenderPipelineDescriptor new];
|
||||
pipelineDesc.sampleCount = 1;
|
||||
pipelineDesc.vertexFunction = vertTxtMatrixFunc;
|
||||
pipelineDesc.fragmentFunction = fragTxtFunc;
|
||||
pipelineDesc.vertexDescriptor = vertDesc;
|
||||
pipelineDesc.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;
|
||||
mtlc->mtlBlitMatrixPipelineState = [mtlc->mtlDevice newRenderPipelineStateWithDescriptor:pipelineDesc error:&error];
|
||||
if (!mtlc->mtlBlitMatrixPipelineState) {
|
||||
NSLog(@"Failed to create blit with matrix pipeline state, error %@", error);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
pipelineDesc.vertexFunction = vertTxtFunc;
|
||||
pipelineDesc.colorAttachments[0].blendingEnabled = YES;
|
||||
//RGB = Source.rgb * SBF + Dest.rgb * DBF
|
||||
//A = Source.a * SBF + Dest.a * DBF
|
||||
//
|
||||
//default SRC:
|
||||
//DBF=0
|
||||
//SBF=1
|
||||
//
|
||||
// SRC_OVER (Porter-Duff Source Over Destination rule):
|
||||
// Ar = As + Ad*(1-As)
|
||||
// Cr = Cs + Cd*(1-As)
|
||||
pipelineDesc.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
|
||||
pipelineDesc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
|
||||
const bool isSourcePremultilied = NO; // <==> Cs = Cs_raw * As_raw
|
||||
if (!isSourcePremultilied)
|
||||
pipelineDesc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha;
|
||||
mtlc->mtlBlitSrcOverPipelineState = [mtlc->mtlDevice newRenderPipelineStateWithDescriptor:pipelineDesc error:&error];
|
||||
if (!mtlc->mtlBlitSrcOverPipelineState) {
|
||||
NSLog(@"Failed to create blit pipeline state (SrcOver), error %@", error);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
pipelineDesc.vertexFunction = vertTxtMatrixFunc;
|
||||
mtlc->mtlBlitMatrixSrcOverPipelineState = [mtlc->mtlDevice newRenderPipelineStateWithDescriptor:pipelineDesc error:&error];
|
||||
if (!mtlc->mtlBlitMatrixSrcOverPipelineState) {
|
||||
NSLog(@"Failed to create blit with matrix pipeline state (SrcOver), error %@", error);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
mtlc->mtlCommandBuffer = nil;
|
||||
|
||||
// Create command queue
|
||||
mtlc->mtlCommandQueue = [mtlc->mtlDevice newCommandQueue];
|
||||
|
||||
// create the MTLGraphicsConfigInfo record for this config
|
||||
MTLGraphicsConfigInfo *mtlinfo = (MTLGraphicsConfigInfo *)malloc(sizeof(MTLGraphicsConfigInfo));
|
||||
if (mtlinfo == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLGraphicsConfig_getMTLConfigInfo: could not allocate memory for mtlinfo");
|
||||
free(mtlc);
|
||||
[argValue addObject: [NSNumber numberWithLong: 0L]];
|
||||
return;
|
||||
}
|
||||
memset(mtlinfo, 0, sizeof(MTLGraphicsConfigInfo));
|
||||
mtlinfo->screen = displayID;
|
||||
mtlinfo->context = mtlc;
|
||||
|
||||
[argValue addObject: [NSNumber numberWithLong:ptr_to_jlong(mtlinfo)]];
|
||||
[pool drain];
|
||||
}
|
||||
@end //GraphicsConfigUtil
|
||||
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_java2d_metal_MTLGraphicsConfig_nativeGetMaxTextureSize
|
||||
(JNIEnv *env, jclass mtlgc)
|
||||
{
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLGraphicsConfig_nativeGetMaxTextureSize");
|
||||
|
||||
__block int max = 0;
|
||||
|
||||
// [ThreadUtilities performOnMainThreadWaiting:YES block:^(){
|
||||
// }];
|
||||
|
||||
return (jint)max;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
#ifndef MTLLayer_h_Included
|
||||
#define MTLLayer_h_Included
|
||||
#import <Metal/Metal.h>
|
||||
#import <MetalKit/MetalKit.h>
|
||||
#import "common.h"
|
||||
|
||||
#import <JavaNativeFoundation/JavaNativeFoundation.h>
|
||||
|
||||
@interface MTLLayer : CAMetalLayer
|
||||
{
|
||||
@private
|
||||
JNFWeakJObjectWrapper *javaLayer;
|
||||
|
||||
// intermediate buffer, used the RQ lock to synchronize
|
||||
MTLContext* ctx;
|
||||
float bufferWidth;
|
||||
float bufferHeight;
|
||||
id<MTLTexture> buffer;
|
||||
}
|
||||
|
||||
@property (nonatomic, retain) JNFWeakJObjectWrapper *javaLayer;
|
||||
@property (readwrite, assign) MTLContext* ctx;
|
||||
@property (readwrite, assign) float bufferWidth;
|
||||
@property (readwrite, assign) float bufferHeight;
|
||||
@property (readwrite, assign) id<MTLTexture> buffer;
|
||||
|
||||
- (id) initWithJavaLayer:(JNFWeakJObjectWrapper *)layer;
|
||||
|
||||
- (void) blitTexture:(id<MTLCommandBuffer>)commandBuf;
|
||||
- (void) fillParallelogramCtxX:(jfloat)x
|
||||
Y:(jfloat)y
|
||||
DX1:(jfloat)dx1
|
||||
DY1:(jfloat)dy1
|
||||
DX2:(jfloat)dx2
|
||||
DY2:(jfloat)dy2;
|
||||
@end
|
||||
|
||||
#endif /* CGLLayer_h_Included */
|
||||
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
#import "MTLGraphicsConfig.h"
|
||||
#import "MTLLayer.h"
|
||||
#import "ThreadUtilities.h"
|
||||
#import "LWCToolkit.h"
|
||||
#import "MTLSurfaceData.h"
|
||||
|
||||
#import "MTLBlitLoops.h"
|
||||
|
||||
@implementation MTLLayer
|
||||
|
||||
|
||||
@synthesize javaLayer;
|
||||
@synthesize ctx;
|
||||
@synthesize bufferWidth;
|
||||
@synthesize bufferHeight;
|
||||
@synthesize buffer;
|
||||
|
||||
- (id) initWithJavaLayer:(JNFWeakJObjectWrapper *)layer
|
||||
{
|
||||
AWT_ASSERT_APPKIT_THREAD;
|
||||
// Initialize ourselves
|
||||
self = [super init];
|
||||
if (self == nil) return self;
|
||||
|
||||
self.javaLayer = layer;
|
||||
|
||||
self.contentsGravity = kCAGravityTopLeft;
|
||||
|
||||
//Disable CALayer's default animation
|
||||
NSMutableDictionary * actions = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
|
||||
[NSNull null], @"anchorPoint",
|
||||
[NSNull null], @"bounds",
|
||||
[NSNull null], @"contents",
|
||||
[NSNull null], @"contentsScale",
|
||||
[NSNull null], @"onOrderIn",
|
||||
[NSNull null], @"onOrderOut",
|
||||
[NSNull null], @"position",
|
||||
[NSNull null], @"sublayers",
|
||||
nil];
|
||||
self.actions = actions;
|
||||
[actions release];
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) blitTexture:(id<MTLCommandBuffer>)commandBuf {
|
||||
if (self.ctx == NULL || self.javaLayer == NULL || self.buffer == nil || ctx->mtlDevice == nil) {
|
||||
J2dTraceLn4(J2D_TRACE_VERBOSE, "MTLLayer.blitTexture: uninitialized (mtlc=%p, javaLayer=%p, buffer=%p, devide=%p)", self.ctx, self.javaLayer, self.buffer, ctx->mtlDevice);
|
||||
return;
|
||||
}
|
||||
|
||||
if (commandBuf == nil) {
|
||||
J2dTraceLn(J2D_TRACE_VERBOSE, "MTLLayer.blitTexture: nothing to do (commandBuf is null)");
|
||||
return;
|
||||
}
|
||||
|
||||
@autoreleasepool {
|
||||
self.device = ctx->mtlDevice;
|
||||
self.pixelFormat = MTLPixelFormatBGRA8Unorm;
|
||||
self.framebufferOnly = NO;
|
||||
|
||||
self.drawableSize =
|
||||
CGSizeMake(self.buffer.width,
|
||||
self.buffer.height);
|
||||
|
||||
id<CAMetalDrawable> mtlDrawable = [self nextDrawable];
|
||||
if (mtlDrawable == nil) {
|
||||
return;
|
||||
}
|
||||
J2dTraceLn6(J2D_TRACE_INFO, "MTLLayer.blitTexture: src tex=%p (w=%d, h=%d), dst tex=%p (w=%d, h=%d)", self.buffer, self.buffer.width, self.buffer.height, mtlDrawable.texture, mtlDrawable.texture.width, mtlDrawable.texture.height);
|
||||
id <MTLBlitCommandEncoder> blitEncoder = [commandBuf blitCommandEncoder];
|
||||
[blitEncoder
|
||||
copyFromTexture:self.buffer sourceSlice:0 sourceLevel:0 sourceOrigin:MTLOriginMake(0, 0, 0) sourceSize:MTLSizeMake(self.buffer.width, self.buffer.height, 1)
|
||||
toTexture:mtlDrawable.texture destinationSlice:0 destinationLevel:0 destinationOrigin:MTLOriginMake(0, 0, 0)];
|
||||
[blitEncoder endEncoding];
|
||||
|
||||
[commandBuf presentDrawable:mtlDrawable];
|
||||
|
||||
[commandBuf addCompletedHandler:^(id <MTLCommandBuffer> cmdBuff) {
|
||||
[cmdBuff release];
|
||||
[ctx->mtlTexturePool markAllTexturesFree];
|
||||
}];
|
||||
|
||||
[commandBuf commit];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) dealloc {
|
||||
self.javaLayer = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
/*
|
||||
* Class: sun_java2d_metal_CGLLayer
|
||||
* Method: nativeCreateLayer
|
||||
* Signature: ()J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_sun_java2d_metal_MTLLayer_nativeCreateLayer
|
||||
(JNIEnv *env, jobject obj)
|
||||
{
|
||||
__block MTLLayer *layer = nil;
|
||||
|
||||
JNF_COCOA_ENTER(env);
|
||||
|
||||
JNFWeakJObjectWrapper *javaLayer = [JNFWeakJObjectWrapper wrapperWithJObject:obj withEnv:env];
|
||||
|
||||
[ThreadUtilities performOnMainThreadWaiting:YES block:^(){
|
||||
AWT_ASSERT_APPKIT_THREAD;
|
||||
|
||||
layer = [[MTLLayer alloc] initWithJavaLayer: javaLayer];
|
||||
}];
|
||||
|
||||
JNF_COCOA_EXIT(env);
|
||||
|
||||
return ptr_to_jlong(layer);
|
||||
}
|
||||
|
||||
// Must be called under the RQ lock.
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_java2d_metal_MTLLayer_validate
|
||||
(JNIEnv *env, jclass cls, jlong layerPtr, jobject surfaceData)
|
||||
{
|
||||
MTLLayer *layer = OBJC(layerPtr);
|
||||
|
||||
if (surfaceData != NULL) {
|
||||
BMTLSDOps *bmtlsdo = (BMTLSDOps*) SurfaceData_GetOps(env, surfaceData);
|
||||
layer.bufferWidth = bmtlsdo->width;
|
||||
layer.bufferHeight = bmtlsdo->width;
|
||||
layer.buffer = bmtlsdo->pTexture;
|
||||
layer.ctx = ((MTLSDOps *)bmtlsdo->privOps)->configInfo->context;
|
||||
layer.device = layer.ctx->mtlDevice;
|
||||
} else {
|
||||
layer.ctx = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_java2d_metal_MTLLayer_nativeSetScale
|
||||
(JNIEnv *env, jclass cls, jlong layerPtr, jdouble scale)
|
||||
{
|
||||
JNF_COCOA_ENTER(env);
|
||||
MTLLayer *layer = jlong_to_ptr(layerPtr);
|
||||
// We always call all setXX methods asynchronously, exception is only in
|
||||
// this method where we need to change native texture size and layer's scale
|
||||
// in one call on appkit, otherwise we'll get window's contents blinking,
|
||||
// during screen-2-screen moving.
|
||||
[ThreadUtilities performOnMainThreadWaiting:[NSThread isMainThread] block:^(){
|
||||
layer.contentsScale = scale;
|
||||
}];
|
||||
JNF_COCOA_EXIT(env);
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
#ifndef MTLMaskBlit_h_Included
|
||||
#define MTLMaskBlit_h_Included
|
||||
|
||||
#include "MTLContext.h"
|
||||
|
||||
void MTLMaskBlit_MaskBlit(JNIEnv *env, MTLContext *mtlc,
|
||||
jint dstx, jint dsty,
|
||||
jint width, jint height,
|
||||
void *pPixels);
|
||||
|
||||
#endif /* MTLMaskBlit_h_Included */
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
#ifndef HEADLESS
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <jlong.h>
|
||||
|
||||
#include "MTLMaskBlit.h"
|
||||
#include "MTLRenderQueue.h"
|
||||
#include "MTLSurfaceDataBase.h"
|
||||
|
||||
/**
|
||||
* REMIND: This method assumes that the dimensions of the incoming pixel
|
||||
* array are less than or equal to the cached blit texture tile;
|
||||
* these are rather fragile assumptions, and should be cleaned up...
|
||||
*/
|
||||
void
|
||||
MTLMaskBlit_MaskBlit(JNIEnv *env, MTLContext *mtlc,
|
||||
jint dstx, jint dsty,
|
||||
jint width, jint height,
|
||||
void *pPixels)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLMaskBlit_MaskBlit");
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLMaskBlit_MaskBlit");
|
||||
|
||||
if (width <= 0 || height <= 0) {
|
||||
J2dTraceLn(J2D_TRACE_WARNING,
|
||||
"MTLMaskBlit_MaskBlit: invalid dimensions");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* !HEADLESS */
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
#ifndef MTLMaskFill_h_Included
|
||||
#define MTLMaskFill_h_Included
|
||||
|
||||
#include "MTLContext.h"
|
||||
|
||||
void MTLMaskFill_MaskFill(MTLContext *mtlc,
|
||||
jint x, jint y, jint w, jint h,
|
||||
jint maskoff, jint maskscan, jint masklen,
|
||||
unsigned char *pMask);
|
||||
|
||||
#endif /* MTLMaskFill_h_Included */
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
#ifndef HEADLESS
|
||||
|
||||
#include "sun_java2d_metal_MTLMaskFill.h"
|
||||
|
||||
#include "MTLMaskFill.h"
|
||||
#include "MTLRenderQueue.h"
|
||||
#include "MTLVertexCache.h"
|
||||
|
||||
/**
|
||||
* This implementation first copies the alpha tile into a texture and then
|
||||
* maps that texture to the destination surface. This approach appears to
|
||||
* offer the best performance despite being a two-step process.
|
||||
*
|
||||
* When the source paint is a Color, we can simply use the GL_MODULATE
|
||||
* function to multiply the current color (already premultiplied with the
|
||||
* extra alpha value from the AlphaComposite) with the alpha value from
|
||||
* the mask texture tile. In picture form, this process looks like:
|
||||
*
|
||||
* A R G B
|
||||
* primary color Pa Pr Pg Pb (modulated with...)
|
||||
* texture unit 0 Ca Ca Ca Ca
|
||||
* ---------------------------------------
|
||||
* resulting color Ra Rr Rg Rb
|
||||
*
|
||||
* where:
|
||||
* Px = current color (already premultiplied by extra alpha)
|
||||
* Cx = coverage value from mask tile
|
||||
* Rx = resulting color/alpha component
|
||||
*
|
||||
* When the source paint is not a Color, it means that we are rendering with
|
||||
* a complex paint (e.g. GradientPaint, TexturePaint). In this case, we
|
||||
* rely on the GL_ARB_multitexture extension to effectively multiply the
|
||||
* paint fragments (autogenerated on texture unit 1, see the
|
||||
* MTLPaints_Set{Gradient,Texture,etc}Paint() methods for more details)
|
||||
* with the coverage values from the mask texture tile (provided on texture
|
||||
* unit 0), all of which is multiplied with the current color value (which
|
||||
* contains the extra alpha value). In picture form:
|
||||
*
|
||||
* A R G B
|
||||
* primary color Ea Ea Ea Ea (modulated with...)
|
||||
* texture unit 0 Ca Ca Ca Ca (modulated with...)
|
||||
* texture unit 1 Pa Pr Pg Pb
|
||||
* ---------------------------------------
|
||||
* resulting color Ra Rr Rg Rb
|
||||
*
|
||||
* where:
|
||||
* Ea = extra alpha
|
||||
* Cx = coverage value from mask tile
|
||||
* Px = gradient/texture paint color (generated for each fragment)
|
||||
* Rx = resulting color/alpha component
|
||||
*
|
||||
* Here are some descriptions of the many variables used in this method:
|
||||
* x,y - upper left corner of the tile destination
|
||||
* w,h - width/height of the mask tile
|
||||
* x0 - placekeeper for the original destination x location
|
||||
* tw,th - width/height of the actual texture tile in pixels
|
||||
* sx1,sy1 - upper left corner of the mask tile source region
|
||||
* sx2,sy2 - lower left corner of the mask tile source region
|
||||
* sx,sy - "current" upper left corner of the mask tile region of interest
|
||||
*/
|
||||
void
|
||||
MTLMaskFill_MaskFill(MTLContext *mtlc,
|
||||
jint x, jint y, jint w, jint h,
|
||||
jint maskoff, jint maskscan, jint masklen,
|
||||
unsigned char *pMask)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLMaskFill_MaskFill");
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLMaskFill_MaskFill");
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_java2d_metal_MTLMaskFill_maskFill
|
||||
(JNIEnv *env, jobject self,
|
||||
jint x, jint y, jint w, jint h,
|
||||
jint maskoff, jint maskscan, jint masklen,
|
||||
jbyteArray maskArray)
|
||||
{
|
||||
MTLContext *mtlc = MTLRenderQueue_GetCurrentContext();
|
||||
unsigned char *mask;
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLMaskFill_maskFill");
|
||||
J2dTraceLn(J2D_TRACE_ERROR, "MTLMaskFill_maskFill");
|
||||
}
|
||||
|
||||
#endif /* !HEADLESS */
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
*/
|
||||
|
||||
#ifndef MTLPaints_h_Included
|
||||
#define MTLPaints_h_Included
|
||||
|
||||
#include "MTLContext.h"
|
||||
|
||||
void MTLPaints_ResetPaint(MTLContext *mtlc);
|
||||
|
||||
void MTLPaints_SetColor(MTLContext *mtlc, jint pixel);
|
||||
|
||||
void MTLPaints_SetGradientPaint(MTLContext *mtlc,
|
||||
jboolean useMask, jboolean cyclic,
|
||||
jdouble p0, jdouble p1, jdouble p3,
|
||||
jint pixel1, jint pixel2);
|
||||
|
||||
void MTLPaints_SetLinearGradientPaint(MTLContext *mtlc, BMTLSDOps *dstOps,
|
||||
jboolean useMask, jboolean linear,
|
||||
jint cycleMethod, jint numStops,
|
||||
jfloat p0, jfloat p1, jfloat p3,
|
||||
void *fractions, void *pixels);
|
||||
|
||||
void MTLPaints_SetRadialGradientPaint(MTLContext *mtlc, BMTLSDOps *dstOps,
|
||||
jboolean useMask, jboolean linear,
|
||||
jint cycleMethod, jint numStops,
|
||||
jfloat m00, jfloat m01, jfloat m02,
|
||||
jfloat m10, jfloat m11, jfloat m12,
|
||||
jfloat focusX,
|
||||
void *fractions, void *pixels);
|
||||
|
||||
void MTLPaints_SetTexturePaint(MTLContext *mtlc,
|
||||
jboolean useMask,
|
||||
jlong pSrcOps, jboolean filter,
|
||||
jdouble xp0, jdouble xp1, jdouble xp3,
|
||||
jdouble yp0, jdouble yp1, jdouble yp3);
|
||||
|
||||
#endif /* MTLPaints_h_Included */
|
||||
@@ -0,0 +1,471 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
#ifndef HEADLESS
|
||||
|
||||
#include <jlong.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "sun_java2d_SunGraphics2D.h"
|
||||
#include "sun_java2d_pipe_BufferedPaints.h"
|
||||
|
||||
#include "MTLPaints.h"
|
||||
#include "MTLContext.h"
|
||||
#include "MTLRenderQueue.h"
|
||||
#include "MTLSurfaceData.h"
|
||||
|
||||
void
|
||||
MTLPaints_ResetPaint(MTLContext *mtlc)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLPaints_ResetPaint");
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLPaints_ResetPaint");
|
||||
}
|
||||
|
||||
void
|
||||
MTLPaints_SetColor(MTLContext *mtlc, jint pixel)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLPaints_SetColor");
|
||||
MTLContext_SetColorInt(mtlc, pixel);
|
||||
}
|
||||
|
||||
/************************* GradientPaint support ****************************/
|
||||
|
||||
static GLuint gradientTexID = 0;
|
||||
|
||||
static void
|
||||
MTLPaints_InitGradientTexture()
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLPaints_InitGradientTexture");
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLPaints_InitGradientTexture");
|
||||
}
|
||||
|
||||
void
|
||||
MTLPaints_SetGradientPaint(MTLContext *mtlc,
|
||||
jboolean useMask, jboolean cyclic,
|
||||
jdouble p0, jdouble p1, jdouble p3,
|
||||
jint pixel1, jint pixel2)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLPaints_SetGradientPaint");
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLPaints_SetGradientPaint");
|
||||
}
|
||||
|
||||
/************************** TexturePaint support ****************************/
|
||||
|
||||
void
|
||||
MTLPaints_SetTexturePaint(MTLContext *mtlc,
|
||||
jboolean useMask,
|
||||
jlong pSrcOps, jboolean filter,
|
||||
jdouble xp0, jdouble xp1, jdouble xp3,
|
||||
jdouble yp0, jdouble yp1, jdouble yp3)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLPaints_SetTexturePaint");
|
||||
}
|
||||
|
||||
/****************** Shared MultipleGradientPaint support ********************/
|
||||
|
||||
/**
|
||||
* These constants are identical to those defined in the
|
||||
* MultipleGradientPaint.CycleMethod enum; they are copied here for
|
||||
* convenience (ideally we would pull them directly from the Java level,
|
||||
* but that entails more hassle than it is worth).
|
||||
*/
|
||||
#define CYCLE_NONE 0
|
||||
#define CYCLE_REFLECT 1
|
||||
#define CYCLE_REPEAT 2
|
||||
|
||||
/**
|
||||
* The following constants are flags that can be bitwise-or'ed together
|
||||
* to control how the MultipleGradientPaint shader source code is generated:
|
||||
*
|
||||
* MULTI_CYCLE_METHOD
|
||||
* Placeholder for the CycleMethod enum constant.
|
||||
*
|
||||
* MULTI_LARGE
|
||||
* If set, use the (slower) shader that supports a larger number of
|
||||
* gradient colors; otherwise, use the optimized codepath. See
|
||||
* the MAX_FRACTIONS_SMALL/LARGE constants below for more details.
|
||||
*
|
||||
* MULTI_USE_MASK
|
||||
* If set, apply the alpha mask value from texture unit 0 to the
|
||||
* final color result (only used in the MaskFill case).
|
||||
*
|
||||
* MULTI_LINEAR_RGB
|
||||
* If set, convert the linear RGB result back into the sRGB color space.
|
||||
*/
|
||||
#define MULTI_CYCLE_METHOD (3 << 0)
|
||||
#define MULTI_LARGE (1 << 2)
|
||||
#define MULTI_USE_MASK (1 << 3)
|
||||
#define MULTI_LINEAR_RGB (1 << 4)
|
||||
|
||||
/**
|
||||
* This value determines the size of the array of programs for each
|
||||
* MultipleGradientPaint type. This value reflects the maximum value that
|
||||
* can be represented by performing a bitwise-or of all the MULTI_*
|
||||
* constants defined above.
|
||||
*/
|
||||
#define MAX_PROGRAMS 32
|
||||
|
||||
/** Evaluates to true if the given bit is set on the local flags variable. */
|
||||
#define IS_SET(flagbit) \
|
||||
(((flags) & (flagbit)) != 0)
|
||||
|
||||
/** Composes the given parameters as flags into the given flags variable.*/
|
||||
#define COMPOSE_FLAGS(flags, cycleMethod, large, useMask, linear) \
|
||||
do { \
|
||||
flags |= ((cycleMethod) & MULTI_CYCLE_METHOD); \
|
||||
if (large) flags |= MULTI_LARGE; \
|
||||
if (useMask) flags |= MULTI_USE_MASK; \
|
||||
if (linear) flags |= MULTI_LINEAR_RGB; \
|
||||
} while (0)
|
||||
|
||||
/** Extracts the CycleMethod enum value from the given flags variable. */
|
||||
#define EXTRACT_CYCLE_METHOD(flags) \
|
||||
((flags) & MULTI_CYCLE_METHOD)
|
||||
|
||||
/**
|
||||
* The maximum number of gradient "stops" supported by the fragment shader
|
||||
* and related code. When the MULTI_LARGE flag is set, we will use
|
||||
* MAX_FRACTIONS_LARGE; otherwise, we use MAX_FRACTIONS_SMALL. By having
|
||||
* two separate values, we can have one highly optimized shader (SMALL) that
|
||||
* supports only a few fractions/colors, and then another, less optimal
|
||||
* shader that supports more stops.
|
||||
*/
|
||||
#define MAX_FRACTIONS sun_java2d_pipe_BufferedPaints_MULTI_MAX_FRACTIONS
|
||||
#define MAX_FRACTIONS_LARGE MAX_FRACTIONS
|
||||
#define MAX_FRACTIONS_SMALL 4
|
||||
|
||||
/**
|
||||
* The maximum number of gradient colors supported by all of the gradient
|
||||
* fragment shaders. Note that this value must be a power of two, as it
|
||||
* determines the size of the 1D texture created below. It also must be
|
||||
* greater than or equal to MAX_FRACTIONS (there is no strict requirement
|
||||
* that the two values be equal).
|
||||
*/
|
||||
#define MAX_COLORS 16
|
||||
|
||||
/**
|
||||
* The handle to the gradient color table texture object used by the shaders.
|
||||
*/
|
||||
static jint multiGradientTexID = 0;
|
||||
|
||||
/**
|
||||
* This is essentially a template of the shader source code that can be used
|
||||
* for either LinearGradientPaint or RadialGradientPaint. It includes the
|
||||
* structure and some variables that are common to each; the remaining
|
||||
* code snippets (for CycleMethod, ColorSpaceType, and mask modulation)
|
||||
* are filled in prior to compiling the shader at runtime depending on the
|
||||
* paint parameters. See MTLPaints_CreateMultiGradProgram() for more details.
|
||||
*/
|
||||
static const char *multiGradientShaderSource =
|
||||
// gradient texture size (in texels)
|
||||
"const int TEXTURE_SIZE = %d;"
|
||||
// maximum number of fractions/colors supported by this shader
|
||||
"const int MAX_FRACTIONS = %d;"
|
||||
// size of a single texel
|
||||
"const float FULL_TEXEL = (1.0 / float(TEXTURE_SIZE));"
|
||||
// size of half of a single texel
|
||||
"const float HALF_TEXEL = (FULL_TEXEL / 2.0);"
|
||||
// texture containing the gradient colors
|
||||
"uniform sampler1D colors;"
|
||||
// array of gradient stops/fractions
|
||||
"uniform float fractions[MAX_FRACTIONS];"
|
||||
// array of scale factors (one for each interval)
|
||||
"uniform float scaleFactors[MAX_FRACTIONS-1];"
|
||||
// (placeholder for mask variable)
|
||||
"%s"
|
||||
// (placeholder for Linear/RadialGP-specific variables)
|
||||
"%s"
|
||||
""
|
||||
"void main(void)"
|
||||
"{"
|
||||
" float dist;"
|
||||
// (placeholder for Linear/RadialGradientPaint-specific code)
|
||||
" %s"
|
||||
""
|
||||
" float tc;"
|
||||
// (placeholder for CycleMethod-specific code)
|
||||
" %s"
|
||||
""
|
||||
// calculate interpolated color
|
||||
" vec4 result = texture1D(colors, tc);"
|
||||
""
|
||||
// (placeholder for ColorSpace conversion code)
|
||||
" %s"
|
||||
""
|
||||
// (placeholder for mask modulation code)
|
||||
" %s"
|
||||
""
|
||||
// modulate with gl_Color in order to apply extra alpha
|
||||
" gl_FragColor = result * gl_Color;"
|
||||
"}";
|
||||
|
||||
/**
|
||||
* This code takes a "dist" value as input (as calculated earlier by the
|
||||
* LGP/RGP-specific code) in the range [0,1] and produces a texture
|
||||
* coordinate value "tc" that represents the position of the chosen color
|
||||
* in the one-dimensional gradient texture (also in the range [0,1]).
|
||||
*
|
||||
* One naive way to implement this would be to iterate through the fractions
|
||||
* to figure out in which interval "dist" falls, and then compute the
|
||||
* relative distance between the two nearest stops. This approach would
|
||||
* require an "if" check on every iteration, and it is best to avoid
|
||||
* conditionals in fragment shaders for performance reasons. Also, one might
|
||||
* be tempted to use a break statement to jump out of the loop once the
|
||||
* interval was found, but break statements (and non-constant loop bounds)
|
||||
* are not natively available on most graphics hardware today, so that is
|
||||
* a non-starter.
|
||||
*
|
||||
* The more optimal approach used here avoids these issues entirely by using
|
||||
* an accumulation function that is equivalent to the process described above.
|
||||
* The scaleFactors array is pre-initialized at enable time as follows:
|
||||
* scaleFactors[i] = 1.0 / (fractions[i+1] - fractions[i]);
|
||||
*
|
||||
* For each iteration, we subtract fractions[i] from dist and then multiply
|
||||
* that value by scaleFactors[i]. If we are within the target interval,
|
||||
* this value will be a fraction in the range [0,1] indicating the relative
|
||||
* distance between fraction[i] and fraction[i+1]. If we are below the
|
||||
* target interval, this value will be negative, so we clamp it to zero
|
||||
* to avoid accumulating any value. If we are above the target interval,
|
||||
* the value will be greater than one, so we clamp it to one. Upon exiting
|
||||
* the loop, we will have accumulated zero or more 1.0's and a single
|
||||
* fractional value. This accumulated value tells us the position of the
|
||||
* fragment color in the one-dimensional gradient texture, i.e., the
|
||||
* texcoord called "tc".
|
||||
*/
|
||||
static const char *texCoordCalcCode =
|
||||
"int i;"
|
||||
"float relFraction = 0.0;"
|
||||
"for (i = 0; i < MAX_FRACTIONS-1; i++) {"
|
||||
" relFraction +="
|
||||
" clamp((dist - fractions[i]) * scaleFactors[i], 0.0, 1.0);"
|
||||
"}"
|
||||
// we offset by half a texel so that we find the linearly interpolated
|
||||
// color between the two texel centers of interest
|
||||
"tc = HALF_TEXEL + (FULL_TEXEL * relFraction);";
|
||||
|
||||
/** Code for NO_CYCLE that gets plugged into the CycleMethod placeholder. */
|
||||
static const char *noCycleCode =
|
||||
"if (dist <= 0.0) {"
|
||||
" tc = 0.0;"
|
||||
"} else if (dist >= 1.0) {"
|
||||
" tc = 1.0;"
|
||||
"} else {"
|
||||
// (placeholder for texcoord calculation)
|
||||
" %s"
|
||||
"}";
|
||||
|
||||
/** Code for REFLECT that gets plugged into the CycleMethod placeholder. */
|
||||
static const char *reflectCode =
|
||||
"dist = 1.0 - (abs(fract(dist * 0.5) - 0.5) * 2.0);"
|
||||
// (placeholder for texcoord calculation)
|
||||
"%s";
|
||||
|
||||
/** Code for REPEAT that gets plugged into the CycleMethod placeholder. */
|
||||
static const char *repeatCode =
|
||||
"dist = fract(dist);"
|
||||
// (placeholder for texcoord calculation)
|
||||
"%s";
|
||||
|
||||
static void
|
||||
MTLPaints_InitMultiGradientTexture()
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLPaints_InitMultiGradientTexture");
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles and links the MultipleGradientPaint shader program. If
|
||||
* successful, this function returns a handle to the newly created
|
||||
* shader program; otherwise returns 0.
|
||||
*/
|
||||
static GLhandleARB
|
||||
MTLPaints_CreateMultiGradProgram(jint flags,
|
||||
char *paintVars, char *distCode)
|
||||
{
|
||||
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLPaints_CreateMultiGradProgram");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from the MTLPaints_SetLinear/RadialGradientPaint() methods
|
||||
* in order to setup the fraction/color values that are common to both.
|
||||
*/
|
||||
static void
|
||||
MTLPaints_SetMultiGradientPaint(GLhandleARB multiGradProgram,
|
||||
jint numStops,
|
||||
void *pFractions, void *pPixels)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLPaints_SetMultiGradientPaint");
|
||||
|
||||
}
|
||||
|
||||
/********************** LinearGradientPaint support *************************/
|
||||
|
||||
/**
|
||||
* The handles to the LinearGradientPaint fragment program objects. The
|
||||
* index to the array should be a bitwise-or'ing of the MULTI_* flags defined
|
||||
* above. Note that most applications will likely need to initialize one
|
||||
* or two of these elements, so the array is usually sparsely populated.
|
||||
*/
|
||||
static GLhandleARB linearGradPrograms[MAX_PROGRAMS];
|
||||
|
||||
/**
|
||||
* Compiles and links the LinearGradientPaint shader program. If successful,
|
||||
* this function returns a handle to the newly created shader program;
|
||||
* otherwise returns 0.
|
||||
*/
|
||||
static GLhandleARB
|
||||
MTLPaints_CreateLinearGradProgram(jint flags)
|
||||
{
|
||||
char *paintVars;
|
||||
char *distCode;
|
||||
|
||||
J2dTraceLn1(J2D_TRACE_INFO,
|
||||
"MTLPaints_CreateLinearGradProgram",
|
||||
flags);
|
||||
|
||||
/*
|
||||
* To simplify the code and to make it easier to upload a number of
|
||||
* uniform values at once, we pack a bunch of scalar (float) values
|
||||
* into vec3 values below. Here's how the values are related:
|
||||
*
|
||||
* params.x = p0
|
||||
* params.y = p1
|
||||
* params.z = p3
|
||||
*
|
||||
* yoff = dstOps->yOffset + dstOps->height
|
||||
*/
|
||||
paintVars =
|
||||
"uniform vec3 params;"
|
||||
"uniform float yoff;";
|
||||
distCode =
|
||||
// note that gl_FragCoord is in window space relative to the
|
||||
// lower-left corner, so we have to flip the y-coordinate here
|
||||
"vec3 fragCoord = vec3(gl_FragCoord.x, yoff-gl_FragCoord.y, 1.0);"
|
||||
"dist = dot(params, fragCoord);";
|
||||
|
||||
return MTLPaints_CreateMultiGradProgram(flags, paintVars, distCode);
|
||||
}
|
||||
|
||||
void
|
||||
MTLPaints_SetLinearGradientPaint(MTLContext *mtlc, BMTLSDOps *dstOps,
|
||||
jboolean useMask, jboolean linear,
|
||||
jint cycleMethod, jint numStops,
|
||||
jfloat p0, jfloat p1, jfloat p3,
|
||||
void *fractions, void *pixels)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLPaints_SetMultiGradientPaint");
|
||||
}
|
||||
|
||||
/********************** RadialGradientPaint support *************************/
|
||||
|
||||
/**
|
||||
* The handles to the RadialGradientPaint fragment program objects. The
|
||||
* index to the array should be a bitwise-or'ing of the MULTI_* flags defined
|
||||
* above. Note that most applications will likely need to initialize one
|
||||
* or two of these elements, so the array is usually sparsely populated.
|
||||
*/
|
||||
static GLhandleARB radialGradPrograms[MAX_PROGRAMS];
|
||||
|
||||
/**
|
||||
* Compiles and links the RadialGradientPaint shader program. If successful,
|
||||
* this function returns a handle to the newly created shader program;
|
||||
* otherwise returns 0.
|
||||
*/
|
||||
static GLhandleARB
|
||||
MTLPaints_CreateRadialGradProgram(jint flags)
|
||||
{
|
||||
char *paintVars;
|
||||
char *distCode;
|
||||
|
||||
J2dTraceLn1(J2D_TRACE_INFO,
|
||||
"MTLPaints_CreateRadialGradProgram",
|
||||
flags);
|
||||
|
||||
/*
|
||||
* To simplify the code and to make it easier to upload a number of
|
||||
* uniform values at once, we pack a bunch of scalar (float) values
|
||||
* into vec3 and vec4 values below. Here's how the values are related:
|
||||
*
|
||||
* m0.x = m00
|
||||
* m0.y = m01
|
||||
* m0.z = m02
|
||||
*
|
||||
* m1.x = m10
|
||||
* m1.y = m11
|
||||
* m1.z = m12
|
||||
*
|
||||
* precalc.x = focusX
|
||||
* precalc.y = yoff = dstOps->yOffset + dstOps->height
|
||||
* precalc.z = 1.0 - (focusX * focusX)
|
||||
* precalc.w = 1.0 / precalc.z
|
||||
*/
|
||||
paintVars =
|
||||
"uniform vec3 m0;"
|
||||
"uniform vec3 m1;"
|
||||
"uniform vec4 precalc;";
|
||||
|
||||
/*
|
||||
* The following code is derived from Daniel Rice's whitepaper on
|
||||
* radial gradient performance (attached to the bug report for 6521533).
|
||||
* Refer to that document as well as the setup code in the Java-level
|
||||
* BufferedPaints.setRadialGradientPaint() method for more details.
|
||||
*/
|
||||
distCode =
|
||||
// note that gl_FragCoord is in window space relative to the
|
||||
// lower-left corner, so we have to flip the y-coordinate here
|
||||
"vec3 fragCoord ="
|
||||
" vec3(gl_FragCoord.x, precalc.y - gl_FragCoord.y, 1.0);"
|
||||
"float x = dot(fragCoord, m0);"
|
||||
"float y = dot(fragCoord, m1);"
|
||||
"float xfx = x - precalc.x;"
|
||||
"dist = (precalc.x*xfx + sqrt(xfx*xfx + y*y*precalc.z))*precalc.w;";
|
||||
|
||||
return MTLPaints_CreateMultiGradProgram(flags, paintVars, distCode);
|
||||
}
|
||||
|
||||
void
|
||||
MTLPaints_SetRadialGradientPaint(MTLContext *mtlc, BMTLSDOps *dstOps,
|
||||
jboolean useMask, jboolean linear,
|
||||
jint cycleMethod, jint numStops,
|
||||
jfloat m00, jfloat m01, jfloat m02,
|
||||
jfloat m10, jfloat m11, jfloat m12,
|
||||
jfloat focusX,
|
||||
void *fractions, void *pixels)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLPaints_SetRadialGradientPaint");
|
||||
}
|
||||
|
||||
#endif /* !HEADLESS */
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
#ifndef MTLRenderQueue_h_Included
|
||||
#define MTLRenderQueue_h_Included
|
||||
|
||||
#include "MTLContext.h"
|
||||
#include "MTLSurfaceData.h"
|
||||
|
||||
/*
|
||||
* 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)
|
||||
|
||||
/*
|
||||
* Parameter used by the RESET_PREVIOUS_OP() convenience macro, which
|
||||
* indicates that any "open" state (such as an unmatched glBegin() or
|
||||
* glEnable(GL_TEXTURE_2D)) should be completed before the following operation
|
||||
* is performed. SET_SURFACES is an example of an operation that needs to
|
||||
* call RESET_PREVIOUS_OP() before completing the surface change operation.
|
||||
*/
|
||||
#define MTL_STATE_RESET -1
|
||||
|
||||
/*
|
||||
* Parameter passed to the CHECK_PREVIOUS_OP() macro to indicate that the
|
||||
* following operation represents a "simple" state change. A simple state
|
||||
* change is one that is allowed to occur within a series of texturing
|
||||
* operations; in other words, this type of state change can occur without
|
||||
* first calling glDisable(GL_TEXTURE_2D). An example of such an operation
|
||||
* is SET_RECT_CLIP.
|
||||
*/
|
||||
#define MTL_STATE_CHANGE -2
|
||||
|
||||
/*
|
||||
* Parameter passed to the CHECK_PREVIOUS_OP() macro to indicate that the
|
||||
* following operation represents an operation that uses an alpha mask,
|
||||
* such as MTLMaskFill and MTLTR_DrawGrayscaleGlyphNoCache().
|
||||
*/
|
||||
#define MTL_STATE_MASK_OP -3
|
||||
|
||||
/*
|
||||
* Parameter passed to the CHECK_PREVIOUS_OP() macro to indicate that the
|
||||
* following operation represents an operation that uses the glyph cache,
|
||||
* such as MTLTR_DrawGrayscaleGlyphViaCache().
|
||||
*/
|
||||
#define MTL_STATE_GLYPH_OP -4
|
||||
|
||||
/*
|
||||
* Parameter passed to the CHECK_PREVIOUS_OP() macro to indicate that the
|
||||
* following operation represents an operation that renders a
|
||||
* parallelogram via a fragment program (see MTLRenderer).
|
||||
*/
|
||||
#define MTL_STATE_PGRAM_OP -5
|
||||
|
||||
/*
|
||||
* Initializes the "previous operation" state to its default value.
|
||||
*/
|
||||
#define INIT_PREVIOUS_OP() previousOp = MTL_STATE_RESET
|
||||
|
||||
/*
|
||||
* These macros now simply delegate to the CheckPreviousOp() method.
|
||||
*/
|
||||
#define CHECK_PREVIOUS_OP(op) MTLRenderQueue_CheckPreviousOp(op)
|
||||
#define RESET_PREVIOUS_OP() CHECK_PREVIOUS_OP(MTL_STATE_RESET)
|
||||
|
||||
/*
|
||||
* 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)
|
||||
|
||||
/*
|
||||
* Exports.
|
||||
*/
|
||||
extern jint previousOp;
|
||||
|
||||
MTLContext *MTLRenderQueue_GetCurrentContext();
|
||||
BMTLSDOps *MTLRenderQueue_GetCurrentDestination();
|
||||
void MTLRenderQueue_CheckPreviousOp(jint op);
|
||||
void MTLTR_DisableGlyphModeState();
|
||||
|
||||
#endif /* MTLRenderQueue_h_Included */
|
||||
@@ -0,0 +1,844 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
#ifndef HEADLESS
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "sun_java2d_pipe_BufferedOpCodes.h"
|
||||
|
||||
#include "jlong.h"
|
||||
#include "MTLBlitLoops.h"
|
||||
#include "MTLBufImgOps.h"
|
||||
#include "MTLMaskBlit.h"
|
||||
#include "MTLMaskFill.h"
|
||||
#include "MTLPaints.h"
|
||||
#include "MTLRenderQueue.h"
|
||||
#include "MTLRenderer.h"
|
||||
#include "MTLTextRenderer.h"
|
||||
|
||||
/**
|
||||
* Used to track whether we are in a series of a simple primitive operations
|
||||
* or texturing operations. This variable should be controlled only via
|
||||
* the INIT/CHECK/RESET_PREVIOUS_OP() macros. See the
|
||||
* MTLRenderQueue_CheckPreviousOp() method below for more information.
|
||||
*/
|
||||
jint previousOp;
|
||||
|
||||
/**
|
||||
* References to the "current" context and destination surface.
|
||||
*/
|
||||
static MTLContext *mtlc = NULL;
|
||||
static BMTLSDOps *dstOps = NULL;
|
||||
|
||||
/**
|
||||
* The following methods are implemented in the windowing system (i.e. GLX
|
||||
* and WGL) source files.
|
||||
*/
|
||||
extern void MTLGC_DestroyMTLGraphicsConfig(jlong pConfigInfo);
|
||||
extern void MTLSD_SwapBuffers(JNIEnv *env, jlong window);
|
||||
|
||||
/**
|
||||
* Helper methods to manage modified layers
|
||||
*/
|
||||
static MTLLayer ** g_modifiedLayers = NULL;
|
||||
static int g_modifiedLayersCount = 0;
|
||||
static int g_modifiedLayersAllocatedCount = 0;
|
||||
|
||||
static void _markLayerModified(MTLLayer * modifiedLayer) {
|
||||
if (modifiedLayer == NULL)
|
||||
return;
|
||||
if (g_modifiedLayers == NULL) {
|
||||
g_modifiedLayersAllocatedCount = 3;
|
||||
g_modifiedLayers = malloc(g_modifiedLayersAllocatedCount * sizeof(MTLLayer *));
|
||||
}
|
||||
for (int c = 0; c < g_modifiedLayersCount; ++c) {
|
||||
if (g_modifiedLayers[c] == modifiedLayer)
|
||||
return;
|
||||
}
|
||||
++g_modifiedLayersCount;
|
||||
if (g_modifiedLayersCount > g_modifiedLayersAllocatedCount) {
|
||||
g_modifiedLayersAllocatedCount = g_modifiedLayersCount;
|
||||
g_modifiedLayers = realloc(g_modifiedLayers, g_modifiedLayersAllocatedCount * sizeof(MTLLayer *));
|
||||
}
|
||||
g_modifiedLayers[g_modifiedLayersCount - 1] = modifiedLayer;
|
||||
}
|
||||
|
||||
static void _scheduleBlitAllModifiedLayers() {
|
||||
for (int c = 0; c < g_modifiedLayersCount; ++c) {
|
||||
MTLLayer * layer = g_modifiedLayers[c];
|
||||
MTLContext * ctx = layer.ctx;
|
||||
if (layer == NULL || ctx == NULL)
|
||||
continue;
|
||||
id<MTLCommandBuffer> bufferToCommit = ctx->mtlCommandBuffer;
|
||||
[JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){
|
||||
[layer blitTexture:bufferToCommit];
|
||||
}];
|
||||
|
||||
ctx->mtlCommandBuffer = nil;
|
||||
}
|
||||
g_modifiedLayersCount = 0;
|
||||
}
|
||||
|
||||
static void _onSurfaceModified(BMTLSDOps *bmtldst) {
|
||||
if (bmtldst != NULL && bmtldst->privOps != NULL && ((MTLSDOps *)bmtldst->privOps)->layer != NULL)
|
||||
_markLayerModified(((MTLSDOps *)bmtldst->privOps)->layer);
|
||||
}
|
||||
|
||||
static const jint g_drawOpcodes[] = {
|
||||
sun_java2d_pipe_BufferedOpCodes_DRAW_LINE,
|
||||
sun_java2d_pipe_BufferedOpCodes_DRAW_RECT,
|
||||
sun_java2d_pipe_BufferedOpCodes_DRAW_POLY,
|
||||
sun_java2d_pipe_BufferedOpCodes_DRAW_PIXEL,
|
||||
sun_java2d_pipe_BufferedOpCodes_DRAW_SCANLINES,
|
||||
sun_java2d_pipe_BufferedOpCodes_DRAW_PARALLELOGRAM,
|
||||
sun_java2d_pipe_BufferedOpCodes_DRAW_AAPARALLELOGRAM,
|
||||
|
||||
sun_java2d_pipe_BufferedOpCodes_DRAW_GLYPH_LIST,
|
||||
|
||||
sun_java2d_pipe_BufferedOpCodes_FILL_RECT,
|
||||
sun_java2d_pipe_BufferedOpCodes_FILL_SPANS,
|
||||
sun_java2d_pipe_BufferedOpCodes_FILL_PARALLELOGRAM,
|
||||
sun_java2d_pipe_BufferedOpCodes_FILL_AAPARALLELOGRAM,
|
||||
|
||||
sun_java2d_pipe_BufferedOpCodes_COPY_AREA,
|
||||
sun_java2d_pipe_BufferedOpCodes_MASK_FILL,
|
||||
sun_java2d_pipe_BufferedOpCodes_MASK_BLIT,
|
||||
sun_java2d_pipe_BufferedOpCodes_SET_SHAPE_CLIP_SPANS
|
||||
};
|
||||
|
||||
static jboolean _isDrawOpcode(jint opcode) {
|
||||
for (int c = 0; c < sizeof(g_drawOpcodes)/sizeof(g_drawOpcodes[0]); ++c) {
|
||||
if (opcode == g_drawOpcodes[c])
|
||||
return JNI_TRUE;
|
||||
}
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_java2d_metal_MTLRenderQueue_flushBuffer
|
||||
(JNIEnv *env, jobject mtlrq,
|
||||
jlong buf, jint limit)
|
||||
{
|
||||
jboolean sync = JNI_FALSE;
|
||||
unsigned char *b, *end;
|
||||
|
||||
J2dTraceLn1(J2D_TRACE_INFO,
|
||||
"MTLRenderQueue_flushBuffer: limit=%d", limit);
|
||||
|
||||
b = (unsigned char *)jlong_to_ptr(buf);
|
||||
if (b == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR,
|
||||
"MTLRenderQueue_flushBuffer: cannot get direct buffer address");
|
||||
return;
|
||||
}
|
||||
|
||||
INIT_PREVIOUS_OP();
|
||||
end = b + limit;
|
||||
|
||||
while (b < end) {
|
||||
jint opcode = NEXT_INT(b);
|
||||
|
||||
J2dTraceLn2(J2D_TRACE_VERBOSE,
|
||||
"MTLRenderQueue_flushBuffer: opcode=%d, rem=%d",
|
||||
opcode, (end-b));
|
||||
|
||||
if (opcode != sun_java2d_pipe_BufferedOpCodes_DRAW_GLYPH_LIST &&
|
||||
opcode != sun_java2d_pipe_BufferedOpCodes_NOOP)
|
||||
{
|
||||
//MTLTR_DisableGlyphModeState();
|
||||
}
|
||||
|
||||
switch (opcode) {
|
||||
|
||||
// draw ops
|
||||
case sun_java2d_pipe_BufferedOpCodes_DRAW_LINE:
|
||||
{
|
||||
J2dTraceLn(J2D_TRACE_VERBOSE, "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);
|
||||
MTLRenderer_DrawLine(mtlc, 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);
|
||||
MTLRenderer_DrawRect(mtlc, 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;
|
||||
MTLRenderer_DrawPoly(mtlc, nPoints, isClosed, transX, transY, xPoints, yPoints);
|
||||
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);
|
||||
CONTINUE_IF_NULL(mtlc);
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLRenderQueue_DRAW_PIXEL");
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_DRAW_SCANLINES:
|
||||
{
|
||||
jint count = NEXT_INT(b);
|
||||
MTLRenderer_DrawScanlines(mtlc, count, (jint *)b);
|
||||
|
||||
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);
|
||||
|
||||
MTLRenderer_DrawParallelogram(mtlc,
|
||||
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);
|
||||
|
||||
MTLRenderer_DrawAAParallelogram(mtlc, dstOps,
|
||||
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);
|
||||
MTLRenderer_FillRect(mtlc, x, y, w, h);
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_FILL_SPANS:
|
||||
{
|
||||
jint count = NEXT_INT(b);
|
||||
MTLRenderer_FillSpans(mtlc, count, (jint *)b);
|
||||
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);
|
||||
MTLRenderer_FillParallelogram(mtlc,
|
||||
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);
|
||||
MTLRenderer_FillAAParallelogram(mtlc, dstOps,
|
||||
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;
|
||||
}
|
||||
MTLTR_DrawGlyphList(env, mtlc, dstOps,
|
||||
numGlyphs, usePositions,
|
||||
subPixPos, rgbOrder, lcdContrast,
|
||||
glyphListOrigX, glyphListOrigY,
|
||||
images, positions);
|
||||
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);
|
||||
MTLBlitLoops_CopyArea(env, mtlc, dstOps,
|
||||
x, y, w, h, dx, dy);
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_BLIT:
|
||||
{
|
||||
J2dTracePrimitive("MTLRenderQueue_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);
|
||||
if (isoblit) {
|
||||
MTLBlitLoops_IsoBlit(env, mtlc, pSrc, pDst,
|
||||
xform, hint, texture, rtt,
|
||||
sx1, sy1, sx2, sy2,
|
||||
dx1, dy1, dx2, dy2);
|
||||
} else {
|
||||
jint srctype = EXTRACT_BYTE(packedParams, OFFSET_SRCTYPE);
|
||||
MTLBlitLoops_Blit(env, mtlc, pSrc, pDst,
|
||||
xform, hint, srctype, texture,
|
||||
sx1, sy1, sx2, sy2,
|
||||
dx1, dy1, dx2, dy2);
|
||||
}
|
||||
_onSurfaceModified(jlong_to_ptr(pDst));
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_SURFACE_TO_SW_BLIT:
|
||||
{
|
||||
J2dTracePrimitive("MTLRenderQueue_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);
|
||||
MTLBlitLoops_SurfaceToSwBlit(env, mtlc,
|
||||
pSrc, pDst, dsttype,
|
||||
sx, sy, dx, dy, w, h);
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_MASK_FILL:
|
||||
{
|
||||
J2dTracePrimitive("MTLRenderQueue_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;
|
||||
MTLMaskFill_MaskFill(mtlc, x, y, w, h,
|
||||
maskoff, maskscan, masklen, pMask);
|
||||
SKIP_BYTES(b, masklen);
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_MASK_BLIT:
|
||||
{
|
||||
J2dTracePrimitive("MTLRenderQueue_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);
|
||||
MTLMaskBlit_MaskBlit(env, mtlc,
|
||||
dstx, dsty, width, height, b);
|
||||
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);
|
||||
MTLContext_SetRectClip(mtlc, dstOps, x1, y1, x2, y2);
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_BEGIN_SHAPE_CLIP:
|
||||
{
|
||||
MTLContext_BeginShapeClip(mtlc);
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_SET_SHAPE_CLIP_SPANS:
|
||||
{
|
||||
jint count = NEXT_INT(b);
|
||||
MTLRenderer_FillSpans(mtlc, count, (jint *)b);
|
||||
SKIP_BYTES(b, count * BYTES_PER_SPAN);
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_END_SHAPE_CLIP:
|
||||
{
|
||||
MTLContext_EndShapeClip(mtlc, dstOps);
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_RESET_CLIP:
|
||||
{
|
||||
MTLContext_ResetClip(mtlc);
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_SET_ALPHA_COMPOSITE:
|
||||
{
|
||||
jint rule = NEXT_INT(b);
|
||||
jfloat extraAlpha = NEXT_FLOAT(b);
|
||||
jint flags = NEXT_INT(b);
|
||||
MTLContext_SetAlphaComposite(mtlc, rule, extraAlpha, flags);
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_SET_XOR_COMPOSITE:
|
||||
{
|
||||
jint xorPixel = NEXT_INT(b);
|
||||
MTLContext_SetXorComposite(mtlc, xorPixel);
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_RESET_COMPOSITE:
|
||||
{
|
||||
MTLContext_ResetComposite(mtlc);
|
||||
}
|
||||
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);
|
||||
MTLContext_SetTransform(mtlc, m00, m10, m01, m11, m02, m12);
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_RESET_TRANSFORM:
|
||||
{
|
||||
MTLContext_ResetTransform(mtlc);
|
||||
}
|
||||
break;
|
||||
|
||||
// context-related ops
|
||||
case sun_java2d_pipe_BufferedOpCodes_SET_SURFACES:
|
||||
{
|
||||
J2dTracePrimitive("MTLRenderQueue_SET_SURFACES");
|
||||
|
||||
jlong pSrc = NEXT_LONG(b);
|
||||
jlong pDst = NEXT_LONG(b);
|
||||
if (mtlc != NULL) {
|
||||
RESET_PREVIOUS_OP();
|
||||
}
|
||||
|
||||
dstOps = (BMTLSDOps *)jlong_to_ptr(pDst);
|
||||
MTLContext_SetSurfaces(env, pSrc, pDst);
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_SET_SCRATCH_SURFACE:
|
||||
{
|
||||
J2dTracePrimitive("MTLRenderQueue_SET_SCRATCH_SURFACE");
|
||||
jlong pConfigInfo = NEXT_LONG(b);
|
||||
MTLGraphicsConfigInfo *mtlInfo =
|
||||
(MTLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo);
|
||||
|
||||
if (mtlInfo == NULL) {
|
||||
J2dTraceImplPrimitive(
|
||||
"MTLRenderQueue_SET_SCRATCH_SURFACE",
|
||||
"ERROR: mtl config info is null");
|
||||
} else {
|
||||
MTLContext *newMtlc = mtlInfo->context;
|
||||
if (newMtlc == NULL) {
|
||||
J2dTraceImplPrimitive(
|
||||
"MTLRenderQueue_SET_SCRATCH_SURFACE",
|
||||
"ERROR: mtl context is null");
|
||||
} else {
|
||||
mtlc = newMtlc;
|
||||
dstOps = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_FLUSH_SURFACE:
|
||||
{
|
||||
J2dTracePrimitive("MTLRenderQueue_FLUSH_SURFACE");
|
||||
jlong pData = NEXT_LONG(b);
|
||||
BMTLSDOps *mtlsdo = (BMTLSDOps *)jlong_to_ptr(pData);
|
||||
if (mtlsdo != NULL) {
|
||||
CONTINUE_IF_NULL(mtlc);
|
||||
RESET_PREVIOUS_OP();
|
||||
MTLSD_Delete(env, mtlsdo);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_DISPOSE_SURFACE:
|
||||
{
|
||||
J2dTracePrimitive("MTLRenderQueue_DISPOSE_SURFACE");
|
||||
jlong pData = NEXT_LONG(b);
|
||||
BMTLSDOps *mtlsdo = (BMTLSDOps *)jlong_to_ptr(pData);
|
||||
if (mtlsdo != NULL) {
|
||||
CONTINUE_IF_NULL(mtlc);
|
||||
RESET_PREVIOUS_OP();
|
||||
MTLSD_Delete(env, mtlsdo);
|
||||
if (mtlsdo->privOps != NULL) {
|
||||
free(mtlsdo->privOps);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_DISPOSE_CONFIG:
|
||||
{
|
||||
J2dTracePrimitive("MTLRenderQueue_DISPOSE_CONFIG");
|
||||
jlong pConfigInfo = NEXT_LONG(b);
|
||||
CONTINUE_IF_NULL(mtlc);
|
||||
RESET_PREVIOUS_OP();
|
||||
[JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){
|
||||
MTLGC_DestroyMTLGraphicsConfig(pConfigInfo);
|
||||
}];
|
||||
|
||||
|
||||
// the previous method will call glX/wglMakeCurrent(None),
|
||||
// so we should nullify the current mtlc and dstOps to avoid
|
||||
// calling glFlush() (or similar) while no context is current
|
||||
mtlc = NULL;
|
||||
// dstOps = NULL;
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_INVALIDATE_CONTEXT:
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLRenderQueue_INVALIDATE_CONTEXT");
|
||||
// flush just in case there are any pending operations in
|
||||
// the hardware pipe
|
||||
if (mtlc != NULL) {
|
||||
RESET_PREVIOUS_OP();
|
||||
}
|
||||
// invalidate the references to the current context and
|
||||
// destination surface that are maintained at the native level
|
||||
mtlc = NULL;
|
||||
// dstOps = NULL;
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_SAVE_STATE:
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLRenderQueue_INVALIDATE_CONTEXT");
|
||||
}
|
||||
break;
|
||||
|
||||
case sun_java2d_pipe_BufferedOpCodes_RESTORE_STATE:
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLRenderQueue_RESTORE_STATE");
|
||||
|
||||
}
|
||||
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);
|
||||
if (mtlc != NULL) {
|
||||
RESET_PREVIOUS_OP();
|
||||
}
|
||||
MTLSD_SwapBuffers(env, window);
|
||||
}
|
||||
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:
|
||||
{
|
||||
MTLPaints_ResetPaint(mtlc);
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_SET_COLOR:
|
||||
{
|
||||
jint pixel = NEXT_INT(b);
|
||||
|
||||
if (dstOps != NULL) {
|
||||
MTLSDOps *dstCGLOps = (MTLSDOps *)dstOps->privOps;
|
||||
dstCGLOps->configInfo->context->mtlColor = pixel;
|
||||
}
|
||||
MTLPaints_SetColor(mtlc, pixel);
|
||||
}
|
||||
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);
|
||||
MTLPaints_SetGradientPaint(mtlc, useMask, cyclic,
|
||||
p0, p1, p3,
|
||||
pixel1, pixel2);
|
||||
}
|
||||
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));
|
||||
MTLPaints_SetLinearGradientPaint(mtlc, dstOps,
|
||||
useMask, linear,
|
||||
cycleMethod, numStops,
|
||||
p0, p1, p3,
|
||||
fractions, pixels);
|
||||
}
|
||||
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));
|
||||
MTLPaints_SetRadialGradientPaint(mtlc, dstOps,
|
||||
useMask, linear,
|
||||
cycleMethod, numStops,
|
||||
m00, m01, m02,
|
||||
m10, m11, m12,
|
||||
focusX,
|
||||
fractions, pixels);
|
||||
}
|
||||
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);
|
||||
MTLPaints_SetTexturePaint(mtlc, useMask, pSrc, filter,
|
||||
xp0, xp1, xp3,
|
||||
yp0, yp1, yp3);
|
||||
}
|
||||
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);
|
||||
MTLBufImgOps_EnableConvolveOp(mtlc, pSrc, edgeZero,
|
||||
kernelWidth, kernelHeight, b);
|
||||
SKIP_BYTES(b, kernelWidth * kernelHeight * sizeof(jfloat));
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_DISABLE_CONVOLVE_OP:
|
||||
{
|
||||
MTLBufImgOps_DisableConvolveOp(mtlc);
|
||||
}
|
||||
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));
|
||||
MTLBufImgOps_EnableRescaleOp(mtlc, pSrc, nonPremult,
|
||||
scaleFactors, offsets);
|
||||
SKIP_BYTES(b, numFactors * sizeof(jfloat) * 2);
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_DISABLE_RESCALE_OP:
|
||||
{
|
||||
MTLBufImgOps_DisableRescaleOp(mtlc);
|
||||
}
|
||||
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;
|
||||
MTLBufImgOps_EnableLookupOp(mtlc, pSrc, nonPremult, shortData,
|
||||
numBands, bandLength, offset,
|
||||
tableValues);
|
||||
SKIP_BYTES(b, numBands * bandLength * bytesPerElem);
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_DISABLE_LOOKUP_OP:
|
||||
{
|
||||
MTLBufImgOps_DisableLookupOp(mtlc);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
J2dRlsTraceLn1(J2D_TRACE_ERROR,
|
||||
"MTLRenderQueue_flushBuffer: invalid opcode=%d", opcode);
|
||||
if (mtlc != NULL) {
|
||||
RESET_PREVIOUS_OP();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (_isDrawOpcode(opcode)) // performed rendering operation on dstOps
|
||||
_onSurfaceModified(dstOps);
|
||||
}
|
||||
|
||||
MTLTR_DisableGlyphModeState();
|
||||
_scheduleBlitAllModifiedLayers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a pointer to the "current" context, as set by the last SET_SURFACES
|
||||
* or SET_SCRATCH_SURFACE operation.
|
||||
*/
|
||||
MTLContext *
|
||||
MTLRenderQueue_GetCurrentContext()
|
||||
{
|
||||
return mtlc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a pointer to the "current" destination surface, as set by the last
|
||||
* SET_SURFACES operation.
|
||||
*/
|
||||
BMTLSDOps *
|
||||
MTLRenderQueue_GetCurrentDestination()
|
||||
{
|
||||
return dstOps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to track whether we are within a series of simple primitive operations
|
||||
* or texturing operations. The op parameter determines the nature of the
|
||||
* operation that is to follow. Valid values for this op parameter are:
|
||||
*/
|
||||
void
|
||||
MTLRenderQueue_CheckPreviousOp(jint op)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLRenderQueue_CheckPreviousOp");
|
||||
previousOp = op;
|
||||
}
|
||||
|
||||
#endif /* !HEADLESS */
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
#ifndef MTLRenderer_h_Included
|
||||
#define MTLRenderer_h_Included
|
||||
|
||||
#include "sun_java2d_pipe_BufferedRenderPipe.h"
|
||||
#include "MTLContext.h"
|
||||
#include "MTLGraphicsConfig.h"
|
||||
#import "MTLLayer.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
|
||||
|
||||
void MTLRenderer_DrawLine(MTLContext *mtlc,
|
||||
jint x1, jint y1, jint x2, jint y2);
|
||||
void MTLRenderer_DrawRect(MTLContext *mtlc,
|
||||
jint x, jint y, jint w, jint h);
|
||||
void MTLRenderer_DrawPoly(MTLContext *mtlc,
|
||||
jint nPoints, jint isClosed,
|
||||
jint transX, jint transY,
|
||||
jint *xPoints, jint *yPoints);
|
||||
void MTLRenderer_DrawScanlines(MTLContext *mtlc,
|
||||
jint count, jint *scanlines);
|
||||
void MTLRenderer_DrawParallelogram(MTLContext *mtlc,
|
||||
jfloat fx11, jfloat fy11,
|
||||
jfloat dx21, jfloat dy21,
|
||||
jfloat dx12, jfloat dy12,
|
||||
jfloat lw21, jfloat lw12);
|
||||
void MTLRenderer_DrawAAParallelogram(MTLContext *mtlc, BMTLSDOps *dstOps,
|
||||
jfloat fx11, jfloat fy11,
|
||||
jfloat dx21, jfloat dy21,
|
||||
jfloat dx12, jfloat dy12,
|
||||
jfloat lw21, jfloat lw12);
|
||||
|
||||
void MTLRenderer_FillRect(MTLContext *mtlc,
|
||||
jint x, jint y, jint w, jint h);
|
||||
void MTLRenderer_FillSpans(MTLContext *mtlc,
|
||||
jint count, jint *spans);
|
||||
void MTLRenderer_FillParallelogram(MTLContext *mtlc,
|
||||
jfloat fx11, jfloat fy11,
|
||||
jfloat dx21, jfloat dy21,
|
||||
jfloat dx12, jfloat dy12);
|
||||
void MTLRenderer_FillAAParallelogram(MTLContext *mtlc, BMTLSDOps *dstOps,
|
||||
jfloat fx11, jfloat fy11,
|
||||
jfloat dx21, jfloat dy21,
|
||||
jfloat dx12, jfloat dy12);
|
||||
|
||||
void MTLRenderer_EnableAAParallelogramProgram();
|
||||
void MTLRenderer_DisableAAParallelogramProgram();
|
||||
void MTLRenderer_BeginFrame(MTLContext* ctx, MTLLayer* layer);
|
||||
|
||||
#endif /* MTLRenderer_h_Included */
|
||||
@@ -0,0 +1,670 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
#ifndef HEADLESS
|
||||
|
||||
#include <jlong.h>
|
||||
#include <jni_util.h>
|
||||
#include <math.h>
|
||||
|
||||
//#define DEBUG 1
|
||||
|
||||
#include "sun_java2d_metal_MTLRenderer.h"
|
||||
|
||||
#include "MTLRenderer.h"
|
||||
#include "MTLRenderQueue.h"
|
||||
#include "MTLSurfaceData.h"
|
||||
#include "MTLUtils.h"
|
||||
#import "MTLLayer.h"
|
||||
|
||||
void MTLRenderer_FillParallelogramMetal(
|
||||
MTLContext* mtlc, id<MTLTexture> dest, jfloat x, jfloat y, jfloat dx1, jfloat dy1, jfloat dx2, jfloat dy2)
|
||||
{
|
||||
if (mtlc == NULL || dest == nil)
|
||||
return;
|
||||
|
||||
J2dTraceLn7(J2D_TRACE_INFO,
|
||||
"MTLRenderer_FillParallelogramMetal "
|
||||
"(x=%6.2f y=%6.2f "
|
||||
"dx1=%6.2f dy1=%6.2f "
|
||||
"dx2=%6.2f dy2=%6.2f dst tex=%p)",
|
||||
x, y,
|
||||
dx1, dy1,
|
||||
dx2, dy2, dest);
|
||||
|
||||
struct Vertex verts[PGRAM_VERTEX_COUNT] = {
|
||||
{ {(2.0*x/dest.width) - 1.0,
|
||||
2.0*(1.0 - y/dest.height) - 1.0, 0.0}},
|
||||
|
||||
{ {2.0*(x+dx1)/dest.width - 1.0,
|
||||
2.0*(1.0 - (y+dy1)/dest.height) - 1.0, 0.0}},
|
||||
|
||||
{ {2.0*(x+dx2)/dest.width - 1.0,
|
||||
2.0*(1.0 - (y+dy2)/dest.height) - 1.0, 0.0}},
|
||||
|
||||
{ {2.0*(x+dx1)/dest.width - 1.0,
|
||||
2.0*(1.0 - (y+dy1)/dest.height) - 1.0, 0.0}},
|
||||
|
||||
{ {2.0*(x + dx1 + dx2)/dest.width - 1.0,
|
||||
2.0*(1.0 - (y+ dy1 + dy2)/dest.height) - 1.0, 0.0}},
|
||||
|
||||
{ {2.0*(x+dx2)/dest.width - 1.0,
|
||||
2.0*(1.0 - (y+dy2)/dest.height) - 1.0, 0.0},
|
||||
}};
|
||||
|
||||
// Encode render command.
|
||||
id<MTLRenderCommandEncoder> mtlEncoder = MTLContext_CreateRenderEncoder(mtlc, dest);
|
||||
if (mtlEncoder == nil)
|
||||
return;
|
||||
|
||||
[mtlEncoder setVertexBytes:verts length:sizeof(verts) atIndex:MeshVertexBuffer];
|
||||
[mtlEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount: PGRAM_VERTEX_COUNT];
|
||||
[mtlEncoder endEncoding];
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: Some of the methods in this file apply a "magic number"
|
||||
* translation to line segments. The OpenGL specification lays out the
|
||||
* "diamond exit rule" for line rasterization, but it is loose enough to
|
||||
* allow for a wide range of line rendering hardware. (It appears that
|
||||
* some hardware, such as the Nvidia GeForce2 series, does not even meet
|
||||
* the spec in all cases.) As such it is difficult to find a mapping
|
||||
* between the Java2D and OpenGL line specs that works consistently across
|
||||
* all hardware combinations.
|
||||
*
|
||||
* Therefore the "magic numbers" you see here have been empirically derived
|
||||
* after testing on a variety of graphics hardware in order to find some
|
||||
* reasonable middle ground between the two specifications. The general
|
||||
* approach is to apply a fractional translation to vertices so that they
|
||||
* hit pixel centers and therefore touch the same pixels as in our other
|
||||
* pipelines. Emphasis was placed on finding values so that MTL lines with
|
||||
* a slope of +/- 1 hit all the same pixels as our other (software) loops.
|
||||
* The stepping in other diagonal lines rendered with MTL may deviate
|
||||
* slightly from those rendered with our software loops, but the most
|
||||
* important thing is that these magic numbers ensure that all MTL lines
|
||||
* hit the same endpoints as our software loops.
|
||||
*
|
||||
* If you find it necessary to change any of these magic numbers in the
|
||||
* future, just be sure that you test the changes across a variety of
|
||||
* hardware to ensure consistent rendering everywhere.
|
||||
*/
|
||||
|
||||
void MTLRenderer_DrawLineMetal(MTLContext *mtlc, id<MTLTexture> dest, jfloat x1, jfloat y1, jfloat x2, jfloat y2) {
|
||||
if (mtlc == NULL || dest == nil)
|
||||
return;
|
||||
|
||||
J2dTraceLn5(J2D_TRACE_INFO, "MTLRenderer_DrawLineMetal (x1=%1.2f y1=%1.2f x2=%1.2f y2=%1.2f), dst tex=%p", x1, y1, x2, y2, dest);
|
||||
|
||||
id<MTLRenderCommandEncoder> mtlEncoder = MTLContext_CreateRenderEncoder(mtlc, dest);
|
||||
if (mtlEncoder == nil)
|
||||
return;
|
||||
|
||||
struct Vertex verts[2] = {
|
||||
{{MTLUtils_normalizeX(dest, x1), MTLUtils_normalizeY(dest, y1), 0.0}},
|
||||
{{MTLUtils_normalizeX(dest, x2), MTLUtils_normalizeY(dest, y2), 0.0}}
|
||||
};
|
||||
|
||||
[mtlEncoder setVertexBytes:verts length:sizeof(verts) atIndex:MeshVertexBuffer];
|
||||
[mtlEncoder drawPrimitives:MTLPrimitiveTypeLine vertexStart:0 vertexCount:2];
|
||||
[mtlEncoder endEncoding];
|
||||
}
|
||||
|
||||
void MTLRenderer_DrawLine(MTLContext *mtlc, jint x1, jint y1, jint x2, jint y2) {
|
||||
BMTLSDOps *dstOps = MTLRenderQueue_GetCurrentDestination();
|
||||
if (dstOps == NULL || dstOps->privOps == NULL) {
|
||||
J2dTraceLn(J2D_TRACE_ERROR, "MTLRenderer_DrawLine: dest is null");
|
||||
return;
|
||||
}
|
||||
|
||||
MTLSDOps *dstCGLOps = (MTLSDOps *)dstOps->privOps;
|
||||
MTLRenderer_DrawLineMetal(dstCGLOps->configInfo->context, dstOps->pTexture, x1, y1, x2, y2);
|
||||
}
|
||||
|
||||
void MTLRenderer_DrawRectMetal(MTLContext *mtlc, id<MTLTexture> dest, jint x, jint y, jint w, jint h) {
|
||||
if (mtlc == NULL || dest == nil)
|
||||
return;
|
||||
|
||||
J2dTraceLn5(J2D_TRACE_INFO, "MTLRenderer_DrawRectMetal (x=%d y=%d w=%d h=%d), dst tex=%p", x, y, w, h, dest);
|
||||
|
||||
// TODO: use DrawParallelogram(x, y, w, h, lw=1, lh=1)
|
||||
id<MTLRenderCommandEncoder> mtlEncoder = MTLContext_CreateRenderEncoder(mtlc, dest);
|
||||
if (mtlEncoder == nil)
|
||||
return;
|
||||
|
||||
const int verticesCount = 5;
|
||||
struct Vertex vertices[verticesCount] = {
|
||||
{{MTLUtils_normalizeX(dest, x), MTLUtils_normalizeY(dest, y), 0.0}},
|
||||
{{MTLUtils_normalizeX(dest, x + w), MTLUtils_normalizeY(dest, y), 0.0}},
|
||||
{{MTLUtils_normalizeX(dest, x + w), MTLUtils_normalizeY(dest, y + h), 0.0}},
|
||||
{{MTLUtils_normalizeX(dest, x), MTLUtils_normalizeY(dest, y + h), 0.0}},
|
||||
{{MTLUtils_normalizeX(dest, x), MTLUtils_normalizeY(dest, y), 0.0}},
|
||||
};
|
||||
[mtlEncoder setVertexBytes:vertices length:sizeof(vertices) atIndex:MeshVertexBuffer];
|
||||
[mtlEncoder drawPrimitives:MTLPrimitiveTypeLineStrip vertexStart:0 vertexCount:verticesCount];
|
||||
[mtlEncoder endEncoding];
|
||||
}
|
||||
|
||||
void MTLRenderer_DrawRect(MTLContext *mtlc, jint x, jint y, jint w, jint h) {
|
||||
BMTLSDOps *bmtldst = MTLRenderQueue_GetCurrentDestination();
|
||||
if (bmtldst == NULL || bmtldst->privOps == NULL) {
|
||||
J2dTraceLn(J2D_TRACE_ERROR, "MTLRenderer_DrawRect: dest is null");
|
||||
return;
|
||||
}
|
||||
|
||||
MTLSDOps *dstCGLOps = (MTLSDOps *)bmtldst->privOps;
|
||||
MTLRenderer_DrawRectMetal(dstCGLOps->configInfo->context, bmtldst->pTexture, x, y, w, h);
|
||||
}
|
||||
|
||||
void _tracePoints(jint nPoints, jint *xPoints, jint *yPoints) {
|
||||
for (int i = 0; i < nPoints; i++)
|
||||
J2dTraceLn2(J2D_TRACE_INFO, "\t(%d, %d)", *(xPoints++), *(yPoints++));
|
||||
}
|
||||
|
||||
const int POLYLINE_BUF_SIZE = 64;
|
||||
|
||||
void _fillVertex(struct Vertex * vertex, int x, int y, int destW, int destH) {
|
||||
vertex->position[0] = 2.0*x/destW - 1.0;
|
||||
vertex->position[1] = 2.0*(1.0 - y/destH) - 1.0;
|
||||
vertex->position[2] = 0;
|
||||
}
|
||||
|
||||
void MTLRenderer_DrawPoly(MTLContext *mtlc,
|
||||
jint nPoints, jint isClosed,
|
||||
jint transX, jint transY,
|
||||
jint *xPoints, jint *yPoints)
|
||||
{
|
||||
// Note that BufferedRenderPipe.drawPoly() has already rejected polys
|
||||
// with nPoints<2, so we can be certain here that we have nPoints>=2.
|
||||
if (xPoints == NULL || yPoints == NULL || nPoints < 2) { // just for insurance
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLRenderer_DrawPoly: points array is empty");
|
||||
return;
|
||||
}
|
||||
|
||||
BMTLSDOps *dstOps = MTLRenderQueue_GetCurrentDestination();
|
||||
if (dstOps == NULL || dstOps->privOps == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLRenderer_DrawPoly: current dest is null");
|
||||
return;
|
||||
}
|
||||
|
||||
MTLSDOps *dstCGLOps = (MTLSDOps *) dstOps->privOps;
|
||||
MTLContext* ctx = dstCGLOps->configInfo->context;
|
||||
if (ctx == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLRenderer_DrawPoly: current mtlContext os null");
|
||||
return;
|
||||
}
|
||||
|
||||
J2dTraceLn4(J2D_TRACE_INFO, "MTLRenderer_DrawPoly: %d points, transX=%d, transY=%d, dst tex=%p", nPoints, transX, transY, dstOps->pTexture);
|
||||
|
||||
__block struct {
|
||||
struct Vertex verts[POLYLINE_BUF_SIZE];
|
||||
} pointsChunk;
|
||||
|
||||
jint prevX = *(xPoints++);
|
||||
jint prevY = *(yPoints++);
|
||||
--nPoints;
|
||||
const jint firstX = prevX;
|
||||
const jint firstY = prevY;
|
||||
while (nPoints > 0) {
|
||||
_fillVertex(pointsChunk.verts, prevX + transX, prevY + transY, dstOps->width, dstOps->height);
|
||||
|
||||
const bool isLastChunk = nPoints + 1 <= POLYLINE_BUF_SIZE;
|
||||
__block int chunkSize = isLastChunk ? nPoints : POLYLINE_BUF_SIZE - 1;
|
||||
|
||||
for (int i = 1; i < chunkSize; i++) {
|
||||
prevX = *(xPoints++);
|
||||
prevY = *(yPoints++);
|
||||
_fillVertex(pointsChunk.verts + i, prevX + transX, prevY + transY, dstOps->width, dstOps->height);
|
||||
}
|
||||
|
||||
bool drawCloseSegment = false;
|
||||
if (isClosed && isLastChunk) {
|
||||
if (chunkSize + 2 <= POLYLINE_BUF_SIZE) {
|
||||
_fillVertex(pointsChunk.verts + chunkSize, firstX + transX, firstY + transY, dstOps->width, dstOps->height);
|
||||
++chunkSize;
|
||||
} else
|
||||
drawCloseSegment = true;
|
||||
}
|
||||
|
||||
nPoints -= chunkSize;
|
||||
id<MTLRenderCommandEncoder> mtlEncoder = MTLContext_CreateRenderEncoder(ctx, dstOps->pTexture);
|
||||
if (mtlEncoder == nil)
|
||||
return;
|
||||
|
||||
[mtlEncoder setVertexBytes:pointsChunk.verts length:sizeof(pointsChunk.verts) atIndex:MeshVertexBuffer];
|
||||
[mtlEncoder drawPrimitives:MTLPrimitiveTypeLineStrip vertexStart:0 vertexCount:chunkSize + 1];
|
||||
if (drawCloseSegment) {
|
||||
struct Vertex vertices[2] = {
|
||||
{{MTLUtils_normalizeX(dstOps->pTexture, prevX + transX), MTLUtils_normalizeY(dstOps->pTexture, prevY + transY), 0.0}},
|
||||
{{MTLUtils_normalizeX(dstOps->pTexture, firstX + transX), MTLUtils_normalizeY(dstOps->pTexture, firstY + transY), 0.0}},
|
||||
};
|
||||
[mtlEncoder setVertexBytes:vertices length:sizeof(vertices) atIndex:MeshVertexBuffer];
|
||||
[mtlEncoder drawPrimitives:MTLPrimitiveTypeLine vertexStart:0 vertexCount:2];
|
||||
}
|
||||
|
||||
[mtlEncoder endEncoding];
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_java2d_metal_MTLRenderer_drawPoly
|
||||
(JNIEnv *env, jobject mtlr,
|
||||
jintArray xpointsArray, jintArray ypointsArray,
|
||||
jint nPoints, jboolean isClosed,
|
||||
jint transX, jint transY)
|
||||
{
|
||||
jint *xPoints, *yPoints;
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLRenderer_drawPoly");
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLRenderer_drawPoly");
|
||||
}
|
||||
|
||||
void
|
||||
MTLRenderer_DrawScanlines(MTLContext *mtlc,
|
||||
jint scanlineCount, jint *scanlines)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLRenderer_DrawScanlines");
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLRenderer_DrawScanlines");
|
||||
}
|
||||
|
||||
void
|
||||
MTLRenderer_FillRect(MTLContext *mtlc, jint x, jint y, jint w, jint h)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLRenderer_FillRect");
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLRenderer_FillRect");
|
||||
}
|
||||
|
||||
const int SPAN_BUF_SIZE=64;
|
||||
|
||||
void
|
||||
MTLRenderer_FillSpans(MTLContext *mtlc, jint spanCount, jint *spans)
|
||||
{
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLRenderer_FillSpans");
|
||||
BMTLSDOps *dstOps = MTLRenderQueue_GetCurrentDestination();
|
||||
if (dstOps == NULL || dstOps->privOps == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLRenderer_FillSpans: current dest is null");
|
||||
return;
|
||||
}
|
||||
MTLSDOps *dstCGLOps = (MTLSDOps *) dstOps->privOps;
|
||||
MTLContext* ctx = dstCGLOps->configInfo->context;
|
||||
if (ctx == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLRenderer_FillSpans: current mtlContext os null");
|
||||
return;
|
||||
}
|
||||
|
||||
while (spanCount > 0) {
|
||||
__block struct {
|
||||
jfloat spns[SPAN_BUF_SIZE*4];
|
||||
} spanStruct;
|
||||
|
||||
__block jfloat sc = spanCount > SPAN_BUF_SIZE ? SPAN_BUF_SIZE : spanCount;
|
||||
|
||||
for (int i = 0; i < sc; i++) {
|
||||
spanStruct.spns[i * 4] = *(spans++);
|
||||
spanStruct.spns[i * 4 + 1] = *(spans++);
|
||||
spanStruct.spns[i * 4 + 2] = *(spans++);
|
||||
spanStruct.spns[i * 4 + 3] = *(spans++);
|
||||
}
|
||||
|
||||
spanCount -= sc;
|
||||
|
||||
id<MTLTexture> dest = dstOps->pTexture;
|
||||
id<MTLRenderCommandEncoder> mtlEncoder = MTLContext_CreateRenderEncoder(ctx, dest);
|
||||
if (mtlEncoder == nil)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < sc; i++) {
|
||||
jfloat x1 = spanStruct.spns[i * 4];
|
||||
jfloat y1 = spanStruct.spns[i * 4 + 1];
|
||||
jfloat x2 = spanStruct.spns[i * 4 + 2];
|
||||
jfloat y2 = spanStruct.spns[i * 4 + 3];
|
||||
|
||||
struct Vertex verts[PGRAM_VERTEX_COUNT] = {
|
||||
{{(2.0 * x1 / dest.width) - 1.0,
|
||||
2.0 * (1.0 - y1 / dest.height) - 1.0, 0.0}},
|
||||
|
||||
{{2.0 * (x2) / dest.width - 1.0,
|
||||
2.0 * (1.0 - y1 / dest.height) - 1.0, 0.0}},
|
||||
|
||||
{{2.0 * x1 / dest.width - 1.0,
|
||||
2.0 * (1.0 - y2 / dest.height) - 1.0, 0.0}},
|
||||
|
||||
{{2.0 * x2 / dest.width - 1.0,
|
||||
2.0 * (1.0 - y1 / dest.height) - 1.0, 0.0}},
|
||||
|
||||
{{2.0 * (x2) / dest.width - 1.0,
|
||||
2.0 * (1.0 - y2 / dest.height) - 1.0, 0.0}},
|
||||
|
||||
{{2.0 * (x1) / dest.width - 1.0,
|
||||
2.0 * (1.0 - y2 / dest.height) - 1.0, 0.0},
|
||||
}};
|
||||
|
||||
[mtlEncoder setVertexBytes:verts length:sizeof(verts) atIndex:MeshVertexBuffer];
|
||||
[mtlEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:PGRAM_VERTEX_COUNT];
|
||||
}
|
||||
|
||||
[mtlEncoder endEncoding];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MTLRenderer_FillParallelogram(MTLContext *mtlc,
|
||||
jfloat fx11, jfloat fy11,
|
||||
jfloat dx21, jfloat dy21,
|
||||
jfloat dx12, jfloat dy12)
|
||||
{
|
||||
J2dTracePrimitive("MTLRenderer_FillParallelogram");
|
||||
|
||||
BMTLSDOps *dstOps = MTLRenderQueue_GetCurrentDestination();
|
||||
if (dstOps == NULL || dstOps->privOps == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLRenderer_FillParallelogram: current dest is null");
|
||||
return;
|
||||
}
|
||||
MTLSDOps *dstCGLOps = (MTLSDOps *) dstOps->privOps;
|
||||
MTLContext* ctx = dstCGLOps->configInfo->context;
|
||||
if (ctx == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLRenderer_FillParallelogram: current mtlContext os null");
|
||||
return;
|
||||
}
|
||||
|
||||
MTLRenderer_FillParallelogramMetal(
|
||||
dstCGLOps->configInfo->context, dstOps->pTexture,
|
||||
fx11, fy11, dx21, dy21, dx12, dy12);
|
||||
}
|
||||
|
||||
void
|
||||
MTLRenderer_DrawParallelogram(MTLContext *mtlc,
|
||||
jfloat fx11, jfloat fy11,
|
||||
jfloat dx21, jfloat dy21,
|
||||
jfloat dx12, jfloat dy12,
|
||||
jfloat lwr21, jfloat lwr12)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLRenderer_DrawParallelogram");
|
||||
// dx,dy for line width in the "21" and "12" directions.
|
||||
jfloat ldx21 = dx21 * lwr21;
|
||||
jfloat ldy21 = dy21 * lwr21;
|
||||
jfloat ldx12 = dx12 * lwr12;
|
||||
jfloat ldy12 = dy12 * lwr12;
|
||||
|
||||
// calculate origin of the outer parallelogram
|
||||
jfloat ox11 = fx11 - (ldx21 + ldx12) / 2.0f;
|
||||
jfloat oy11 = fy11 - (ldy21 + ldy12) / 2.0f;
|
||||
|
||||
J2dTraceLn8(J2D_TRACE_INFO,
|
||||
"MTLRenderer_DrawParallelogram "
|
||||
"(x=%6.2f y=%6.2f "
|
||||
"dx1=%6.2f dy1=%6.2f lwr1=%6.2f "
|
||||
"dx2=%6.2f dy2=%6.2f lwr2=%6.2f)",
|
||||
fx11, fy11,
|
||||
dx21, dy21, lwr21,
|
||||
dx12, dy12, lwr12);
|
||||
|
||||
}
|
||||
|
||||
static GLhandleARB aaPgramProgram = 0;
|
||||
|
||||
/*
|
||||
* This shader fills the space between an outer and inner parallelogram.
|
||||
* It can be used to draw an outline by specifying both inner and outer
|
||||
* values. It fills pixels by estimating what portion falls inside the
|
||||
* outer shape, and subtracting an estimate of what portion falls inside
|
||||
* the inner shape. Specifying both inner and outer values produces a
|
||||
* standard "wide outline". Specifying an inner shape that falls far
|
||||
* outside the outer shape allows the same shader to fill the outer
|
||||
* shape entirely since pixels that fall within the outer shape are never
|
||||
* inside the inner shape and so they are filled based solely on their
|
||||
* coverage of the outer shape.
|
||||
*
|
||||
* The setup code renders this shader over the bounds of the outer
|
||||
* shape (or the only shape in the case of a fill operation) and
|
||||
* sets the texture 0 coordinates so that 0,0=>0,1=>1,1=>1,0 in those
|
||||
* texture coordinates map to the four corners of the parallelogram.
|
||||
* Similarly the texture 1 coordinates map the inner shape to the
|
||||
* unit square as well, but in a different coordinate system.
|
||||
*
|
||||
* When viewed in the texture coordinate systems the parallelograms
|
||||
* we are filling are unit squares, but the pixels have then become
|
||||
* tiny parallelograms themselves. Both of the texture coordinate
|
||||
* systems are affine transforms so the rate of change in X and Y
|
||||
* of the texture coordinates are essentially constants and happen
|
||||
* to correspond to the size and direction of the slanted sides of
|
||||
* the distorted pixels relative to the "square mapped" boundary
|
||||
* of the parallelograms.
|
||||
*
|
||||
* The shader uses the dFdx() and dFdy() functions to measure the "rate
|
||||
* of change" of these texture coordinates and thus gets an accurate
|
||||
* measure of the size and shape of a pixel relative to the two
|
||||
* parallelograms. It then uses the bounds of the size and shape
|
||||
* of a pixel to intersect with the unit square to estimate the
|
||||
* coverage of the pixel. Unfortunately, without a lot more work
|
||||
* to calculate the exact area of intersection between a unit
|
||||
* square (the original parallelogram) and a parallelogram (the
|
||||
* distorted pixel), this shader only approximates the pixel
|
||||
* coverage, but emperically the estimate is very useful and
|
||||
* produces visually pleasing results, if not theoretically accurate.
|
||||
*/
|
||||
static const char *aaPgramShaderSource =
|
||||
"void main() {"
|
||||
// Calculate the vectors for the "legs" of the pixel parallelogram
|
||||
// for the outer parallelogram.
|
||||
" vec2 oleg1 = dFdx(gl_TexCoord[0].st);"
|
||||
" vec2 oleg2 = dFdy(gl_TexCoord[0].st);"
|
||||
// Calculate the bounds of the distorted pixel parallelogram.
|
||||
" vec2 corner = gl_TexCoord[0].st - (oleg1+oleg2)/2.0;"
|
||||
" vec2 omin = min(corner, corner+oleg1);"
|
||||
" omin = min(omin, corner+oleg2);"
|
||||
" omin = min(omin, corner+oleg1+oleg2);"
|
||||
" vec2 omax = max(corner, corner+oleg1);"
|
||||
" omax = max(omax, corner+oleg2);"
|
||||
" omax = max(omax, corner+oleg1+oleg2);"
|
||||
// Calculate the vectors for the "legs" of the pixel parallelogram
|
||||
// for the inner parallelogram.
|
||||
" vec2 ileg1 = dFdx(gl_TexCoord[1].st);"
|
||||
" vec2 ileg2 = dFdy(gl_TexCoord[1].st);"
|
||||
// Calculate the bounds of the distorted pixel parallelogram.
|
||||
" corner = gl_TexCoord[1].st - (ileg1+ileg2)/2.0;"
|
||||
" vec2 imin = min(corner, corner+ileg1);"
|
||||
" imin = min(imin, corner+ileg2);"
|
||||
" imin = min(imin, corner+ileg1+ileg2);"
|
||||
" vec2 imax = max(corner, corner+ileg1);"
|
||||
" imax = max(imax, corner+ileg2);"
|
||||
" imax = max(imax, corner+ileg1+ileg2);"
|
||||
// Clamp the bounds of the parallelograms to the unit square to
|
||||
// estimate the intersection of the pixel parallelogram with
|
||||
// the unit square. The ratio of the 2 rectangle areas is a
|
||||
// reasonable estimate of the proportion of coverage.
|
||||
" vec2 o1 = clamp(omin, 0.0, 1.0);"
|
||||
" vec2 o2 = clamp(omax, 0.0, 1.0);"
|
||||
" float oint = (o2.y-o1.y)*(o2.x-o1.x);"
|
||||
" float oarea = (omax.y-omin.y)*(omax.x-omin.x);"
|
||||
" vec2 i1 = clamp(imin, 0.0, 1.0);"
|
||||
" vec2 i2 = clamp(imax, 0.0, 1.0);"
|
||||
" float iint = (i2.y-i1.y)*(i2.x-i1.x);"
|
||||
" float iarea = (imax.y-imin.y)*(imax.x-imin.x);"
|
||||
// Proportion of pixel in outer shape minus the proportion
|
||||
// of pixel in the inner shape == the coverage of the pixel
|
||||
// in the area between the two.
|
||||
" float coverage = oint/oarea - iint / iarea;"
|
||||
" gl_FragColor = gl_Color * coverage;"
|
||||
"}";
|
||||
|
||||
#define ADJUST_PGRAM(V1, DV, V2) \
|
||||
do { \
|
||||
if ((DV) >= 0) { \
|
||||
(V2) += (DV); \
|
||||
} else { \
|
||||
(V1) += (DV); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// Invert the following transform:
|
||||
// DeltaT(0, 0) == (0, 0)
|
||||
// DeltaT(1, 0) == (DX1, DY1)
|
||||
// DeltaT(0, 1) == (DX2, DY2)
|
||||
// DeltaT(1, 1) == (DX1+DX2, DY1+DY2)
|
||||
// TM00 = DX1, TM01 = DX2, (TM02 = X11)
|
||||
// TM10 = DY1, TM11 = DY2, (TM12 = Y11)
|
||||
// Determinant = TM00*TM11 - TM01*TM10
|
||||
// = DX1*DY2 - DX2*DY1
|
||||
// Inverse is:
|
||||
// IM00 = TM11/det, IM01 = -TM01/det
|
||||
// IM10 = -TM10/det, IM11 = TM00/det
|
||||
// IM02 = (TM01 * TM12 - TM11 * TM02) / det,
|
||||
// IM12 = (TM10 * TM02 - TM00 * TM12) / det,
|
||||
|
||||
#define DECLARE_MATRIX(MAT) \
|
||||
jfloat MAT ## 00, MAT ## 01, MAT ## 02, MAT ## 10, MAT ## 11, MAT ## 12
|
||||
|
||||
#define GET_INVERTED_MATRIX(MAT, X11, Y11, DX1, DY1, DX2, DY2, RET_CODE) \
|
||||
do { \
|
||||
jfloat det = DX1*DY2 - DX2*DY1; \
|
||||
if (det == 0) { \
|
||||
RET_CODE; \
|
||||
} \
|
||||
MAT ## 00 = DY2/det; \
|
||||
MAT ## 01 = -DX2/det; \
|
||||
MAT ## 10 = -DY1/det; \
|
||||
MAT ## 11 = DX1/det; \
|
||||
MAT ## 02 = (DX2 * Y11 - DY2 * X11) / det; \
|
||||
MAT ## 12 = (DY1 * X11 - DX1 * Y11) / det; \
|
||||
} while (0)
|
||||
|
||||
#define TRANSFORM(MAT, TX, TY, X, Y) \
|
||||
do { \
|
||||
TX = (X) * MAT ## 00 + (Y) * MAT ## 01 + MAT ## 02; \
|
||||
TY = (X) * MAT ## 10 + (Y) * MAT ## 11 + MAT ## 12; \
|
||||
} while (0)
|
||||
|
||||
void
|
||||
MTLRenderer_FillAAParallelogram(MTLContext *mtlc, BMTLSDOps *dstOps,
|
||||
jfloat fx11, jfloat fy11,
|
||||
jfloat dx21, jfloat dy21,
|
||||
jfloat dx12, jfloat dy12)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLRenderer_FillAAParallelogram");
|
||||
DECLARE_MATRIX(om);
|
||||
// parameters for parallelogram bounding box
|
||||
jfloat bx11, by11, bx22, by22;
|
||||
// parameters for uv texture coordinates of parallelogram corners
|
||||
jfloat u11, v11, u12, v12, u21, v21, u22, v22;
|
||||
|
||||
J2dTraceLn6(J2D_TRACE_INFO,
|
||||
"MTLRenderer_FillAAParallelogram "
|
||||
"(x=%6.2f y=%6.2f "
|
||||
"dx1=%6.2f dy1=%6.2f "
|
||||
"dx2=%6.2f dy2=%6.2f)",
|
||||
fx11, fy11,
|
||||
dx21, dy21,
|
||||
dx12, dy12);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
MTLRenderer_FillAAParallelogramInnerOuter(MTLContext *mtlc, MTLSDOps *dstOps,
|
||||
jfloat ox11, jfloat oy11,
|
||||
jfloat ox21, jfloat oy21,
|
||||
jfloat ox12, jfloat oy12,
|
||||
jfloat ix11, jfloat iy11,
|
||||
jfloat ix21, jfloat iy21,
|
||||
jfloat ix12, jfloat iy12)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLRenderer_FillAAParallelogramInnerOuter");
|
||||
}
|
||||
|
||||
void
|
||||
MTLRenderer_DrawAAParallelogram(MTLContext *mtlc, BMTLSDOps *dstOps,
|
||||
jfloat fx11, jfloat fy11,
|
||||
jfloat dx21, jfloat dy21,
|
||||
jfloat dx12, jfloat dy12,
|
||||
jfloat lwr21, jfloat lwr12)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLRenderer_DrawAAParallelogram");
|
||||
// dx,dy for line width in the "21" and "12" directions.
|
||||
jfloat ldx21, ldy21, ldx12, ldy12;
|
||||
// parameters for "outer" parallelogram
|
||||
jfloat ofx11, ofy11, odx21, ody21, odx12, ody12;
|
||||
// parameters for "inner" parallelogram
|
||||
jfloat ifx11, ify11, idx21, idy21, idx12, idy12;
|
||||
|
||||
J2dTraceLn8(J2D_TRACE_INFO,
|
||||
"MTLRenderer_DrawAAParallelogram "
|
||||
"(x=%6.2f y=%6.2f "
|
||||
"dx1=%6.2f dy1=%6.2f lwr1=%6.2f "
|
||||
"dx2=%6.2f dy2=%6.2f lwr2=%6.2f)",
|
||||
fx11, fy11,
|
||||
dx21, dy21, lwr21,
|
||||
dx12, dy12, lwr12);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
MTLRenderer_EnableAAParallelogramProgram()
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLRenderer_EnableAAParallelogramProgram");
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLRenderer_EnableAAParallelogramProgram");
|
||||
}
|
||||
|
||||
void
|
||||
MTLRenderer_DisableAAParallelogramProgram()
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLRenderer_DisableAAParallelogramProgram");
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLRenderer_DisableAAParallelogramProgram");
|
||||
}
|
||||
|
||||
void debugDraw(MTLContext *ctx, id<MTLTexture> dst, int red/*othrewise blue*/, int freq) {
|
||||
J2dTraceLn1(J2D_TRACE_VERBOSE, "draw debug onto dst tex=%p", dst);
|
||||
MTLContext_SetColor(ctx, red > 0 ? red : 0, 0, red <= 0 ? 255 : 0, 255);
|
||||
id <MTLRenderCommandEncoder> encoder = MTLContext_CreateRenderEncoder(ctx, dst);
|
||||
const int w = dst.width;
|
||||
const int h = dst.height;
|
||||
int x = 2;
|
||||
int y = 2;
|
||||
do {
|
||||
struct Vertex vvv[2] = {
|
||||
{{MTLUtils_normalizeX(dst,x), MTLUtils_normalizeY(dst, y), 0.0}},
|
||||
{{MTLUtils_normalizeX(dst, dst.width - x), MTLUtils_normalizeY(dst, dst.height - y), 0.0}},
|
||||
};
|
||||
[encoder setVertexBytes:vvv length:sizeof(vvv) atIndex:MeshVertexBuffer];
|
||||
[encoder drawPrimitives:MTLPrimitiveTypeLine vertexStart:0 vertexCount:2];
|
||||
|
||||
if (freq == 0)
|
||||
break;
|
||||
if (freq > 0)
|
||||
x += (w - 3)/freq;
|
||||
else
|
||||
y += (h - 3)/freq;
|
||||
} while (x < w && y < h);
|
||||
|
||||
[encoder endEncoding];
|
||||
}
|
||||
|
||||
#endif /* !HEADLESS */
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
#ifndef MTLSurfaceData_h_Included
|
||||
#define MTLSurfaceData_h_Included
|
||||
|
||||
#import "MTLSurfaceDataBase.h"
|
||||
#import "MTLGraphicsConfig.h"
|
||||
#import "AWTWindow.h"
|
||||
#import "MTLLayer.h"
|
||||
|
||||
/**
|
||||
* The CGLSDOps structure contains the CGL-specific information for a given
|
||||
* MTLSurfaceData. It is referenced by the native MTLSDOps structure.
|
||||
*/
|
||||
typedef struct _MTLSDOps {
|
||||
AWTView *peerData;
|
||||
MTLLayer *layer;
|
||||
jint argb[4]; // background clear color
|
||||
MTLGraphicsConfigInfo *configInfo;
|
||||
} MTLSDOps;
|
||||
|
||||
#endif /* MTLSurfaceData_h_Included */
|
||||
@@ -0,0 +1,458 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
#import <stdlib.h>
|
||||
|
||||
#import "sun_java2d_metal_MTLSurfaceData.h"
|
||||
|
||||
#import "jni_util.h"
|
||||
#import "MTLRenderQueue.h"
|
||||
#import "MTLGraphicsConfig.h"
|
||||
#import "MTLSurfaceData.h"
|
||||
#import "ThreadUtilities.h"
|
||||
#include "jlong.h"
|
||||
|
||||
/**
|
||||
* The following methods are implemented in the windowing system (i.e. GLX
|
||||
* and WGL) source files.
|
||||
*/
|
||||
extern jlong MTLSD_GetNativeConfigInfo(BMTLSDOps *mtlsdo);
|
||||
extern jboolean MTLSD_InitMTLWindow(JNIEnv *env, MTLSDOps *mtlsdo);
|
||||
extern void MTLSD_DestroyMTLSurface(JNIEnv *env, MTLSDOps *mtlsdo);
|
||||
|
||||
void MTLSD_SetNativeDimensions(JNIEnv *env, BMTLSDOps *mtlsdo, jint w, jint h);
|
||||
|
||||
/**
|
||||
* This table contains the "pixel formats" for all system memory surfaces
|
||||
* that OpenGL is capable of handling, indexed by the "PF_" constants defined
|
||||
* in MTLSurfaceData.java. These pixel formats contain information that is
|
||||
* passed to OpenGL when copying from a system memory ("Sw") surface to
|
||||
* an OpenGL "Surface" (via glDrawPixels()) or "Texture" (via glTexImage2D()).
|
||||
*/
|
||||
MTLPixelFormat MTPixelFormats[] = {};
|
||||
|
||||
/**
|
||||
* Given a starting value and a maximum limit, returns the first power-of-two
|
||||
* greater than the starting value. If the resulting value is greater than
|
||||
* the maximum limit, zero is returned.
|
||||
*/
|
||||
jint
|
||||
MTLSD_NextPowerOfTwo(jint val, jint max)
|
||||
{
|
||||
jint i;
|
||||
|
||||
if (val > max) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 1; i < val; i *= 2);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if both given dimensions are a power of two.
|
||||
*/
|
||||
static jboolean
|
||||
MTLSD_IsPowerOfTwo(jint width, jint height)
|
||||
{
|
||||
return (((width & (width-1)) | (height & (height-1))) == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes an MTL texture, using the given width and height as
|
||||
* a guide.
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_sun_java2d_metal_MTLSurfaceData_initTexture
|
||||
(JNIEnv *env, jobject mtlsd,
|
||||
jlong pData, jboolean isOpaque,
|
||||
jboolean texNonPow2, jboolean texRect,
|
||||
jint width, jint height)
|
||||
{
|
||||
BMTLSDOps *bmtlsdo = (BMTLSDOps *)jlong_to_ptr(pData);
|
||||
J2dTraceLn3(J2D_TRACE_INFO, "MTLSurfaceData_initTexture: w=%d h=%d p=%p", width, height, bmtlsdo);
|
||||
|
||||
if (bmtlsdo == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initTexture: ops are null");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
if (width <= 0 || height <= 0) {
|
||||
J2dRlsTraceLn2(J2D_TRACE_ERROR, "MTLSurfaceData_initTexture: texture dimensions is incorrect, w=%d, h=%d", width, height);
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
MTLSDOps *mtlsdo = (MTLSDOps *)bmtlsdo->privOps;
|
||||
if (mtlsdo == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initTexture: MTLSDOps are null");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
if (mtlsdo->configInfo == NULL || mtlsdo->configInfo->context == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initTexture: MTLSDOps wasn't initialized (context is null)");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
MTLContext* ctx = mtlsdo->configInfo->context;
|
||||
|
||||
MTLTextureDescriptor *textureDescriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat: MTLPixelFormatBGRA8Unorm width: width height: height mipmapped: NO];
|
||||
bmtlsdo->pTexture = [[ctx->mtlDevice newTextureWithDescriptor: textureDescriptor] retain];
|
||||
bmtlsdo->isOpaque = isOpaque;
|
||||
bmtlsdo->xOffset = 0;
|
||||
bmtlsdo->yOffset = 0;
|
||||
bmtlsdo->width = width;
|
||||
bmtlsdo->height = height;
|
||||
bmtlsdo->textureWidth = width;
|
||||
bmtlsdo->textureHeight = height;
|
||||
bmtlsdo->textureTarget = -1;
|
||||
bmtlsdo->drawableType = MTLSD_TEXTURE;
|
||||
|
||||
MTLSD_SetNativeDimensions(env, bmtlsdo, width, width);
|
||||
J2dTraceLn4(J2D_TRACE_VERBOSE, "\tcreated MTLTexture [texture]: w=%d h=%d bp=%p [tex=%p]", width, height, bmtlsdo, bmtlsdo->pTexture);
|
||||
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a framebuffer object, using the given width and height as
|
||||
* a guide. See MTLSD_InitTextureObject() and MTLSD_initRTexture()
|
||||
* for more information.
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_sun_java2d_metal_MTLSurfaceData_initRTexture
|
||||
(JNIEnv *env, jobject mtlsd,
|
||||
jlong pData, jboolean isOpaque,
|
||||
jboolean texNonPow2, jboolean texRect,
|
||||
jint width, jint height)
|
||||
{
|
||||
|
||||
BMTLSDOps *bmtlsdo = (BMTLSDOps *)jlong_to_ptr(pData);
|
||||
|
||||
if (bmtlsdo == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR,
|
||||
"MTLSurfaceData_initRTexture: BMTLSDOps are null");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
MTLSDOps *mtlsdo = (MTLSDOps *)bmtlsdo->privOps;
|
||||
|
||||
if (mtlsdo == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR,
|
||||
"MTLSurfaceData_initRTexture: MTLSDOps are null");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
if (mtlsdo->configInfo == NULL || mtlsdo->configInfo->context == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSurfaceData_initRTexture: MTLSDOps wasn't initialized (context is null)");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
const MTLContext* ctx = mtlsdo->configInfo->context;
|
||||
MTLTextureDescriptor *textureDescriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat: MTLPixelFormatBGRA8Unorm width: width height: height mipmapped: NO];
|
||||
bmtlsdo->pTexture = [[ctx->mtlDevice newTextureWithDescriptor: textureDescriptor] retain];;
|
||||
|
||||
bmtlsdo->isOpaque = isOpaque;
|
||||
bmtlsdo->xOffset = 0;
|
||||
bmtlsdo->yOffset = 0;
|
||||
bmtlsdo->width = width;
|
||||
bmtlsdo->height = height;
|
||||
bmtlsdo->textureWidth = width;
|
||||
bmtlsdo->textureHeight = height;
|
||||
bmtlsdo->textureTarget = -1;
|
||||
bmtlsdo->drawableType = MTLSD_RT_TEXTURE;
|
||||
|
||||
MTLSD_SetNativeDimensions(env, bmtlsdo, width, width);
|
||||
J2dTraceLn4(J2D_TRACE_VERBOSE, "\tcreated MTLTexture [FBObject]: w=%d h=%d bp=%p [tex=%p]", width, height, bmtlsdo, bmtlsdo->pTexture);
|
||||
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a surface in the backbuffer of a given double-buffered
|
||||
* onscreen window for use in a BufferStrategy.Flip situation. The bounds of
|
||||
* the backbuffer surface should always be kept in sync with the bounds of
|
||||
* the underlying native window.
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_sun_java2d_metal_MTLSurfaceData_initFlipBackbuffer
|
||||
(JNIEnv *env, jobject mtlsd,
|
||||
jlong pData)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLSurfaceData_initFlipBackbuffer");
|
||||
MTLSDOps *mtlsdo = (MTLSDOps *)jlong_to_ptr(pData);
|
||||
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLSurfaceData_initFlipBackbuffer");
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_java2d_metal_MTLSurfaceData_getTextureTarget
|
||||
(JNIEnv *env, jobject mtlsd,
|
||||
jlong pData)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLSurfaceData_getTextureTarget");
|
||||
MTLSDOps *mtlsdo = (MTLSDOps *)jlong_to_ptr(pData);
|
||||
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLSurfaceData_getTextureTarget");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_java2d_metal_MTLSurfaceData_getTextureID
|
||||
(JNIEnv *env, jobject mtlsd,
|
||||
jlong pData)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLSurfaceData_getTextureID");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes nativeWidth/Height fields of the surfaceData object with
|
||||
* passed arguments.
|
||||
*/
|
||||
void
|
||||
MTLSD_SetNativeDimensions(JNIEnv *env, BMTLSDOps *mtlsdo,
|
||||
jint width, jint height)
|
||||
{
|
||||
jobject sdObject;
|
||||
|
||||
sdObject = (*env)->NewLocalRef(env, mtlsdo->sdOps.sdObject);
|
||||
if (sdObject == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
JNU_SetFieldByName(env, NULL, sdObject, "nativeWidth", "I", width);
|
||||
if (!((*env)->ExceptionOccurred(env))) {
|
||||
JNU_SetFieldByName(env, NULL, sdObject, "nativeHeight", "I", height);
|
||||
}
|
||||
|
||||
(*env)->DeleteLocalRef(env, sdObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes native OpenGL resources associated with this surface.
|
||||
*/
|
||||
void
|
||||
MTLSD_Delete(JNIEnv *env, BMTLSDOps *mtlsdo)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLSD_Delete");
|
||||
J2dTraceLn1(J2D_TRACE_INFO, "MTLSD_Delete: type=%d",
|
||||
mtlsdo->drawableType);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the implementation of the general DisposeFunc defined in
|
||||
* SurfaceData.h and used by the Disposer mechanism. It first flushes all
|
||||
* native OpenGL resources and then frees any memory allocated within the
|
||||
* native MTLSDOps structure.
|
||||
*/
|
||||
void
|
||||
MTLSD_Dispose(JNIEnv *env, SurfaceDataOps *ops)
|
||||
{
|
||||
MTLSDOps *mtlsdo = (MTLSDOps *)ops;
|
||||
jlong pConfigInfo = MTLSD_GetNativeConfigInfo(mtlsdo);
|
||||
|
||||
JNU_CallStaticMethodByName(env, NULL, "sun/java2d/metal/MTLSurfaceData",
|
||||
"dispose", "(JJ)V",
|
||||
ptr_to_jlong(ops), pConfigInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the implementation of the general surface LockFunc defined in
|
||||
* SurfaceData.h.
|
||||
*/
|
||||
jint
|
||||
MTLSD_Lock(JNIEnv *env,
|
||||
SurfaceDataOps *ops,
|
||||
SurfaceDataRasInfo *pRasInfo,
|
||||
jint lockflags)
|
||||
{
|
||||
JNU_ThrowInternalError(env, "MTLSD_Lock not implemented!");
|
||||
return SD_FAILURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the implementation of the general GetRasInfoFunc defined in
|
||||
* SurfaceData.h.
|
||||
*/
|
||||
void
|
||||
MTLSD_GetRasInfo(JNIEnv *env,
|
||||
SurfaceDataOps *ops,
|
||||
SurfaceDataRasInfo *pRasInfo)
|
||||
{
|
||||
JNU_ThrowInternalError(env, "MTLSD_GetRasInfo not implemented!");
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the implementation of the general surface UnlockFunc defined in
|
||||
* SurfaceData.h.
|
||||
*/
|
||||
void
|
||||
MTLSD_Unlock(JNIEnv *env,
|
||||
SurfaceDataOps *ops,
|
||||
SurfaceDataRasInfo *pRasInfo)
|
||||
{
|
||||
JNU_ThrowInternalError(env, "MTLSD_Unlock not implemented!");
|
||||
}
|
||||
|
||||
/**
|
||||
* This function disposes of any native windowing system resources associated
|
||||
* with this surface.
|
||||
*/
|
||||
void
|
||||
MTLSD_DestroyMTLSurface(JNIEnv *env, MTLSDOps *mtlsdo)
|
||||
{
|
||||
J2dTraceLn(J2D_TRACE_INFO, "OGLSD_DestroyOGLSurface");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a pointer (as a jlong) to the native CGLGraphicsConfigInfo
|
||||
* associated with the given OGLSDOps. This method can be called from
|
||||
* shared code to retrieve the native GraphicsConfig data in a platform-
|
||||
* independent manner.
|
||||
*/
|
||||
jlong
|
||||
MTLSD_GetNativeConfigInfo(BMTLSDOps *mtlsdo)
|
||||
{
|
||||
J2dTraceLn(J2D_TRACE_INFO, "OGLSD_GetNativeConfigInfo");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function initializes a native window surface and caches the window
|
||||
* bounds in the given OGLSDOps. Returns JNI_TRUE if the operation was
|
||||
* successful; JNI_FALSE otherwise.
|
||||
*/
|
||||
jboolean
|
||||
MTLSD_InitMTLWindow(JNIEnv *env, MTLSDOps *oglsdo)
|
||||
{
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLSD_InitMTLWindow");
|
||||
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
MTLSD_SwapBuffers(JNIEnv *env, jlong pPeerData)
|
||||
{
|
||||
J2dTraceLn(J2D_TRACE_INFO, "OGLSD_SwapBuffers");
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark "--- CGLSurfaceData methods ---"
|
||||
|
||||
extern LockFunc MTLSD_Lock;
|
||||
extern GetRasInfoFunc MTLSD_GetRasInfo;
|
||||
extern UnlockFunc MTLSD_Unlock;
|
||||
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_java2d_metal_MTLSurfaceData_initOps
|
||||
(JNIEnv *env, jobject cglsd,
|
||||
jlong pConfigInfo, jlong pPeerData, jlong layerPtr,
|
||||
jint xoff, jint yoff, jboolean isOpaque)
|
||||
{
|
||||
BMTLSDOps *bmtlsdo = (BMTLSDOps *)SurfaceData_InitOps(env, cglsd, sizeof(BMTLSDOps));
|
||||
MTLSDOps *mtlsdo = (MTLSDOps *)malloc(sizeof(MTLSDOps));
|
||||
|
||||
J2dTraceLn1(J2D_TRACE_INFO, "MTLSurfaceData_initOps p=%p", bmtlsdo);
|
||||
J2dTraceLn1(J2D_TRACE_INFO, " pPeerData=%p", jlong_to_ptr(pPeerData));
|
||||
J2dTraceLn1(J2D_TRACE_INFO, " layerPtr=%p", jlong_to_ptr(layerPtr));
|
||||
J2dTraceLn2(J2D_TRACE_INFO, " xoff=%d, yoff=%d", (int)xoff, (int)yoff);
|
||||
|
||||
if (mtlsdo == NULL) {
|
||||
JNU_ThrowOutOfMemoryError(env, "creating native cgl ops");
|
||||
return;
|
||||
}
|
||||
|
||||
bmtlsdo->privOps = mtlsdo;
|
||||
|
||||
bmtlsdo->sdOps.Lock = MTLSD_Lock;
|
||||
bmtlsdo->sdOps.GetRasInfo = MTLSD_GetRasInfo;
|
||||
bmtlsdo->sdOps.Unlock = MTLSD_Unlock;
|
||||
bmtlsdo->sdOps.Dispose = MTLSD_Dispose;
|
||||
|
||||
bmtlsdo->drawableType = MTLSD_UNDEFINED;
|
||||
bmtlsdo->needsInit = JNI_TRUE;
|
||||
bmtlsdo->xOffset = xoff;
|
||||
bmtlsdo->yOffset = yoff;
|
||||
bmtlsdo->isOpaque = isOpaque;
|
||||
|
||||
mtlsdo->peerData = (AWTView *)jlong_to_ptr(pPeerData);
|
||||
mtlsdo->layer = (MTLLayer *)jlong_to_ptr(layerPtr);
|
||||
mtlsdo->configInfo = (MTLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo);
|
||||
|
||||
if (mtlsdo->configInfo == NULL) {
|
||||
free(mtlsdo);
|
||||
JNU_ThrowNullPointerException(env, "Config info is null in initOps");
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_java2d_metal_MTLSurfaceData_clearWindow
|
||||
(JNIEnv *env, jobject cglsd)
|
||||
{
|
||||
J2dTraceLn(J2D_TRACE_INFO, "CGLSurfaceData_clearWindow");
|
||||
|
||||
BMTLSDOps *mtlsdo = (MTLSDOps*) SurfaceData_GetOps(env, cglsd);
|
||||
MTLSDOps *cglsdo = (MTLSDOps*) mtlsdo->privOps;
|
||||
|
||||
cglsdo->peerData = NULL;
|
||||
cglsdo->layer = NULL;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_java2d_metal_MTLSurfaceData_validate
|
||||
(JNIEnv *env, jobject jsurfacedata,
|
||||
jint xoff, jint yoff, jint width, jint height, jboolean isOpaque)
|
||||
{
|
||||
J2dTraceLn2(J2D_TRACE_INFO, "MTLLSurfaceData_validate: w=%d h=%d", width, height);
|
||||
|
||||
BMTLSDOps *mtlsdo = (BMTLSDOps*)SurfaceData_GetOps(env, jsurfacedata);
|
||||
mtlsdo->needsInit = JNI_TRUE;
|
||||
mtlsdo->xOffset = xoff;
|
||||
mtlsdo->yOffset = yoff;
|
||||
|
||||
mtlsdo->width = width;
|
||||
mtlsdo->height = height;
|
||||
mtlsdo->isOpaque = isOpaque;
|
||||
|
||||
if (mtlsdo->drawableType == MTLSD_WINDOW) {
|
||||
// J2dTraceLn4(J2D_TRACE_INFO, "MTLContext_SetSurfaces: w=%d h=%d src=%p dst=%p", width, height, mtlsdo, mtlsdo);
|
||||
MTLContext_SetSurfaces(env, ptr_to_jlong(mtlsdo), ptr_to_jlong(mtlsdo));
|
||||
|
||||
// we have to explicitly tell the NSOpenGLContext that its target
|
||||
// drawable has changed size
|
||||
MTLSDOps *cglsdo = (MTLSDOps *)mtlsdo->privOps;
|
||||
MTLContext *mtlc = cglsdo->configInfo->context;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
#ifndef MTLSurfaceDataBase_h_Included
|
||||
#define MTLSurfaceDataBase_h_Included
|
||||
|
||||
#include "java_awt_image_AffineTransformOp.h"
|
||||
#include "sun_java2d_metal_MTLSurfaceData.h"
|
||||
#include "sun_java2d_pipe_hw_AccelSurface.h"
|
||||
|
||||
#include "SurfaceData.h"
|
||||
#include "Trace.h"
|
||||
#include "MTLFuncs.h"
|
||||
|
||||
|
||||
/**
|
||||
* The MTLPixelFormat structure contains all the information OpenGL needs to
|
||||
* know when copying from or into a particular system memory image buffer (via
|
||||
* glDrawPixels(), glReadPixels, glTexSubImage2D(), etc).
|
||||
*
|
||||
* GLenum format;
|
||||
* The pixel format parameter used in glDrawPixels() and other similar calls.
|
||||
* Indicates the component ordering for each pixel (e.g. GL_BGRA).
|
||||
*
|
||||
* GLenum type;
|
||||
* The pixel data type parameter used in glDrawPixels() and other similar
|
||||
* calls. Indicates the data type for an entire pixel or for each component
|
||||
* in a pixel (e.g. GL_UNSIGNED_BYTE with GL_BGR means a pixel consists of
|
||||
* 3 unsigned byte components, blue first, then green, then red;
|
||||
* GL_UNSIGNED_INT_8_8_8_8_REV with GL_BGRA means a pixel consists of 1
|
||||
* unsigned integer comprised of four byte components, alpha first, then red,
|
||||
* then green, then blue).
|
||||
*
|
||||
* jint alignment;
|
||||
* The byte alignment parameter used in glPixelStorei(GL_UNPACK_ALIGNMENT). A
|
||||
* value of 4 indicates that each pixel starts on a 4-byte aligned region in
|
||||
* memory, and so on. This alignment parameter helps OpenGL speed up pixel
|
||||
* transfer operations by transferring memory in aligned blocks.
|
||||
*
|
||||
* jboolean hasAlpha;
|
||||
* If true, indicates that this pixel format contains an alpha component.
|
||||
*
|
||||
* jboolean isPremult;
|
||||
* If true, indicates that this pixel format contains color components that
|
||||
* have been pre-multiplied by their corresponding alpha component.
|
||||
*/
|
||||
typedef struct {
|
||||
//GLenum format;
|
||||
//GLenum type;
|
||||
jint format;
|
||||
jint type;
|
||||
jint alignment;
|
||||
jboolean hasAlpha;
|
||||
jboolean isPremult;
|
||||
} MTPixelFormat;
|
||||
|
||||
/**
|
||||
* The MTLSDOps structure describes a native OpenGL surface and contains all
|
||||
* information pertaining to the native surface. Some information about
|
||||
* the more important/different fields:
|
||||
*
|
||||
* void *privOps;
|
||||
* Pointer to native-specific (GLX, WGL, etc.) SurfaceData info, such as the
|
||||
* native Drawable handle and GraphicsConfig data.
|
||||
*
|
||||
* jint drawableType;
|
||||
* The surface type; can be any one of the surface type constants defined
|
||||
* below (MTLSD_WINDOW, MTLSD_TEXTURE, etc).
|
||||
*
|
||||
* GLenum activeBuffer;
|
||||
* Can be either GL_FRONT if this is the front buffer surface of an onscreen
|
||||
* window or a pbuffer surface, or GL_BACK if this is the backbuffer surface
|
||||
* of an onscreen window.
|
||||
*
|
||||
* jboolean isOpaque;
|
||||
* If true, the surface should be treated as being fully opaque. If
|
||||
* the underlying surface (e.g. pbuffer) has an alpha channel and isOpaque
|
||||
* is true, then we should take appropriate action (i.e. call glColorMask()
|
||||
* to disable writes into the alpha channel) to ensure that the surface
|
||||
* remains 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 OpenGL viewport origin from the lower-left
|
||||
* corner of the heavyweight drawable. For example, a top-level frame on
|
||||
* Windows XP has lower-left insets of (4,4). The OpenGL viewport origin
|
||||
* would typically begin at the lower-left corner of the client region (inside
|
||||
* the frame decorations), but AWT/Swing will take the insets into account
|
||||
* when rendering into that window. So in order to account for this, we
|
||||
* need to adjust the OpenGL viewport origin by an x/yOffset of (-4,-4). On
|
||||
* X11, top-level frames typically don't have this insets issue, so their
|
||||
* x/yOffset would be (0,0) (the same applies to pbuffers).
|
||||
*
|
||||
* jint width/height;
|
||||
* The cached surface bounds. For offscreen surface types (MTLSD_FBOBJECT,
|
||||
* MTLSD_TEXTURE, etc.) these values must remain constant. Onscreen window
|
||||
* surfaces (MTLSD_WINDOW, MTLSD_FLIP_BACKBUFFER, 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.
|
||||
*
|
||||
* GLuint textureID;
|
||||
* The texture object handle, as generated by glGenTextures(). If this value
|
||||
* is zero, the texture has not yet been initialized.
|
||||
*
|
||||
* jint textureWidth/Height;
|
||||
* The actual bounds of the texture object for this surface. If the
|
||||
* GL_ARB_texture_non_power_of_two extension is not present, the dimensions
|
||||
* of an OpenGL texture object must be a power-of-two (e.g. 64x32 or 128x512).
|
||||
* The texture image that we care about has dimensions specified by the width
|
||||
* and height fields in this MTLSDOps structure. For example, if the image
|
||||
* to be stored in the texture has dimensions 115x47, the actual OpenGL
|
||||
* texture we allocate will have dimensions 128x64 to meet the pow2
|
||||
* restriction. The image bounds within the texture can be accessed using
|
||||
* floating point texture coordinates in the range [0.0,1.0].
|
||||
*
|
||||
* GLenum textureTarget;
|
||||
* The texture target of the texture object for this surface. If this
|
||||
* surface is not backed by a texture, this value is set to zero. Otherwise,
|
||||
* this value is GL_TEXTURE_RECTANGLE_ARB when the GL_ARB_texture_rectangle
|
||||
* extension is in use; if not, it is set to GL_TEXTURE_2D.
|
||||
*
|
||||
* GLint textureFilter;
|
||||
* The current filter state for this texture object (can be either GL_NEAREST
|
||||
* or GL_LINEAR). We cache this value here and check it before updating
|
||||
* the filter state to avoid redundant calls to glTexParameteri() when the
|
||||
* filter state remains constant (see the MTLSD_UPDATE_TEXTURE_FILTER()
|
||||
* macro below).
|
||||
*
|
||||
* GLuint fbobjectID, depthID;
|
||||
* The object handles for the framebuffer object and depth renderbuffer
|
||||
* associated with this surface. These fields are only used when
|
||||
* drawableType is MTLSD_FBOBJECT, otherwise they are zero.
|
||||
*/
|
||||
typedef struct {
|
||||
SurfaceDataOps sdOps;
|
||||
void *privOps;
|
||||
jint drawableType;
|
||||
jint activeBuffer;
|
||||
jboolean isOpaque;
|
||||
jboolean needsInit;
|
||||
jint xOffset;
|
||||
jint yOffset;
|
||||
jint width;
|
||||
jint height;
|
||||
void* pTexture;
|
||||
jint textureWidth;
|
||||
jint textureHeight;
|
||||
/* GLenum */ jint textureTarget;
|
||||
/* GLint */ jint textureFilter;
|
||||
/* GLuint */ jint fbobjectID;
|
||||
/* GLuint */ jint depthID;
|
||||
} BMTLSDOps;
|
||||
|
||||
#define MTLSD_UNDEFINED sun_java2d_pipe_hw_AccelSurface_UNDEFINED
|
||||
#define MTLSD_WINDOW sun_java2d_pipe_hw_AccelSurface_WINDOW
|
||||
#define MTLSD_TEXTURE sun_java2d_pipe_hw_AccelSurface_TEXTURE
|
||||
#define MTLSD_FLIP_BACKBUFFER sun_java2d_pipe_hw_AccelSurface_FLIP_BACKBUFFER
|
||||
#define MTLSD_RT_TEXTURE sun_java2d_pipe_hw_AccelSurface_RT_TEXTURE
|
||||
|
||||
/**
|
||||
* These are shorthand names for the filtering method constants used by
|
||||
* image transform methods.
|
||||
*/
|
||||
#define MTLSD_XFORM_DEFAULT 0
|
||||
#define MTLSD_XFORM_NEAREST_NEIGHBOR \
|
||||
java_awt_image_AffineTransformOp_TYPE_NEAREST_NEIGHBOR
|
||||
#define MTLSD_XFORM_BILINEAR \
|
||||
java_awt_image_AffineTransformOp_TYPE_BILINEAR
|
||||
|
||||
/**
|
||||
* Exported methods.
|
||||
*/
|
||||
jint MTLSD_Lock(JNIEnv *env,
|
||||
SurfaceDataOps *ops, SurfaceDataRasInfo *pRasInfo,
|
||||
jint lockflags);
|
||||
void MTLSD_GetRasInfo(JNIEnv *env,
|
||||
SurfaceDataOps *ops, SurfaceDataRasInfo *pRasInfo);
|
||||
void MTLSD_Unlock(JNIEnv *env,
|
||||
SurfaceDataOps *ops, SurfaceDataRasInfo *pRasInfo);
|
||||
void MTLSD_Dispose(JNIEnv *env, SurfaceDataOps *ops);
|
||||
void MTLSD_Delete(JNIEnv *env, BMTLSDOps *mtlsdo);
|
||||
jint MTLSD_NextPowerOfTwo(jint val, jint max);
|
||||
|
||||
#endif /* MTLSurfaceDataBase_h_Included */
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
#ifndef MTLTextRenderer_h_Included
|
||||
#define MTLTextRenderer_h_Included
|
||||
|
||||
#include <jni.h>
|
||||
#include <jlong.h>
|
||||
#include "sun_java2d_pipe_BufferedTextPipe.h"
|
||||
#include "MTLContext.h"
|
||||
#include "MTLSurfaceData.h"
|
||||
|
||||
#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
|
||||
|
||||
void MTLTR_EnableGlyphVertexCache(MTLContext *mtlc);
|
||||
void MTLTR_DisableGlyphVertexCache(MTLContext *mtlc);
|
||||
|
||||
void MTLTR_DrawGlyphList(JNIEnv *env, MTLContext *mtlc, MTLSDOps *dstOps,
|
||||
jint totalGlyphs, jboolean usePositions,
|
||||
jboolean subPixPos, jboolean rgbOrder,
|
||||
jint lcdContrast,
|
||||
jfloat glyphListOrigX, jfloat glyphListOrigY,
|
||||
unsigned char *images, unsigned char *positions);
|
||||
|
||||
#endif /* MTLTextRenderer_h_Included */
|
||||
@@ -0,0 +1,382 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
#ifndef HEADLESS
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <jlong.h>
|
||||
|
||||
#include "sun_java2d_metal_MTLTextRenderer.h"
|
||||
|
||||
#include "SurfaceData.h"
|
||||
#include "MTLContext.h"
|
||||
#include "MTLRenderQueue.h"
|
||||
#include "MTLTextRenderer.h"
|
||||
#include "MTLVertexCache.h"
|
||||
#include "AccelGlyphCache.h"
|
||||
|
||||
/**
|
||||
* The following constants define the inner and outer bounds of the
|
||||
* accelerated glyph cache.
|
||||
*/
|
||||
#define MTLTR_CACHE_WIDTH 1024
|
||||
#define MTLTR_CACHE_HEIGHT 1024
|
||||
#define MTLTR_CACHE_CELL_WIDTH 64
|
||||
#define MTLTR_CACHE_CELL_HEIGHT 64
|
||||
|
||||
/**
|
||||
* The current "glyph mode" state. This variable is used to track the
|
||||
* codepath used to render a particular glyph. This variable is reset to
|
||||
* MODE_NOT_INITED at the beginning of every call to MTLTR_DrawGlyphList().
|
||||
* As each glyph is rendered, the glyphMode variable is updated to reflect
|
||||
* the current mode, so if the current mode is the same as the mode used
|
||||
* to render the previous glyph, we can avoid doing costly setup operations
|
||||
* each time.
|
||||
*/
|
||||
typedef enum {
|
||||
MODE_NOT_INITED,
|
||||
MODE_USE_CACHE_GRAY,
|
||||
MODE_USE_CACHE_LCD,
|
||||
MODE_NO_CACHE_GRAY,
|
||||
MODE_NO_CACHE_LCD,
|
||||
MODE_NO_CACHE_COLOR
|
||||
} GlyphMode;
|
||||
static GlyphMode glyphMode = MODE_NOT_INITED;
|
||||
|
||||
/**
|
||||
* There are two separate glyph caches: for AA and for LCD.
|
||||
* Once one of them is initialized as either GRAY or LCD, it
|
||||
* stays in that mode for the duration of the application. It should
|
||||
* be safe to use this one glyph cache for all screens in a multimon
|
||||
* environment, since the glyph cache texture is shared between all contexts,
|
||||
* and (in theory) OpenGL drivers should be smart enough to manage that
|
||||
* texture across all screens.
|
||||
*/
|
||||
|
||||
static GlyphCacheInfo *glyphCacheLCD = NULL;
|
||||
static GlyphCacheInfo *glyphCacheAA = NULL;
|
||||
|
||||
/**
|
||||
* The handle to the LCD text fragment program object.
|
||||
*/
|
||||
static GLhandleARB lcdTextProgram = 0;
|
||||
|
||||
/**
|
||||
* This value tracks the previous LCD contrast setting, so if the contrast
|
||||
* value hasn't changed since the last time the gamma uniforms were
|
||||
* updated (not very common), then we can skip updating the unforms.
|
||||
*/
|
||||
static jint lastLCDContrast = -1;
|
||||
|
||||
/**
|
||||
* This value tracks the previous LCD rgbOrder setting, so if the rgbOrder
|
||||
* value has changed since the last time, it indicates that we need to
|
||||
* invalidate the cache, which may already store glyph images in the reverse
|
||||
* order. Note that in most real world applications this value will not
|
||||
* change over the course of the application, but tests like Font2DTest
|
||||
* allow for changing the ordering at runtime, so we need to handle that case.
|
||||
*/
|
||||
static jboolean lastRGBOrder = JNI_TRUE;
|
||||
|
||||
/**
|
||||
* This constant defines the size of the tile to use in the
|
||||
* MTLTR_DrawLCDGlyphNoCache() method. See below for more on why we
|
||||
* restrict this value to a particular size.
|
||||
*/
|
||||
#define MTLTR_NOCACHE_TILE_SIZE 64
|
||||
|
||||
/**
|
||||
* These constants define the size of the "cached destination" texture.
|
||||
* This texture is only used when rendering LCD-optimized text, as that
|
||||
* codepath needs direct access to the destination. There is no way to
|
||||
* access the framebuffer directly from an OpenGL shader, so we need to first
|
||||
* copy the destination region corresponding to a particular glyph into
|
||||
* this cached texture, and then that texture will be accessed inside the
|
||||
* shader. Copying the destination into this cached texture can be a very
|
||||
* expensive operation (accounting for about half the rendering time for
|
||||
* LCD text), so to mitigate this cost we try to bulk read a horizontal
|
||||
* region of the destination at a time. (These values are empirically
|
||||
* derived for the common case where text runs horizontally.)
|
||||
*
|
||||
* Note: It is assumed in various calculations below that:
|
||||
* (MTLTR_CACHED_DEST_WIDTH >= MTLTR_CACHE_CELL_WIDTH) &&
|
||||
* (MTLTR_CACHED_DEST_WIDTH >= MTLTR_NOCACHE_TILE_SIZE) &&
|
||||
* (MTLTR_CACHED_DEST_HEIGHT >= MTLTR_CACHE_CELL_HEIGHT) &&
|
||||
* (MTLTR_CACHED_DEST_HEIGHT >= MTLTR_NOCACHE_TILE_SIZE)
|
||||
*/
|
||||
#define MTLTR_CACHED_DEST_WIDTH 1024
|
||||
#define MTLTR_CACHED_DEST_HEIGHT (MTLTR_CACHE_CELL_HEIGHT * 2)
|
||||
|
||||
/**
|
||||
* The handle to the "cached destination" texture object.
|
||||
*/
|
||||
static GLuint cachedDestTextureID = 0;
|
||||
|
||||
/**
|
||||
* The current bounds of the "cached destination" texture, in destination
|
||||
* coordinate space. The width/height of these bounds will not exceed the
|
||||
* MTLTR_CACHED_DEST_WIDTH/HEIGHT values defined above. These bounds are
|
||||
* only considered valid when the isCachedDestValid flag is JNI_TRUE.
|
||||
*/
|
||||
static SurfaceDataBounds cachedDestBounds;
|
||||
|
||||
/**
|
||||
* This flag indicates whether the "cached destination" texture contains
|
||||
* valid data. This flag is reset to JNI_FALSE at the beginning of every
|
||||
* call to MTLTR_DrawGlyphList(). Once we copy valid destination data
|
||||
* into the cached texture, this flag is set to JNI_TRUE. This way, we can
|
||||
* limit the number of times we need to copy destination data, which is a
|
||||
* very costly operation.
|
||||
*/
|
||||
static jboolean isCachedDestValid = JNI_FALSE;
|
||||
|
||||
/**
|
||||
* The bounds of the previously rendered LCD glyph, in destination
|
||||
* coordinate space. We use these bounds to determine whether the glyph
|
||||
* currently being rendered overlaps the previously rendered glyph (i.e.
|
||||
* its bounding box intersects that of the previously rendered glyph). If
|
||||
* so, we need to re-read the destination area associated with that previous
|
||||
* glyph so that we can correctly blend with the actual destination data.
|
||||
*/
|
||||
static SurfaceDataBounds previousGlyphBounds;
|
||||
|
||||
/**
|
||||
* Initializes the one glyph cache (texture and data structure).
|
||||
* If lcdCache is JNI_TRUE, the texture will contain RGB data,
|
||||
* otherwise we will simply store the grayscale/monochrome glyph images
|
||||
* as intensity values (which work well with the GL_MODULATE function).
|
||||
*/
|
||||
static jboolean
|
||||
MTLTR_InitGlyphCache(jboolean lcdCache)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLTR_InitGlyphCache");
|
||||
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given glyph to the glyph cache (texture and data structure)
|
||||
* associated with the given MTLContext.
|
||||
*/
|
||||
static void
|
||||
MTLTR_AddTmTLyphCache(GlyphInfo *glyph, GLenum pixelFormat)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLTR_AddTmTLyphCache");
|
||||
|
||||
CacheCellInfo *ccinfo;
|
||||
GlyphCacheInfo *gcinfo;
|
||||
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLTR_AddTmTLyphCache");
|
||||
J2dTracePrimitive("MTLTR_InitGlyphCache");
|
||||
}
|
||||
|
||||
/**
|
||||
* (Re)Initializes the gamma related uniforms.
|
||||
*
|
||||
* The given contrast value is an int in the range [100, 250] which we will
|
||||
* then scale to fit in the range [1.0, 2.5].
|
||||
*/
|
||||
static jboolean
|
||||
MTLTR_UpdateLCDTextContrast(jint contrast)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLTR_UpdateLCDTextContrast");
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the current gamma-adjusted source color ("src_adj") of the LCD
|
||||
* text shader program. Note that we could calculate this value in the
|
||||
* shader (e.g. just as we do for "dst_adj"), but would be unnecessary work
|
||||
* (and a measurable performance hit, maybe around 5%) since this value is
|
||||
* constant over the entire glyph list. So instead we just calculate the
|
||||
* gamma-adjusted value once and update the uniform parameter of the LCD
|
||||
* shader as needed.
|
||||
*/
|
||||
static jboolean
|
||||
MTLTR_UpdateLCDTextColor(jint contrast)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLTR_UpdateLCDTextColor");
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables the LCD text shader and updates any related state, such as the
|
||||
* gamma lookup table textures.
|
||||
*/
|
||||
static jboolean
|
||||
MTLTR_EnableLCDGlyphModeState(GLuint glyphTextureID,
|
||||
GLuint dstTextureID,
|
||||
jint contrast)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLTR_EnableLCDGlyphModeState");
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
MTLTR_EnableGlyphVertexCache(MTLContext *mtlc)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLTR_EnableGlyphVertexCache");
|
||||
}
|
||||
|
||||
void
|
||||
MTLTR_DisableGlyphVertexCache(MTLContext *mtlc)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLTR_DisableGlyphVertexCache");
|
||||
J2dTraceNotImplPrimitive("MTLTR_DisableGlyphVertexCache");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables any pending state associated with the current "glyph mode".
|
||||
*/
|
||||
void
|
||||
MTLTR_DisableGlyphModeState()
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLTR_DisableGlyphModeState");
|
||||
J2dTraceLn1(J2D_TRACE_VERBOSE,
|
||||
"MTLTR_DisableGlyphModeState: mode=%d", glyphMode);
|
||||
}
|
||||
|
||||
static jboolean
|
||||
MTLTR_DrawGrayscaleGlyphViaCache(MTLContext *mtlc,
|
||||
GlyphInfo *ginfo, jint x, jint y)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLTR_DisableGlyphVertexCache");
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates to true if the rectangle defined by gx1/gy1/gx2/gy2 is
|
||||
* inside outerBounds.
|
||||
*/
|
||||
#define INSIDE(gx1, gy1, gx2, gy2, outerBounds) \
|
||||
(((gx1) >= outerBounds.x1) && ((gy1) >= outerBounds.y1) && \
|
||||
((gx2) <= outerBounds.x2) && ((gy2) <= outerBounds.y2))
|
||||
|
||||
/**
|
||||
* Evaluates to true if the rectangle defined by gx1/gy1/gx2/gy2 intersects
|
||||
* the rectangle defined by bounds.
|
||||
*/
|
||||
#define INTERSECTS(gx1, gy1, gx2, gy2, bounds) \
|
||||
((bounds.x2 > (gx1)) && (bounds.y2 > (gy1)) && \
|
||||
(bounds.x1 < (gx2)) && (bounds.y1 < (gy2)))
|
||||
|
||||
/**
|
||||
* This method checks to see if the given LCD glyph bounds fall within the
|
||||
* cached destination texture bounds. If so, this method can return
|
||||
* immediately. If not, this method will copy a chunk of framebuffer data
|
||||
* into the cached destination texture and then update the current cached
|
||||
* destination bounds before returning.
|
||||
*/
|
||||
static void
|
||||
MTLTR_UpdateCachedDestination(MTLSDOps *dstOps, GlyphInfo *ginfo,
|
||||
jint gx1, jint gy1, jint gx2, jint gy2,
|
||||
jint glyphIndex, jint totalGlyphs)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLTR_UpdateCachedDestination");
|
||||
}
|
||||
|
||||
static jboolean
|
||||
MTLTR_DrawLCDGlyphViaCache(MTLContext *mtlc, MTLSDOps *dstOps,
|
||||
GlyphInfo *ginfo, jint x, jint y,
|
||||
jint glyphIndex, jint totalGlyphs,
|
||||
jboolean rgbOrder, jint contrast,
|
||||
jint dstTextureID, jboolean * opened)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLTR_DrawLCDGlyphViaCache");
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
static jboolean
|
||||
MTLTR_DrawGrayscaleGlyphNoCache(MTLContext *mtlc,
|
||||
GlyphInfo *ginfo, jint x, jint y)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLTR_DrawGrayscaleGlyphNoCache");
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
static jboolean
|
||||
MTLTR_DrawLCDGlyphNoCache(MTLContext *mtlc, MTLSDOps *dstOps,
|
||||
GlyphInfo *ginfo, jint x, jint y,
|
||||
jint rowBytesOffset,
|
||||
jboolean rgbOrder, jint contrast,
|
||||
jint dstTextureID)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLTR_DrawLCDGlyphNoCache");
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
static jboolean
|
||||
MTLTR_DrawColorGlyphNoCache(MTLContext *mtlc, GlyphInfo *ginfo, jint x, jint y)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLTR_DrawColorGlyphNoCache");
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
|
||||
// see DrawGlyphList.c for more on this macro...
|
||||
#define FLOOR_ASSIGN(l, r) \
|
||||
if ((r)<0) (l) = ((int)floor(r)); else (l) = ((int)(r))
|
||||
|
||||
void
|
||||
MTLTR_DrawGlyphList(JNIEnv *env, MTLContext *mtlc, MTLSDOps *dstOps,
|
||||
jint totalGlyphs, jboolean usePositions,
|
||||
jboolean subPixPos, jboolean rgbOrder, jint lcdContrast,
|
||||
jfloat glyphListOrigX, jfloat glyphListOrigY,
|
||||
unsigned char *images, unsigned char *positions)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLTR_DrawGlyphList");
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_java2d_metal_MTLTextRenderer_drawGlyphList
|
||||
(JNIEnv *env, jobject self,
|
||||
jint numGlyphs, jboolean usePositions,
|
||||
jboolean subPixPos, jboolean rgbOrder, jint lcdContrast,
|
||||
jfloat glyphListOrigX, jfloat glyphListOrigY,
|
||||
jlongArray imgArray, jfloatArray posArray)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLTextRenderer_drawGlyphList");
|
||||
}
|
||||
|
||||
#endif /* !HEADLESS */
|
||||
@@ -0,0 +1,37 @@
|
||||
#ifndef MTLTexturePool_h_Included
|
||||
#define MTLTexturePool_h_Included
|
||||
#import <Metal/Metal.h>
|
||||
|
||||
@interface MTLTexturePoolItem : NSObject
|
||||
{
|
||||
@private
|
||||
|
||||
id<MTLTexture> texture;
|
||||
bool isBusy;
|
||||
}
|
||||
|
||||
@property (readwrite, retain) id<MTLTexture> texture;
|
||||
@property (readwrite, assign) bool isBusy;
|
||||
|
||||
- (id) initWithTexture:(id<MTLTexture>)tex;
|
||||
@end
|
||||
|
||||
// NOTE: owns all MTLTexture objects
|
||||
@interface MTLTexturePool : NSObject
|
||||
{
|
||||
@private
|
||||
|
||||
id<MTLDevice> device;
|
||||
NSMutableArray<MTLTexturePoolItem*> * pool;
|
||||
}
|
||||
|
||||
@property (readwrite, assign) id<MTLDevice> device;
|
||||
@property (readwrite, retain) NSMutableArray<MTLTexturePoolItem*> * pool;
|
||||
|
||||
- (id) initWithDevice:(id<MTLDevice>)device;
|
||||
- (id<MTLTexture>) getTexture:(int)width height:(int)height format:(MTLPixelFormat)format;
|
||||
- (void) markTextureFree:(id<MTLTexture>)texture;
|
||||
- (void) markAllTexturesFree;
|
||||
@end
|
||||
|
||||
#endif /* MTLTexturePool_h_Included */
|
||||
@@ -0,0 +1,92 @@
|
||||
#import "MTLTexturePool.h"
|
||||
#import "Trace.h"
|
||||
|
||||
@implementation MTLTexturePoolItem
|
||||
|
||||
@synthesize texture;
|
||||
@synthesize isBusy;
|
||||
|
||||
- (id) initWithTexture:(id<MTLTexture>)tex {
|
||||
self = [super init];
|
||||
if (self == nil) return self;
|
||||
self.texture = tex;
|
||||
isBusy = NO;
|
||||
return self;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation MTLTexturePool
|
||||
|
||||
@synthesize device;
|
||||
@synthesize pool;
|
||||
|
||||
- (id) initWithDevice:(id<MTLDevice>)dev {
|
||||
self = [super init];
|
||||
if (self == nil) return self;
|
||||
|
||||
self.device = dev;
|
||||
self.pool = [NSMutableArray arrayWithCapacity:10];
|
||||
return self;
|
||||
}
|
||||
|
||||
// NOTE: called from RQ-thread (on blit operations)
|
||||
- (id<MTLTexture>) getTexture:(int)width height:(int)height format:(MTLPixelFormat)format {
|
||||
@synchronized (self) {
|
||||
// 1. find free item
|
||||
// TODO: optimize search, use Map<(w,h,pf), TexPoolItem>
|
||||
const int count = [self.pool count];
|
||||
for (int c = 0; c < count; ++c) {
|
||||
MTLTexturePoolItem *tpi = [self.pool objectAtIndex:c];
|
||||
if (tpi == nil)
|
||||
continue;
|
||||
// TODO: use checks tpi.texture.width <= width && tpi.texture.height <= height
|
||||
if (tpi.texture.width == width && tpi.texture.height == height && tpi.texture.pixelFormat == format &&
|
||||
!tpi.isBusy) {
|
||||
tpi.isBusy = YES;
|
||||
return tpi.texture;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. create
|
||||
MTLTextureDescriptor *textureDescriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:format width:width height:height mipmapped:NO];
|
||||
id <MTLTexture> tex = [self.device newTextureWithDescriptor:textureDescriptor];
|
||||
MTLTexturePoolItem *tpi = [[MTLTexturePoolItem alloc] initWithTexture:tex];
|
||||
[self.pool addObject:tpi];
|
||||
J2dTraceLn4(J2D_TRACE_VERBOSE, "MTLTexturePool: created pool item: tex=%p, w=%d h=%d, pf=%d", tex, width, height, format);
|
||||
return tpi.texture;
|
||||
}
|
||||
};
|
||||
|
||||
// NOTE: called from completion-handler (pooled thread)
|
||||
- (void) markTextureFree:(id<MTLTexture>)texture {
|
||||
// TODO: optimize search, use Map<(w,h,pf), TexPoolItem>
|
||||
@synchronized (self) {
|
||||
const int count = [self.pool count];
|
||||
for (int c = 0; c < count; ++c) {
|
||||
MTLTexturePoolItem * tpi = [self.pool objectAtIndex:c];
|
||||
if (tpi == nil)
|
||||
continue;
|
||||
if (tpi.texture == texture) {
|
||||
tpi.isBusy = NO;
|
||||
return;
|
||||
}
|
||||
}
|
||||
J2dTraceLn1(J2D_TRACE_ERROR, "MTLTexturePool: can't find item with texture %p", texture);
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: called from completion-handler (pooled thread)
|
||||
- (void) markAllTexturesFree {
|
||||
@synchronized (self) {
|
||||
const int count = [self.pool count];
|
||||
for (int c = 0; c < count; ++c) {
|
||||
MTLTexturePoolItem *tpi = [self.pool objectAtIndex:c];
|
||||
if (tpi == nil)
|
||||
continue;
|
||||
tpi.isBusy = NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,9 @@
|
||||
#ifndef MTLUtils_h_Included
|
||||
#define MTLUtils_h_Included
|
||||
|
||||
#import <Metal/Metal.h>
|
||||
|
||||
float MTLUtils_normalizeX(id<MTLTexture> dest, float x);
|
||||
float MTLUtils_normalizeY(id<MTLTexture> dest, float y);
|
||||
|
||||
#endif /* MTLUtils_h_Included */
|
||||
@@ -0,0 +1,26 @@
|
||||
#include "MTLUtils.h"
|
||||
|
||||
float MTLUtils_normalizeX(id<MTLTexture> dest, float x) { return (2.0*x/dest.width) - 1.0; }
|
||||
float MTLUtils_normalizeY(id<MTLTexture> dest, float y) { return 2.0*(1.0 - y/dest.height) - 1.0; }
|
||||
|
||||
#include <jni.h>
|
||||
#include <simd/simd.h>
|
||||
#include "common.h"
|
||||
#include "Trace.h"
|
||||
|
||||
extern void J2dTraceImpl(int level, jboolean cr, const char *string, ...);
|
||||
void J2dTraceTraceVector(simd_float4 pt) {
|
||||
J2dTraceImpl(J2D_TRACE_VERBOSE, JNI_FALSE, "[%lf %lf %lf %lf]", pt.x, pt.y, pt.z, pt.w);
|
||||
}
|
||||
|
||||
void checkTransform(struct TxtVertex txpt, simd_float4x4 transform4x4) {
|
||||
J2dTraceImpl(J2D_TRACE_VERBOSE, JNI_FALSE, "check transform: ");
|
||||
|
||||
simd_float4 fpt = simd_make_float4(txpt.position[0], txpt.position[1], txpt.position[2], 1.f);
|
||||
simd_float4 fpt_trans = simd_mul(transform4x4, fpt);
|
||||
J2dTraceTraceVector(fpt);
|
||||
J2dTraceImpl(J2D_TRACE_VERBOSE, JNI_FALSE, " ===>>> ");
|
||||
J2dTraceTraceVector(fpt_trans);
|
||||
J2dTraceLn(J2D_TRACE_VERBOSE, " ");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
#ifndef MTLVertexCache_h_Included
|
||||
#define MTLVertexCache_h_Included
|
||||
|
||||
#include "j2d_md.h"
|
||||
#include "MTLContext.h"
|
||||
|
||||
/**
|
||||
* Constants that control the size of the vertex cache.
|
||||
*/
|
||||
#define MTLVC_MAX_INDEX 1024
|
||||
|
||||
/**
|
||||
* Constants that control the size of the texture tile cache used for
|
||||
* mask operations.
|
||||
*/
|
||||
#define MTLVC_MASK_CACHE_TILE_WIDTH 32
|
||||
#define MTLVC_MASK_CACHE_TILE_HEIGHT 32
|
||||
#define MTLVC_MASK_CACHE_TILE_SIZE \
|
||||
(MTLVC_MASK_CACHE_TILE_WIDTH * MTLVC_MASK_CACHE_TILE_HEIGHT)
|
||||
|
||||
#define MTLVC_MASK_CACHE_WIDTH_IN_TILES 8
|
||||
#define MTLVC_MASK_CACHE_HEIGHT_IN_TILES 4
|
||||
|
||||
#define MTLVC_MASK_CACHE_WIDTH_IN_TEXELS \
|
||||
(MTLVC_MASK_CACHE_TILE_WIDTH * MTLVC_MASK_CACHE_WIDTH_IN_TILES)
|
||||
#define MTLVC_MASK_CACHE_HEIGHT_IN_TEXELS \
|
||||
(MTLVC_MASK_CACHE_TILE_HEIGHT * MTLVC_MASK_CACHE_HEIGHT_IN_TILES)
|
||||
|
||||
/*
|
||||
* We reserve one (fully opaque) tile in the upper-right corner for
|
||||
* operations where the mask is null.
|
||||
*/
|
||||
#define MTLVC_MASK_CACHE_MAX_INDEX \
|
||||
((MTLVC_MASK_CACHE_WIDTH_IN_TILES * MTLVC_MASK_CACHE_HEIGHT_IN_TILES) - 1)
|
||||
#define MTLVC_MASK_CACHE_SPECIAL_TILE_X \
|
||||
(MTLVC_MASK_CACHE_WIDTH_IN_TEXELS - MTLVC_MASK_CACHE_TILE_WIDTH)
|
||||
#define MTLVC_MASK_CACHE_SPECIAL_TILE_Y \
|
||||
(MTLVC_MASK_CACHE_HEIGHT_IN_TEXELS - MTLVC_MASK_CACHE_TILE_HEIGHT)
|
||||
|
||||
/**
|
||||
* Exported methods.
|
||||
*/
|
||||
jboolean MTLVertexCache_InitVertexCache(MTLContext *mtlc);
|
||||
void MTLVertexCache_FlushVertexCache();
|
||||
void MTLVertexCache_RestoreColorState(MTLContext *mtlc);
|
||||
|
||||
void MTLVertexCache_EnableMaskCache(MTLContext *mtlc);
|
||||
void MTLVertexCache_DisableMaskCache(MTLContext *mtlc);
|
||||
void MTLVertexCache_AddMaskQuad(MTLContext *mtlc,
|
||||
jint srcx, jint srcy,
|
||||
jint dstx, jint dsty,
|
||||
jint width, jint height,
|
||||
jint maskscan, void *mask);
|
||||
|
||||
void MTLVertexCache_AddGlyphQuad(MTLContext *mtlc,
|
||||
jfloat tx1, jfloat ty1,
|
||||
jfloat tx2, jfloat ty2,
|
||||
jfloat dx1, jfloat dy1,
|
||||
jfloat dx2, jfloat dy2);
|
||||
|
||||
#endif /* MTLVertexCache_h_Included */
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
#ifndef HEADLESS
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "sun_java2d_SunGraphics2D.h"
|
||||
|
||||
#include "MTLPaints.h"
|
||||
#include "MTLVertexCache.h"
|
||||
|
||||
typedef struct _J2DVertex {
|
||||
jfloat tx, ty;
|
||||
jubyte r, g, b, a;
|
||||
jfloat dx, dy;
|
||||
} J2DVertex;
|
||||
|
||||
static J2DVertex *vertexCache = NULL;
|
||||
static jint vertexCacheIndex = 0;
|
||||
|
||||
static jint maskCacheTexID = 0;
|
||||
static jint maskCacheIndex = 0;
|
||||
|
||||
#define MTLVC_ADD_VERTEX(TX, TY, R, G, B, A, DX, DY) \
|
||||
do { \
|
||||
J2DVertex *v = &vertexCache[vertexCacheIndex++]; \
|
||||
v->tx = TX; \
|
||||
v->ty = TY; \
|
||||
v->r = R; \
|
||||
v->g = G; \
|
||||
v->b = B; \
|
||||
v->a = A; \
|
||||
v->dx = DX; \
|
||||
v->dy = DY; \
|
||||
} while (0)
|
||||
|
||||
#define MTLVC_ADD_QUAD(TX1, TY1, TX2, TY2, DX1, DY1, DX2, DY2, R, G, B, A) \
|
||||
do { \
|
||||
MTLVC_ADD_VERTEX(TX1, TY1, R, G, B, A, DX1, DY1); \
|
||||
MTLVC_ADD_VERTEX(TX2, TY1, R, G, B, A, DX2, DY1); \
|
||||
MTLVC_ADD_VERTEX(TX2, TY2, R, G, B, A, DX2, DY2); \
|
||||
MTLVC_ADD_VERTEX(TX1, TY2, R, G, B, A, DX1, DY2); \
|
||||
} while (0)
|
||||
|
||||
jboolean
|
||||
MTLVertexCache_InitVertexCache(MTLContext *mtlc)
|
||||
{
|
||||
//TODO
|
||||
J2dTraceNotImplPrimitive("MTLVertexCache_InitVertexCache");
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_InitVertexCache");
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
MTLVertexCache_FlushVertexCache()
|
||||
{
|
||||
// TODO
|
||||
J2dTraceNotImplPrimitive("MTLVertexCache_FlushVertexCache");
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_FlushVertexCache");
|
||||
vertexCacheIndex = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is somewhat hacky, but necessary for the foreseeable future.
|
||||
* The problem is the way OpenGL handles color values in vertex arrays. When
|
||||
* a vertex in a vertex array contains a color, and then the vertex array
|
||||
* is rendered via glDrawArrays(), the global OpenGL color state is actually
|
||||
* modified each time a vertex is rendered. This means that after all
|
||||
* vertices have been flushed, the global OpenGL color state will be set to
|
||||
* the color of the most recently rendered element in the vertex array.
|
||||
*
|
||||
* The reason this is a problem for us is that we do not want to flush the
|
||||
* vertex array (in the case of mask/glyph operations) or issue a glEnd()
|
||||
* (in the case of non-antialiased primitives) everytime the current color
|
||||
* changes, which would defeat any benefit from batching in the first place.
|
||||
* We handle this in practice by not calling CHECK/RESET_PREVIOUS_OP() when
|
||||
* the simple color state is changing in MTLPaints_SetColor(). This is
|
||||
* problematic for vertex caching because we may end up with the following
|
||||
* situation, for example:
|
||||
* SET_COLOR (orange)
|
||||
* MASK_FILL
|
||||
* MASK_FILL
|
||||
* SET_COLOR (blue; remember, this won't cause a flush)
|
||||
* FILL_RECT (this will cause the vertex array to be flushed)
|
||||
*
|
||||
* In this case, we would actually end up rendering an orange FILL_RECT,
|
||||
* not a blue one as intended, because flushing the vertex cache flush would
|
||||
* override the color state from the most recent SET_COLOR call.
|
||||
*
|
||||
* Long story short, the easiest way to resolve this problem is to call
|
||||
* this method just after disabling the mask/glyph cache, which will ensure
|
||||
* that the appropriate color state is restored.
|
||||
*/
|
||||
void
|
||||
MTLVertexCache_RestoreColorState(MTLContext *mtlc)
|
||||
{
|
||||
// TODO
|
||||
J2dTraceNotImplPrimitive("MTLVertexCache_RestoreColorState");
|
||||
if (mtlc->paintState == sun_java2d_SunGraphics2D_PAINT_ALPHACOLOR) {
|
||||
MTLPaints_SetColor(mtlc, mtlc->pixel);
|
||||
}
|
||||
}
|
||||
|
||||
static jboolean
|
||||
MTLVertexCache_InitMaskCache()
|
||||
{
|
||||
// TODO
|
||||
J2dTraceNotImplPrimitive("MTLVertexCache_InitMaskCache");
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_InitMaskCache");
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
MTLVertexCache_EnableMaskCache(MTLContext *mtlc)
|
||||
{
|
||||
// TODO
|
||||
J2dTraceNotImplPrimitive("MTLVertexCache_EnableMaskCache");
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_EnableMaskCache");
|
||||
}
|
||||
|
||||
void
|
||||
MTLVertexCache_DisableMaskCache(MTLContext *mtlc)
|
||||
{
|
||||
// TODO
|
||||
J2dTraceNotImplPrimitive("MTLVertexCache_DisableMaskCache");
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_DisableMaskCache");
|
||||
maskCacheIndex = 0;
|
||||
}
|
||||
|
||||
void
|
||||
MTLVertexCache_AddMaskQuad(MTLContext *mtlc,
|
||||
jint srcx, jint srcy,
|
||||
jint dstx, jint dsty,
|
||||
jint width, jint height,
|
||||
jint maskscan, void *mask)
|
||||
{
|
||||
// TODO
|
||||
J2dTraceNotImplPrimitive("MTLVertexCache_AddMaskQuad");
|
||||
}
|
||||
|
||||
void
|
||||
MTLVertexCache_AddGlyphQuad(MTLContext *mtlc,
|
||||
jfloat tx1, jfloat ty1, jfloat tx2, jfloat ty2,
|
||||
jfloat dx1, jfloat dy1, jfloat dx2, jfloat dy2)
|
||||
{
|
||||
// TODO
|
||||
J2dTraceNotImplPrimitive("MTLVertexCache_AddGlyphQuad");
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_AddGlyphQuad");
|
||||
}
|
||||
|
||||
#endif /* !HEADLESS */
|
||||
@@ -324,9 +324,13 @@ public class Blit extends GraphicsPrimitive
|
||||
int srcx, int srcy, int dstx, int dsty,
|
||||
int width, int height)
|
||||
{
|
||||
tracePrimitive(target);
|
||||
if ((traceflags & TRACEPTIME) == 0) {
|
||||
tracePrimitive(target);
|
||||
}
|
||||
long time = System.nanoTime();
|
||||
target.Blit(src, dst, comp, clip,
|
||||
srcx, srcy, dstx, dsty, width, height);
|
||||
tracePrimitiveTime(target, System.nanoTime() - time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,9 +209,13 @@ public class BlitBg extends GraphicsPrimitive
|
||||
int srcx, int srcy, int dstx, int dsty,
|
||||
int width, int height)
|
||||
{
|
||||
tracePrimitive(target);
|
||||
if ((traceflags & TRACEPTIME) == 0) {
|
||||
tracePrimitive(target);
|
||||
}
|
||||
long time = System.nanoTime();
|
||||
target.BlitBg(src, dst, comp, clip, bgColor,
|
||||
srcx, srcy, dstx, dsty, width, height);
|
||||
tracePrimitiveTime(target, System.nanoTime() - time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,8 +152,12 @@ public class DrawGlyphListAA extends GraphicsPrimitive {
|
||||
public void DrawGlyphListAA(SunGraphics2D sg2d, SurfaceData dest,
|
||||
GlyphList glyphs)
|
||||
{
|
||||
tracePrimitive(target);
|
||||
if ((traceflags & TRACEPTIME) == 0) {
|
||||
tracePrimitive(target);
|
||||
}
|
||||
long time = System.nanoTime();
|
||||
target.DrawGlyphListAA(sg2d, dest, glyphs);
|
||||
tracePrimitiveTime(target, System.nanoTime() - time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,8 +109,12 @@ public class DrawGlyphListLCD extends GraphicsPrimitive {
|
||||
public void DrawGlyphListLCD(SunGraphics2D sg2d, SurfaceData dest,
|
||||
GlyphList glyphs)
|
||||
{
|
||||
tracePrimitive(target);
|
||||
if ((traceflags & TRACEPTIME) == 0) {
|
||||
tracePrimitive(target);
|
||||
}
|
||||
long time = System.nanoTime();
|
||||
target.DrawGlyphListLCD(sg2d, dest, glyphs);
|
||||
tracePrimitiveTime(target, System.nanoTime() - time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,8 +104,12 @@ public class DrawLine extends GraphicsPrimitive
|
||||
public void DrawLine(SunGraphics2D sg2d, SurfaceData dest,
|
||||
int x1, int y1, int x2, int y2)
|
||||
{
|
||||
tracePrimitive(target);
|
||||
if ((traceflags & TRACEPTIME) == 0) {
|
||||
tracePrimitive(target);
|
||||
}
|
||||
long time = System.nanoTime();
|
||||
target.DrawLine(sg2d, dest, x1, y1, x2, y2);
|
||||
tracePrimitiveTime(target, System.nanoTime() - time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,8 +111,12 @@ public class FillParallelogram extends GraphicsPrimitive
|
||||
double dx1, double dy1,
|
||||
double dx2, double dy2)
|
||||
{
|
||||
tracePrimitive(target);
|
||||
if ((traceflags & TRACEPTIME) == 0) {
|
||||
tracePrimitive(target);
|
||||
}
|
||||
long time = System.nanoTime();
|
||||
target.FillParallelogram(sg2d, dest, x0, y0, dx1, dy1, dx2, dy2);
|
||||
tracePrimitiveTime(target, System.nanoTime() - time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,8 +125,12 @@ public class FillRect extends GraphicsPrimitive
|
||||
public void FillRect(SunGraphics2D sg2d, SurfaceData dest,
|
||||
int x, int y, int w, int h)
|
||||
{
|
||||
tracePrimitive(target);
|
||||
if ((traceflags & TRACEPTIME) == 0) {
|
||||
tracePrimitive(target);
|
||||
}
|
||||
long time = System.nanoTime();
|
||||
target.FillRect(sg2d, dest, x, y, w, h);
|
||||
tracePrimitiveTime(target, System.nanoTime() - time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,8 +112,12 @@ public class FillSpans extends GraphicsPrimitive
|
||||
public void FillSpans(SunGraphics2D sg2d, SurfaceData dest,
|
||||
SpanIterator si)
|
||||
{
|
||||
tracePrimitive(target);
|
||||
if ((traceflags & TRACEPTIME) == 0) {
|
||||
tracePrimitive(target);
|
||||
}
|
||||
long time = System.nanoTime();
|
||||
target.FillSpans(sg2d, dest, si);
|
||||
tracePrimitiveTime(target, System.nanoTime() - time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ import java.lang.reflect.Field;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.Iterator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.io.PrintStream;
|
||||
import java.io.OutputStream;
|
||||
@@ -322,17 +323,28 @@ public abstract class GraphicsPrimitive {
|
||||
|
||||
public static int traceflags;
|
||||
public static String tracefile;
|
||||
public static String pname;
|
||||
public static PrintStream traceout;
|
||||
public static long treshold = 0;
|
||||
public static boolean verbose = false;
|
||||
|
||||
public static final int TRACELOG = 1;
|
||||
public static final int TRACETIMESTAMP = 2;
|
||||
public static final int TRACECOUNTS = 4;
|
||||
public static final int TRACEPTIME = 8;
|
||||
public static final int TRACEPNAME = 16;
|
||||
public static final int TRACEPIMPL = 32;
|
||||
|
||||
static void showTraceUsage() {
|
||||
System.err.println("usage: -Dsun.java2d.trace="+
|
||||
"[log[,timestamp]],[count],[ptime],[pimpl],[name:<substr pattern>],"+
|
||||
"[out:<filename>],[td=<treshold>],[help],[verbose]");
|
||||
}
|
||||
|
||||
static {
|
||||
GetPropertyAction gpa = new GetPropertyAction("sun.java2d.trace");
|
||||
String trace = AccessController.doPrivileged(gpa);
|
||||
if (trace != null) {
|
||||
boolean verbose = false;
|
||||
int traceflags = 0;
|
||||
StringTokenizer st = new StringTokenizer(trace, ",");
|
||||
while (st.hasMoreTokens()) {
|
||||
@@ -343,19 +355,33 @@ public abstract class GraphicsPrimitive {
|
||||
traceflags |= GraphicsPrimitive.TRACELOG;
|
||||
} else if (tok.equalsIgnoreCase("timestamp")) {
|
||||
traceflags |= GraphicsPrimitive.TRACETIMESTAMP;
|
||||
} else if (tok.equalsIgnoreCase("ptime")) {
|
||||
traceflags |=GraphicsPrimitive.TRACEPTIME;
|
||||
} else if (tok.equalsIgnoreCase("pimpl")) {
|
||||
traceflags |=GraphicsPrimitive.TRACEPIMPL;
|
||||
} else if (tok.regionMatches(true, 0, "name:", 0, 5)) {
|
||||
traceflags |=GraphicsPrimitive.TRACEPNAME;
|
||||
pname = tok.substring(6);
|
||||
} else if (tok.equalsIgnoreCase("verbose")) {
|
||||
verbose = true;
|
||||
} else if (tok.regionMatches(true, 0, "out:", 0, 4)) {
|
||||
tracefile = tok.substring(4);
|
||||
} else if (tok.regionMatches(true, 0, "td=", 0, 3)) {
|
||||
try {
|
||||
treshold = Long.parseLong(tok.substring(3));
|
||||
} catch (NumberFormatException e) {
|
||||
showTraceUsage();
|
||||
}
|
||||
} else {
|
||||
if (!tok.equalsIgnoreCase("help")) {
|
||||
System.err.println("unrecognized token: "+tok);
|
||||
}
|
||||
System.err.println("usage: -Dsun.java2d.trace="+
|
||||
"[log[,timestamp]],[count],"+
|
||||
"[out:<filename>],[help],[verbose]");
|
||||
showTraceUsage();
|
||||
}
|
||||
}
|
||||
|
||||
GraphicsPrimitiveMgr.setTraceFlags(traceflags);
|
||||
|
||||
if (verbose) {
|
||||
System.err.print("GraphicsPrimitive logging ");
|
||||
if ((traceflags & GraphicsPrimitive.TRACELOG) != 0) {
|
||||
@@ -416,7 +442,12 @@ public abstract class GraphicsPrimitive {
|
||||
}
|
||||
|
||||
public static class TraceReporter implements Runnable {
|
||||
public static void setShutdownHook() {
|
||||
private static boolean hookEnabled = false;
|
||||
|
||||
public static synchronized void setShutdownHook() {
|
||||
if (hookEnabled) return;
|
||||
hookEnabled = true;
|
||||
|
||||
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
|
||||
TraceReporter t = new TraceReporter();
|
||||
Thread thread = new Thread(
|
||||
@@ -430,33 +461,39 @@ public abstract class GraphicsPrimitive {
|
||||
|
||||
public void run() {
|
||||
PrintStream ps = getTraceOutputFile();
|
||||
Iterator<Map.Entry<Object, int[]>> iterator =
|
||||
traceMap.entrySet().iterator();
|
||||
long total = 0;
|
||||
int numprims = 0;
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<Object, int[]> me = iterator.next();
|
||||
Object prim = me.getKey();
|
||||
int[] count = me.getValue();
|
||||
if (count[0] == 1) {
|
||||
ps.print("1 call to ");
|
||||
} else {
|
||||
ps.print(count[0]+" calls to ");
|
||||
if (traceMap != null) {
|
||||
Iterator<Map.Entry<Object, int[]>> iterator =
|
||||
traceMap.entrySet().iterator();
|
||||
long total = 0;
|
||||
int numprims = 0;
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<Object, int[]> me = iterator.next();
|
||||
Object prim = me.getKey();
|
||||
int[] count = me.getValue();
|
||||
if (count[0] == 1) {
|
||||
ps.print("1 call to ");
|
||||
} else {
|
||||
ps.print(count[0] + " calls to ");
|
||||
}
|
||||
ps.println(prim);
|
||||
numprims++;
|
||||
total += count[0];
|
||||
}
|
||||
if (numprims == 0) {
|
||||
ps.println("No graphics primitives executed");
|
||||
} else if (numprims > 1) {
|
||||
ps.println(total + " total calls to " +
|
||||
numprims + " different primitives");
|
||||
}
|
||||
ps.println(prim);
|
||||
numprims++;
|
||||
total += count[0];
|
||||
}
|
||||
if (numprims == 0) {
|
||||
ps.println("No graphics primitives executed");
|
||||
} else if (numprims > 1) {
|
||||
ps.println(total+" total calls to "+
|
||||
numprims+" different primitives");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static synchronized void tracePrimitive(Object prim) {
|
||||
public synchronized static void tracePrimitive(Object prim) {
|
||||
if ((traceflags & TRACEPNAME) != 0) {
|
||||
if (!prim.toString().contains(pname)) return;
|
||||
}
|
||||
|
||||
if ((traceflags & TRACECOUNTS) != 0) {
|
||||
if (traceMap == null) {
|
||||
traceMap = new HashMap<>();
|
||||
@@ -478,6 +515,40 @@ public abstract class GraphicsPrimitive {
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized static void traceImplPrimitive(Object prim, Object msg) {
|
||||
if ((traceflags & TRACEPNAME) != 0) {
|
||||
if (!prim.toString().contains(pname)) return;
|
||||
}
|
||||
|
||||
if ((traceflags & TRACEPIMPL) != 0) {
|
||||
PrintStream ps = getTraceOutputFile();
|
||||
if ((traceflags & TRACETIMESTAMP) != 0) {
|
||||
ps.print(System.currentTimeMillis());
|
||||
}
|
||||
ps.println(prim + " : " + msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public synchronized static void tracePrimitiveTime(Object prim, long time) {
|
||||
if ((traceflags & TRACEPNAME) != 0) {
|
||||
if (!prim.toString().contains(pname)) return;
|
||||
}
|
||||
if (time > treshold && (traceflags & TRACEPTIME) != 0 && (traceflags & TRACELOG) != 0) {
|
||||
PrintStream ps = getTraceOutputFile();
|
||||
ps.println(prim + " time: " + time);
|
||||
if (verbose) {
|
||||
final StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
|
||||
if (stackTrace.length > 3) {
|
||||
for (int i = 3; i < stackTrace.length; i++) {
|
||||
ps.println(" " + stackTrace[i].toString());
|
||||
}
|
||||
}
|
||||
ps.println();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void setupGeneralBinaryOp(GeneralBinaryOp gbo) {
|
||||
int primID = gbo.getPrimTypeID();
|
||||
String methodSignature = gbo.getSignature();
|
||||
|
||||
@@ -51,6 +51,7 @@ public final class GraphicsPrimitiveMgr {
|
||||
Class<?> Path2D, Class<?> Path2DFloat,
|
||||
Class<?> SHints);
|
||||
private static native void registerNativeLoops();
|
||||
static native void setTraceFlags(int traceflags);
|
||||
|
||||
static {
|
||||
initIDs(GraphicsPrimitive.class,
|
||||
|
||||
@@ -255,10 +255,14 @@ public class MaskBlit extends GraphicsPrimitive
|
||||
int width, int height,
|
||||
byte[] mask, int maskoff, int maskscan)
|
||||
{
|
||||
tracePrimitive(target);
|
||||
if ((traceflags & TRACEPTIME) == 0) {
|
||||
tracePrimitive(target);
|
||||
}
|
||||
long time = System.nanoTime();
|
||||
target.MaskBlit(src, dst, comp, clip,
|
||||
srcx, srcy, dstx, dsty, width, height,
|
||||
mask, maskoff, maskscan);
|
||||
tracePrimitiveTime(target, System.nanoTime() - time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,9 +237,13 @@ public class MaskFill extends GraphicsPrimitive
|
||||
int x, int y, int w, int h,
|
||||
byte[] mask, int maskoff, int maskscan)
|
||||
{
|
||||
tracePrimitive(target);
|
||||
if ((traceflags & TRACEPTIME) == 0) {
|
||||
tracePrimitive(target);
|
||||
}
|
||||
long time = System.nanoTime();
|
||||
target.MaskFill(sg2d, sData, comp, x, y, w, h,
|
||||
mask, maskoff, maskscan);
|
||||
tracePrimitiveTime(target, System.nanoTime() - time);
|
||||
}
|
||||
|
||||
public void FillAAPgram(SunGraphics2D sg2d, SurfaceData sData,
|
||||
@@ -248,9 +252,13 @@ public class MaskFill extends GraphicsPrimitive
|
||||
double dx1, double dy1,
|
||||
double dx2, double dy2)
|
||||
{
|
||||
tracePrimitive(fillPgramTarget);
|
||||
if ((traceflags & TRACEPTIME) == 0) {
|
||||
tracePrimitive(fillPgramTarget);
|
||||
}
|
||||
long time = System.nanoTime();
|
||||
target.FillAAPgram(sg2d, sData, comp,
|
||||
x, y, dx1, dy1, dx2, dy2);
|
||||
tracePrimitiveTime(fillPgramTarget, System.nanoTime() - time);
|
||||
}
|
||||
|
||||
public void DrawAAPgram(SunGraphics2D sg2d, SurfaceData sData,
|
||||
@@ -260,9 +268,13 @@ public class MaskFill extends GraphicsPrimitive
|
||||
double dx2, double dy2,
|
||||
double lw1, double lw2)
|
||||
{
|
||||
tracePrimitive(drawPgramTarget);
|
||||
if ((traceflags & TRACEPTIME) == 0) {
|
||||
tracePrimitive(drawPgramTarget);
|
||||
}
|
||||
long time = System.nanoTime();
|
||||
target.DrawAAPgram(sg2d, sData, comp,
|
||||
x, y, dx1, dy1, dx2, dy2, lw1, lw2);
|
||||
tracePrimitiveTime(drawPgramTarget, System.nanoTime() - time);
|
||||
}
|
||||
|
||||
public boolean canDoParallelograms() {
|
||||
|
||||
@@ -146,10 +146,14 @@ public class ScaledBlit extends GraphicsPrimitive
|
||||
double dx1, double dy1,
|
||||
double dx2, double dy2)
|
||||
{
|
||||
tracePrimitive(target);
|
||||
if ((traceflags & TRACEPTIME) == 0) {
|
||||
tracePrimitive(target);
|
||||
}
|
||||
long time = System.nanoTime();
|
||||
target.Scale(src, dst, comp, clip,
|
||||
sx1, sy1, sx2, sy2,
|
||||
dx1, dy1, dx2, dy2);
|
||||
tracePrimitiveTime(target, System.nanoTime() - time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,11 +129,15 @@ public class TransformHelper extends GraphicsPrimitive
|
||||
int dx1, int dy1, int dx2, int dy2,
|
||||
int[] edges, int dxoff, int dyoff)
|
||||
{
|
||||
tracePrimitive(target);
|
||||
if ((traceflags & TRACEPTIME) == 0) {
|
||||
tracePrimitive(target);
|
||||
}
|
||||
long time = System.nanoTime();
|
||||
target.Transform(output, src, dst, comp, clip, itx, txtype,
|
||||
sx1, sy1, sx2, sy2,
|
||||
dx1, dy1, dx2, dy2,
|
||||
edges, dxoff, dyoff);
|
||||
tracePrimitiveTime(target, System.nanoTime() - time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ public class OGLContext extends BufferedContext {
|
||||
|
||||
private final OGLGraphicsConfig config;
|
||||
|
||||
OGLContext(RenderQueue rq, OGLGraphicsConfig config) {
|
||||
public OGLContext(RenderQueue rq, OGLGraphicsConfig config) {
|
||||
super(rq);
|
||||
this.config = config;
|
||||
}
|
||||
@@ -71,7 +71,7 @@ public class OGLContext extends BufferedContext {
|
||||
* situations where we may not otherwise have a current context (e.g.
|
||||
* when disposing a texture-based surface).
|
||||
*/
|
||||
static void setScratchSurface(long pConfigInfo) {
|
||||
public static void setScratchSurface(long pConfigInfo) {
|
||||
// assert OGLRenderQueue.getInstance().lock.isHeldByCurrentThread();
|
||||
|
||||
// invalidate the current context
|
||||
@@ -92,7 +92,7 @@ public class OGLContext extends BufferedContext {
|
||||
* that affect the current context state (e.g. disposing a context or
|
||||
* surface).
|
||||
*/
|
||||
static void invalidateCurrentContext() {
|
||||
public static void invalidateCurrentContext() {
|
||||
// assert OGLRenderQueue.getInstance().lock.isHeldByCurrentThread();
|
||||
|
||||
// invalidate the current Java-level context so that we
|
||||
@@ -121,7 +121,7 @@ public class OGLContext extends BufferedContext {
|
||||
*
|
||||
* @return an id string for the adapter
|
||||
*/
|
||||
static final native String getOGLIdString();
|
||||
public static final native String getOGLIdString();
|
||||
|
||||
@Override
|
||||
public void saveState() {
|
||||
@@ -155,18 +155,18 @@ public class OGLContext extends BufferedContext {
|
||||
rq.flushNow();
|
||||
}
|
||||
|
||||
static class OGLContextCaps extends ContextCapabilities {
|
||||
public static class OGLContextCaps extends ContextCapabilities {
|
||||
/**
|
||||
* Indicates the presence of the GL_EXT_framebuffer_object extension.
|
||||
* This cap will only be set if the fbobject system property has been
|
||||
* enabled and we are able to create an FBO with depth buffer.
|
||||
*/
|
||||
@Native
|
||||
static final int CAPS_EXT_FBOBJECT =
|
||||
public static final int CAPS_EXT_FBOBJECT =
|
||||
(CAPS_RT_TEXTURE_ALPHA | CAPS_RT_TEXTURE_OPAQUE);
|
||||
/** Indicates that the context is doublebuffered. */
|
||||
@Native
|
||||
static final int CAPS_DOUBLEBUFFERED = (FIRST_PRIVATE_CAP << 0);
|
||||
public static final int CAPS_DOUBLEBUFFERED = (FIRST_PRIVATE_CAP << 0);
|
||||
/**
|
||||
* Indicates the presence of the GL_ARB_fragment_shader extension.
|
||||
* This cap will only be set if the lcdshader system property has been
|
||||
@@ -196,7 +196,7 @@ public class OGLContext extends BufferedContext {
|
||||
static final int CAPS_EXT_TEXBARRIER = (FIRST_PRIVATE_CAP << 5);
|
||||
|
||||
|
||||
OGLContextCaps(int caps, String adapterId) {
|
||||
public OGLContextCaps(int caps, String adapterId) {
|
||||
super(caps, adapterId);
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ import sun.java2d.pipe.hw.AccelGraphicsConfig;
|
||||
* GLXGraphicsConfig and WGLGraphicsConfig, making it easier to invoke these
|
||||
* methods directly from OGLSurfaceData.
|
||||
*/
|
||||
interface OGLGraphicsConfig extends
|
||||
public interface OGLGraphicsConfig extends
|
||||
AccelGraphicsConfig, SurfaceManager.ProxiedGraphicsConfig
|
||||
{
|
||||
OGLContext getContext();
|
||||
|
||||
@@ -64,8 +64,13 @@ class OGLTextRenderer extends BufferedTextPipe {
|
||||
super(ogltr.rq);
|
||||
}
|
||||
protected void drawGlyphList(SunGraphics2D sg2d, GlyphList gl) {
|
||||
GraphicsPrimitive.tracePrimitive("OGLDrawGlyphs");
|
||||
final String prim = "OGLDrawGlyphs" + (gl.isRGBOrder() ? "LCD" : "Gray");
|
||||
if ((GraphicsPrimitive.traceflags & GraphicsPrimitive.TRACEPTIME) == 0) {
|
||||
GraphicsPrimitive.tracePrimitive(prim);
|
||||
}
|
||||
long time = System.nanoTime();
|
||||
super.drawGlyphList(sg2d, gl);
|
||||
GraphicsPrimitive.tracePrimitiveTime(prim, System.nanoTime() - time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,4 +140,8 @@ public abstract class GlyphListPipe implements TextPipe {
|
||||
int aaHint) {
|
||||
drawGlyphList(sg2d, gl);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,11 +27,14 @@
|
||||
#define _Included_Trace
|
||||
|
||||
#include <jni.h>
|
||||
#include "jni_util.h"
|
||||
#include "debug_trace.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
extern JavaVM *jvm;
|
||||
extern jint graphicsPrimitive_traceflags;
|
||||
|
||||
/**
|
||||
* J2dTrace
|
||||
@@ -175,6 +178,59 @@ J2dTraceInit();
|
||||
J2dTraceImpl(level, JNI_TRUE, string, arg1, arg2, arg3, arg4, arg5); \
|
||||
}
|
||||
|
||||
#define J2dTracePrimitive(string) { \
|
||||
if (graphicsPrimitive_traceflags && jvm) { \
|
||||
JNIEnv *env; \
|
||||
jstring jstr; \
|
||||
(*jvm)->AttachCurrentThreadAsDaemon(jvm, &env, NULL); \
|
||||
jstr = (*env)->NewStringUTF(env, string); \
|
||||
JNU_CallStaticMethodByName(env, NULL, "sun/java2d/loops/GraphicsPrimitive", \
|
||||
"tracePrimitive", "(Ljava/lang/Object;)V", jstr); \
|
||||
(*env)->DeleteLocalRef(env, jstr); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define J2dTraceNotImplPrimitive(prim) { \
|
||||
if (graphicsPrimitive_traceflags && jvm) { \
|
||||
char cbuf[255]; \
|
||||
JNIEnv *env; \
|
||||
jstring jprim; \
|
||||
jstring jmsg; \
|
||||
snprintf(cbuf, 255, "[NOT IMPL] at %s:%d", __FILE__, __LINE__); \
|
||||
(*jvm)->AttachCurrentThreadAsDaemon(jvm, &env, NULL); \
|
||||
jprim = (*env)->NewStringUTF(env, prim); \
|
||||
jmsg = (*env)->NewStringUTF(env, cbuf); \
|
||||
JNU_CallStaticMethodByName(env, NULL, \
|
||||
"sun/java2d/loops/GraphicsPrimitive", \
|
||||
"traceImplPrimitive", \
|
||||
"(Ljava/lang/Object;Ljava/lang/Object;)V", \
|
||||
jprim, jmsg); \
|
||||
(*env)->DeleteLocalRef(env, jprim); \
|
||||
(*env)->DeleteLocalRef(env, jmsg); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define J2dTraceImplPrimitive(prim, msg) { \
|
||||
if (graphicsPrimitive_traceflags && jvm) { \
|
||||
char cbuf[255]; \
|
||||
JNIEnv *env; \
|
||||
jstring jprim; \
|
||||
jstring jmsg; \
|
||||
snprintf(cbuf, 255, "%s at %s:%d", msg, __FILE__, __LINE__); \
|
||||
(*jvm)->AttachCurrentThreadAsDaemon(jvm, &env, NULL); \
|
||||
jprim = (*env)->NewStringUTF(env, prim); \
|
||||
jmsg = (*env)->NewStringUTF(env, cbuf); \
|
||||
JNU_CallStaticMethodByName(env, NULL, \
|
||||
"sun/java2d/loops/GraphicsPrimitive", \
|
||||
"traceImplPrimitive", \
|
||||
"(Ljava/lang/Object;Ljava/lang/Object;)V", \
|
||||
jprim, jmsg); \
|
||||
(*env)->DeleteLocalRef(env, jprim); \
|
||||
(*env)->DeleteLocalRef(env, jmsg); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@@ -48,7 +48,6 @@ Java_sun_java2d_loops_FillParallelogram_FillParallelogram
|
||||
CompositeInfo compInfo;
|
||||
jint pixel;
|
||||
jint ix1, iy1, ix2, iy2;
|
||||
|
||||
if ((dy1 == 0 && dx1 == 0) || (dy2 == 0 && dx2 == 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -75,6 +75,7 @@ JNIEXPORT jfieldID path2DWindingRuleID;
|
||||
JNIEXPORT jfieldID path2DFloatCoordsID;
|
||||
JNIEXPORT jfieldID sg2dStrokeHintID;
|
||||
JNIEXPORT jint sunHints_INTVAL_STROKE_PURE;
|
||||
JNIEXPORT jint graphicsPrimitive_traceflags = 0;
|
||||
|
||||
/*
|
||||
* Class: sun_java2d_loops_GraphicsPrimitiveMgr
|
||||
@@ -148,6 +149,13 @@ Java_sun_java2d_loops_GraphicsPrimitiveMgr_initIDs
|
||||
sunHints_INTVAL_STROKE_PURE = (*env)->GetStaticIntField(env, SHints, fid);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_java2d_loops_GraphicsPrimitiveMgr_setTraceFlags
|
||||
(JNIEnv *env, jclass GPMgr, jint traceflags)
|
||||
{
|
||||
graphicsPrimitive_traceflags = traceflags;
|
||||
}
|
||||
|
||||
void GrPrim_RefineBounds(SurfaceDataBounds *bounds, jint transX, jint transY,
|
||||
jfloat *coords, jint maxCoords)
|
||||
{
|
||||
|
||||
@@ -558,6 +558,7 @@ JNIEXPORT extern jfieldID path2DWindingRuleID;
|
||||
JNIEXPORT extern jfieldID path2DFloatCoordsID;
|
||||
JNIEXPORT extern jfieldID sg2dStrokeHintID;
|
||||
JNIEXPORT extern jint sunHints_INTVAL_STROKE_PURE;
|
||||
JNIEXPORT extern jint graphicsPrimitive_traceflags;
|
||||
|
||||
/*
|
||||
* Macros for using jlong variables as 32bits.32bits fractional values
|
||||
|
||||
@@ -191,7 +191,7 @@ typedef AwtObject* PDATA;
|
||||
#define LO_INT(l) ((int)(short)(l))
|
||||
#define HI_INT(l) ((int)(short)(((DWORD)(l) >> 16) & 0xFFFF))
|
||||
|
||||
extern JavaVM *jvm;
|
||||
extern "C" JavaVM *jvm;
|
||||
|
||||
// Platform encoding is Unicode (UTF-16), re-define JNU_ functions
|
||||
// to proper JNI functions.
|
||||
|
||||
599
test/jdk/jbu/perf/metal/MetalPerfTest.java
Normal file
599
test/jdk/jbu/perf/metal/MetalPerfTest.java
Normal file
@@ -0,0 +1,599 @@
|
||||
/*
|
||||
* Copyright 2019 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.
|
||||
*
|
||||
* 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 perf.metal;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.QuadCurve2D;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class MetalPerfTest {
|
||||
private final static int N = 500;
|
||||
private final static float WIDTH = 800;
|
||||
private final static float HEIGHT = 800;
|
||||
private final static float R = 25;
|
||||
private final static int BW = 50;
|
||||
private final static int BH = 50;
|
||||
private final static int COUNT = 300;
|
||||
private final static int DELAY = 10;
|
||||
private final static int RESOLUTION = 5;
|
||||
private final static int COLOR_TOLERANCE = 10;
|
||||
|
||||
|
||||
interface Renderable {
|
||||
void render(Graphics2D g2d);
|
||||
void update();
|
||||
}
|
||||
|
||||
static class Particles {
|
||||
private float[] bx;
|
||||
private float[] by;
|
||||
private float[] vx;
|
||||
private float[] vy;
|
||||
private float r;
|
||||
private int n;
|
||||
|
||||
private float x0;
|
||||
private float y0;
|
||||
private float width;
|
||||
private float height;
|
||||
|
||||
Particles(int n, float r, float x0, float y0, float width, float height) {
|
||||
bx = new float[n];
|
||||
by = new float[n];
|
||||
vx = new float[n];
|
||||
vy = new float[n];
|
||||
this.n = n;
|
||||
this.r = r;
|
||||
this.x0 = x0;
|
||||
this.y0 = y0;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
for (int i = 0; i < n; i++) {
|
||||
bx[i] = (float) (x0 + r + 0.1 + Math.random() * (width - 2 * r - 0.2 - x0));
|
||||
by[i] = (float) (y0 + r + 0.1 + Math.random() * (height - 2 * r - 0.2 - y0));
|
||||
vx[i] = 0.1f * (float) (Math.random() * 2 * r - r);
|
||||
vy[i] = 0.1f * (float) (Math.random() * 2 * r - r);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void render(Graphics2D g2d, ParticleRenderer renderer) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
renderer.render(g2d, i, bx, by, vx, vy);
|
||||
}
|
||||
}
|
||||
|
||||
void update() {
|
||||
for (int i = 0; i < n; i++) {
|
||||
bx[i] += vx[i];
|
||||
if (bx[i] + r > width || bx[i] - r < x0) vx[i] = -vx[i];
|
||||
by[i] += vy[i];
|
||||
if (by[i] + r > height || by[i] - r < y0) vy[i] = -vy[i];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
interface ParticleRenderer {
|
||||
void render(Graphics2D g2d, int id, float[] x, float[] y, float[] vx, float[] vy);
|
||||
|
||||
}
|
||||
|
||||
static class FlatParticleRenderer implements ParticleRenderer {
|
||||
Color[] colors;
|
||||
float r;
|
||||
|
||||
FlatParticleRenderer(int n, float r) {
|
||||
colors = new Color[n];
|
||||
this.r = r;
|
||||
for (int i = 0; i < n; i++) {
|
||||
colors[i] = new Color((float) Math.random(),
|
||||
(float) Math.random(), (float) Math.random());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Graphics2D g2d, int id, float[] x, float[] y, float[] vx, float[] vy) {
|
||||
g2d.setColor(colors[id % colors.length]);
|
||||
g2d.fillOval((int)(x[id] - r), (int)(y[id] - r), (int)(2*r), (int)(2*r));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class FlatOvalRotParticleRenderer extends FlatParticleRenderer {
|
||||
|
||||
|
||||
FlatOvalRotParticleRenderer(int n, float r) {
|
||||
super(n, r);
|
||||
}
|
||||
|
||||
void setPaint(Graphics2D g2d, int id) {
|
||||
g2d.setColor(colors[id % colors.length]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Graphics2D g2d, int id, float[] x, float[] y, float[] vx, float[] vy) {
|
||||
setPaint(g2d, id);
|
||||
if (Math.abs(vx[id] + vy[id]) > 0.001) {
|
||||
AffineTransform t = (AffineTransform) g2d.getTransform().clone();
|
||||
double l = vx[id] / Math.sqrt(vx[id] * vx[id] + vy[id] * vy[id]);
|
||||
if (vy[id] < 0) {
|
||||
l = -l;
|
||||
}
|
||||
g2d.translate(x[id], y[id]);
|
||||
g2d.rotate(Math.acos(l));
|
||||
g2d.fillOval(-(int)r, (int)(-0.5*r), (int) (2 * r), (int)r);
|
||||
g2d.setTransform(t);
|
||||
} else {
|
||||
g2d.fillOval((int)(x[id] - r), (int)(y[id] - 0.5*r),
|
||||
(int) (2 * r), (int) r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class LinGradOvalRotParticleRenderer extends FlatOvalRotParticleRenderer {
|
||||
|
||||
|
||||
LinGradOvalRotParticleRenderer(int n, float r) {
|
||||
super(n, r);
|
||||
}
|
||||
|
||||
@Override
|
||||
void setPaint(Graphics2D g2d, int id) {
|
||||
Point2D start = new Point2D.Double(- r, - 0.5*r);
|
||||
Point2D end = new Point2D.Double( 2 * r, r);
|
||||
float[] dist = {0.0f, 1.0f};
|
||||
Color[] cls = {colors[id %colors.length], Color.WHITE};
|
||||
LinearGradientPaint p =
|
||||
new LinearGradientPaint(start, end, dist, cls);
|
||||
g2d.setPaint(p);
|
||||
}
|
||||
}
|
||||
|
||||
static class FlatBoxParticleRenderer extends FlatParticleRenderer {
|
||||
|
||||
|
||||
FlatBoxParticleRenderer(int n, float r) {
|
||||
super(n, r);
|
||||
}
|
||||
@Override
|
||||
public void render(Graphics2D g2d, int id, float[] x, float[] y, float[] vx, float[] vy) {
|
||||
g2d.setColor(colors[id % colors.length]);
|
||||
g2d.fillRect((int)(x[id] - r), (int)(y[id] - r), (int)(2*r), (int)(2*r));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class FlatBoxRotParticleRenderer extends FlatParticleRenderer {
|
||||
|
||||
|
||||
FlatBoxRotParticleRenderer(int n, float r) {
|
||||
super(n, r);
|
||||
}
|
||||
@Override
|
||||
public void render(Graphics2D g2d, int id, float[] x, float[] y, float[] vx, float[] vy) {
|
||||
g2d.setColor(colors[id % colors.length]);
|
||||
if (Math.abs(vx[id] + vy[id]) > 0.001) {
|
||||
AffineTransform t = (AffineTransform) g2d.getTransform().clone();
|
||||
double l = vx[id] / Math.sqrt(vx[id] * vx[id] + vy[id] * vy[id]);
|
||||
if (vy[id] < 0) {
|
||||
l = -l;
|
||||
}
|
||||
g2d.translate(x[id], y[id]);
|
||||
g2d.rotate(Math.acos(l));
|
||||
g2d.fillRect(-(int)r, -(int)r, (int) (2 * r), (int) (2 * r));
|
||||
g2d.setTransform(t);
|
||||
} else {
|
||||
g2d.fillRect((int)(x[id] - r), (int)(y[id] - r),
|
||||
(int) (2 * r), (int) (2 * r));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class WiredParticleRenderer extends FlatParticleRenderer {
|
||||
|
||||
|
||||
WiredParticleRenderer(int n, float r) {
|
||||
super(n, r);
|
||||
}
|
||||
@Override
|
||||
public void render(Graphics2D g2d, int id, float[] x, float[] y, float[] vx, float[] vy) {
|
||||
g2d.setColor(colors[id % colors.length]);
|
||||
g2d.drawOval((int)(x[id] - r), (int)(y[id] - r), (int)(2*r), (int)(2*r));
|
||||
}
|
||||
|
||||
}
|
||||
static class WiredBoxParticleRenderer extends FlatParticleRenderer {
|
||||
|
||||
WiredBoxParticleRenderer(int n, float r) {
|
||||
super(n, r);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Graphics2D g2d, int id, float[] x, float[] y, float[] vx, float[] vy) {
|
||||
g2d.setColor(colors[id % colors.length]);
|
||||
g2d.drawRect((int)(x[id] - r), (int)(y[id] - r), (int)(2*r), (int)(2*r));
|
||||
}
|
||||
|
||||
}
|
||||
static class SegParticleRenderer extends FlatParticleRenderer {
|
||||
|
||||
SegParticleRenderer(int n, float r) {
|
||||
super(n, r);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Graphics2D g2d, int id, float[] x, float[] y, float[] vx, float[] vy) {
|
||||
double v = Math.sqrt(vx[id]*vx[id]+vy[id]*vy[id]);
|
||||
float nvx = (float) (vx[id]/v);
|
||||
float nvy = (float) (vy[id]/v);
|
||||
g2d.setColor(colors[id % colors.length]);
|
||||
g2d.drawLine((int)(x[id] - r*nvx), (int)(y[id] - r*nvy),
|
||||
(int)(x[id] + 2*r*nvx), (int)(y[id] + 2*r*nvy));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
static class WiredQuadParticleRenderer extends FlatParticleRenderer {
|
||||
|
||||
WiredQuadParticleRenderer(int n, float r) {
|
||||
super(n, r);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Graphics2D g2d, int id, float[] x, float[] y, float[] vx, float[] vy) {
|
||||
if (id > 2 && (id % 3) == 0) {
|
||||
g2d.setColor(colors[id % colors.length]);
|
||||
g2d.draw(new QuadCurve2D.Float(x[id-3], y[id-3], x[id-2], y[id-2], x[id-1], y[id-1]));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static class FlatQuadParticleRenderer extends FlatParticleRenderer {
|
||||
|
||||
FlatQuadParticleRenderer(int n, float r) {
|
||||
super(n, r);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Graphics2D g2d, int id, float[] x, float[] y, float[] vx, float[] vy) {
|
||||
if (id > 2 && (id % 3) == 0) {
|
||||
g2d.setColor(colors[id % colors.length]);
|
||||
g2d.fill(new QuadCurve2D.Float(x[id-3], y[id-3], x[id-2], y[id-2], x[id-1], y[id-1]));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class PerfMeter {
|
||||
|
||||
private int frame = 0;
|
||||
|
||||
private JPanel panel;
|
||||
|
||||
private long time;
|
||||
private double execTime = 0;
|
||||
private Color expColor = Color.RED;
|
||||
AtomicBoolean waiting = new AtomicBoolean(false);
|
||||
|
||||
double exec(final Renderable renderable) throws Exception{
|
||||
final CountDownLatch latch = new CountDownLatch(COUNT);
|
||||
final CountDownLatch latchFrame = new CountDownLatch(1);
|
||||
|
||||
final JFrame f = new JFrame();
|
||||
f.addWindowListener(new WindowAdapter() {
|
||||
@Override
|
||||
public void windowClosed(WindowEvent e) {
|
||||
latchFrame.countDown();
|
||||
}
|
||||
});
|
||||
|
||||
SwingUtilities.invokeAndWait(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
panel = new JPanel()
|
||||
{
|
||||
@Override
|
||||
protected void paintComponent(Graphics g) {
|
||||
|
||||
super.paintComponent(g);
|
||||
time = System.nanoTime();
|
||||
Graphics2D g2d = (Graphics2D) g;
|
||||
renderable.render(g2d);
|
||||
g2d.setColor(expColor);
|
||||
g.fillRect(0, 0, BW, BH);
|
||||
}
|
||||
};
|
||||
|
||||
panel.setPreferredSize(new Dimension((int)(WIDTH + BW), (int)(HEIGHT + BH)));
|
||||
panel.setBackground(Color.BLACK);
|
||||
f.add(panel);
|
||||
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
|
||||
f.pack();
|
||||
f.setVisible(true);
|
||||
}
|
||||
});
|
||||
Robot robot = new Robot();
|
||||
|
||||
Timer timer = new Timer(DELAY, e -> {
|
||||
|
||||
if (waiting.compareAndSet(false, true)) {
|
||||
Color c = robot.getPixelColor(panel.getTopLevelAncestor().getX() + 25,
|
||||
panel.getTopLevelAncestor().getY() + 25);
|
||||
if (isAlmostEqual(c, Color.BLUE)) {
|
||||
expColor = Color.RED;
|
||||
} else {
|
||||
expColor = Color.BLUE;
|
||||
}
|
||||
renderable.update();
|
||||
panel.getParent().repaint();
|
||||
|
||||
} else {
|
||||
while (!isAlmostEqual(
|
||||
robot.getPixelColor(
|
||||
panel.getTopLevelAncestor().getX() + BW / 2,
|
||||
panel.getTopLevelAncestor().getY() + BH / 2),
|
||||
expColor))
|
||||
{
|
||||
try {
|
||||
Thread.sleep(RESOLUTION);
|
||||
} catch (InterruptedException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
time = System.nanoTime() - time;
|
||||
execTime += time;
|
||||
frame++;
|
||||
waiting.set(false);
|
||||
}
|
||||
|
||||
latch.countDown();
|
||||
});
|
||||
timer.start();
|
||||
latch.await();
|
||||
SwingUtilities.invokeAndWait(() -> {
|
||||
timer.stop();
|
||||
f.setVisible(false);
|
||||
f.dispose();
|
||||
});
|
||||
|
||||
latchFrame.await();
|
||||
return 1e9/(execTime / frame);
|
||||
}
|
||||
|
||||
private boolean isAlmostEqual(Color c1, Color c2) {
|
||||
return Math.abs(c1.getRed() - c2.getRed()) < COLOR_TOLERANCE ||
|
||||
Math.abs(c1.getGreen() - c2.getGreen()) < COLOR_TOLERANCE ||
|
||||
Math.abs(c1.getBlue() - c2.getBlue()) < COLOR_TOLERANCE;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static final Particles balls = new Particles(N, R, BW, BH, WIDTH, HEIGHT);
|
||||
private static final ParticleRenderer flatRenderer = new FlatParticleRenderer(N, R);
|
||||
private static final ParticleRenderer flatOvalRotRenderer = new FlatOvalRotParticleRenderer(N, R);
|
||||
private static final ParticleRenderer flatBoxRenderer = new FlatBoxParticleRenderer(N, R);
|
||||
private static final ParticleRenderer flatBoxRotRenderer = new FlatBoxRotParticleRenderer(N, R);
|
||||
private static final ParticleRenderer linGradOvalRotRenderer = new LinGradOvalRotParticleRenderer(N, R);
|
||||
private static final ParticleRenderer wiredRenderer = new WiredParticleRenderer(N, R);
|
||||
private static final ParticleRenderer wiredBoxRenderer = new WiredBoxParticleRenderer(N, R);
|
||||
private static final ParticleRenderer segRenderer = new SegParticleRenderer(N, R);
|
||||
private static final ParticleRenderer flatQuadRenderer = new FlatQuadParticleRenderer(N, R);
|
||||
private static final ParticleRenderer wiredQuadRenderer = new WiredQuadParticleRenderer(N, R);
|
||||
|
||||
|
||||
@Test
|
||||
public void testFlatBubbles() throws Exception {
|
||||
|
||||
double fps = (new PerfMeter()).exec(new Renderable() {
|
||||
@Override
|
||||
public void render(Graphics2D g2d) {
|
||||
balls.render(g2d, flatRenderer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
balls.update();
|
||||
}
|
||||
});
|
||||
|
||||
System.out.println(fps);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFlatBoxBubbles() throws Exception {
|
||||
|
||||
double fps = (new PerfMeter()).exec(new Renderable() {
|
||||
@Override
|
||||
public void render(Graphics2D g2d) {
|
||||
balls.render(g2d, flatBoxRenderer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
balls.update();
|
||||
}
|
||||
});
|
||||
|
||||
System.out.println(fps);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFlatBoxRotBubbles() throws Exception {
|
||||
|
||||
double fps = (new PerfMeter()).exec(new Renderable() {
|
||||
@Override
|
||||
public void render(Graphics2D g2d) {
|
||||
balls.render(g2d, flatBoxRotRenderer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
balls.update();
|
||||
}
|
||||
});
|
||||
|
||||
System.out.println(fps);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFlatOvalRotBubbles() throws Exception {
|
||||
|
||||
double fps = (new PerfMeter()).exec(new Renderable() {
|
||||
@Override
|
||||
public void render(Graphics2D g2d) {
|
||||
balls.render(g2d, flatOvalRotRenderer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
balls.update();
|
||||
}
|
||||
});
|
||||
|
||||
System.out.println(fps);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLinGradOvalRotBubbles() throws Exception {
|
||||
|
||||
double fps = (new PerfMeter()).exec(new Renderable() {
|
||||
@Override
|
||||
public void render(Graphics2D g2d) {
|
||||
balls.render(g2d, linGradOvalRotRenderer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
balls.update();
|
||||
}
|
||||
});
|
||||
|
||||
System.out.println(fps);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testWiredBubbles() throws Exception {
|
||||
|
||||
double fps = (new PerfMeter()).exec(new Renderable() {
|
||||
@Override
|
||||
public void render(Graphics2D g2d) {
|
||||
balls.render(g2d, wiredRenderer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
balls.update();
|
||||
}
|
||||
});
|
||||
|
||||
System.out.println(fps);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWiredBoxBubbles() throws Exception {
|
||||
|
||||
double fps = (new PerfMeter()).exec(new Renderable() {
|
||||
@Override
|
||||
public void render(Graphics2D g2d) {
|
||||
balls.render(g2d, wiredBoxRenderer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
balls.update();
|
||||
}
|
||||
});
|
||||
|
||||
System.out.println(fps);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLines() throws Exception {
|
||||
|
||||
double fps = (new PerfMeter()).exec(new Renderable() {
|
||||
@Override
|
||||
public void render(Graphics2D g2d) {
|
||||
balls.render(g2d, segRenderer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
balls.update();
|
||||
}
|
||||
});
|
||||
|
||||
System.out.println(fps);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFlatQuad() throws Exception {
|
||||
|
||||
double fps = (new PerfMeter()).exec(new Renderable() {
|
||||
@Override
|
||||
public void render(Graphics2D g2d) {
|
||||
balls.render(g2d, flatQuadRenderer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
balls.update();
|
||||
}
|
||||
});
|
||||
|
||||
System.out.println(fps);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWiredQuad() throws Exception {
|
||||
|
||||
double fps = (new PerfMeter()).exec(new Renderable() {
|
||||
@Override
|
||||
public void render(Graphics2D g2d) {
|
||||
balls.render(g2d, wiredQuadRenderer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
balls.update();
|
||||
}
|
||||
});
|
||||
|
||||
System.out.println(fps);
|
||||
}
|
||||
|
||||
}
|
||||
78
test/jdk/jbu/quality/metal/MetalRenderTest.java
Normal file
78
test/jdk/jbu/quality/metal/MetalRenderTest.java
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
package quality.metal;
|
||||
|
||||
import org.junit.Test;
|
||||
import quality.util.RenderUtil;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
public class MetalRenderTest {
|
||||
|
||||
@Test
|
||||
public void testMetal() throws Exception {
|
||||
BufferedImage bi = RenderUtil.capture(120, 120,
|
||||
graphics2D -> {
|
||||
graphics2D.setColor(Color.GREEN);
|
||||
graphics2D.fillRect(10, 10, 50, 50);
|
||||
graphics2D.setColor(Color.RED);
|
||||
graphics2D.fillOval(30, 30, 150, 150);
|
||||
|
||||
});
|
||||
RenderUtil.checkImage(bi, "metal", "geom.png");
|
||||
}
|
||||
@Test
|
||||
public void testMetal1() throws Exception {
|
||||
JFrame[] f = new JFrame[1];
|
||||
SwingUtilities.invokeAndWait(() -> {
|
||||
f[0] = new JFrame();
|
||||
|
||||
f[0].setSize(300, 300);
|
||||
// for frame border effects,
|
||||
// e.g. rounded frame
|
||||
f[0].setVisible(true);
|
||||
});
|
||||
|
||||
Thread.sleep(4000);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMetal2() throws Exception {
|
||||
Frame[] f = new Frame[1];
|
||||
SwingUtilities.invokeAndWait(() -> {
|
||||
f[0] = new Frame();
|
||||
|
||||
f[0].setSize(300, 300);
|
||||
// for frame border effects,
|
||||
// e.g. rounded frame
|
||||
f[0].setVisible(true);
|
||||
});
|
||||
|
||||
Thread.sleep(4000);
|
||||
}
|
||||
}
|
||||
167
test/jdk/jbu/quality/util/RenderUtil.java
Normal file
167
test/jdk/jbu/quality/util/RenderUtil.java
Normal file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
package quality.util;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.Raster;
|
||||
import java.io.File;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class RenderUtil {
|
||||
final static int TOLERANCE = 1;
|
||||
|
||||
public static BufferedImage capture(int width, int height, Consumer<Graphics2D> painter)
|
||||
throws Exception
|
||||
{
|
||||
JFrame[] f = new JFrame[1];
|
||||
Point[] p = new Point[1];
|
||||
double[] scale = new double[2];
|
||||
SwingUtilities.invokeAndWait(() -> {
|
||||
f[0] = new JFrame();
|
||||
|
||||
JComponent c = new MyComponent(painter);
|
||||
|
||||
f[0].add(c);
|
||||
c.setSize(width + 10, height + 10);
|
||||
f[0].setSize(width + 100, height + 100); // giving some space
|
||||
// for frame border effects,
|
||||
// e.g. rounded frame
|
||||
c.setLocation(50, 50);
|
||||
f[0].setVisible(true);
|
||||
p[0]= c.getLocationOnScreen();
|
||||
scale[0] = f[0].getGraphicsConfiguration().getDefaultTransform().getScaleX();
|
||||
scale[1] = f[0].getGraphicsConfiguration().getDefaultTransform().getScaleY();
|
||||
});
|
||||
|
||||
Rectangle screenRect;
|
||||
Robot r = new Robot();
|
||||
while (!Color.black.equals(r.getPixelColor(p[0].x+1, p[0].y))) {
|
||||
Thread.sleep(100);
|
||||
}
|
||||
screenRect = new Rectangle(
|
||||
p[0].x + 5,
|
||||
p[0].y + 5,
|
||||
(int)((width - 20) * scale[0]), (int)((height - 30) * scale[1]));
|
||||
|
||||
BufferedImage result = r.createScreenCapture(screenRect);
|
||||
SwingUtilities.invokeAndWait(f[0]::dispose);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static class MyComponent extends JComponent {
|
||||
private final Consumer<Graphics2D> painter;
|
||||
|
||||
private MyComponent(Consumer<Graphics2D> painter) {
|
||||
this.painter = painter;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void paintComponent(Graphics g) {
|
||||
Shape savedClip = g.getClip();
|
||||
g.translate(5, 5);
|
||||
painter.accept((Graphics2D)g);
|
||||
g.translate(-5, -5);
|
||||
g.setClip(savedClip);
|
||||
g.setColor(Color.black);
|
||||
g.fillRect(0, 0, getWidth() + 10, 5);
|
||||
g.fillRect(0, getHeight()-5, getWidth() + 10, 5);
|
||||
g.fillRect(getWidth() - 10, -10, getWidth() + 5, getHeight() + 5);
|
||||
g.fillRect(-5, -10, 10, getHeight() + 5);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("SameParameterValue")
|
||||
public static void checkImage(BufferedImage image, String path, String gfName) throws Exception {
|
||||
|
||||
String[] testDataVariant = {
|
||||
"osx_hardware_rendering", "osx_software_rendering",
|
||||
"osx_sierra_rendering", "osx_lowres_rendering",
|
||||
"linux_rendering", "windows_rendering"};
|
||||
|
||||
String testDataStr = System.getProperty("testdata");
|
||||
assertNotNull("testdata property is not set", testDataStr);
|
||||
|
||||
File testData = new File(testDataStr, "quality" + File.separator + path);
|
||||
assertTrue("Test data dir does not exist", testData.exists());
|
||||
|
||||
if (System.getProperty("gentestdata") == null) {
|
||||
boolean failed = true;
|
||||
StringBuilder failureReason = new StringBuilder();
|
||||
for (String variant : testDataVariant) {
|
||||
File goldenFile = new File(testData, variant + File.separator +
|
||||
gfName);
|
||||
if (!goldenFile.exists()) continue;
|
||||
|
||||
BufferedImage goldenImage = ImageIO.read(goldenFile);
|
||||
failed = true;
|
||||
if (image.getWidth() != goldenImage.getWidth() ||
|
||||
image.getHeight() != image.getHeight())
|
||||
{
|
||||
failureReason.append(variant).append(" : Golden image and result have different sizes\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
Raster gRaster = goldenImage.getData();
|
||||
Raster rRaster = image.getData();
|
||||
int[] gArr = new int[3];
|
||||
int[] rArr = new int[3];
|
||||
failed = false;
|
||||
scan:
|
||||
for (int i = 0; i < gRaster.getWidth(); i++) {
|
||||
for (int j = 0; j < gRaster.getHeight(); j++) {
|
||||
gRaster.getPixel(i, j, gArr);
|
||||
rRaster.getPixel(i, j, rArr);
|
||||
assertTrue(gArr.length == rArr.length);
|
||||
for (int k = 0; k < gArr.length; k++) {
|
||||
int diff = Math.abs(gArr[k] - rArr[k]);
|
||||
if (diff > TOLERANCE) {
|
||||
failureReason.append(variant).append(" : Different pixels found (").
|
||||
append("c[").append(k).append("]=").append(diff).
|
||||
append(") at (").append(i).append(",").append(j).append(")");
|
||||
failed = true;
|
||||
break scan;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!failed) break;
|
||||
}
|
||||
|
||||
if (failed) throw new RuntimeException(failureReason.toString());
|
||||
}
|
||||
else {
|
||||
ImageIO.write(image, "png", new File(testData, gfName));
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
test/jdk/jbu/testdata/quality/metal/osx_hardware_rendering/geom.png
vendored
Normal file
BIN
test/jdk/jbu/testdata/quality/metal/osx_hardware_rendering/geom.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
Reference in New Issue
Block a user