mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-13 21:09:41 +01:00
Compare commits
95 Commits
jdk-21+11
...
lanai-sync
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0de241433d | ||
|
|
fd95090fa2 | ||
|
|
9cb40a9bc7 | ||
|
|
97c7a63ab6 | ||
|
|
623aa48c4f | ||
|
|
83bbb3941e | ||
|
|
cae4b9cc37 | ||
|
|
9226e84501 | ||
|
|
3da068b282 | ||
|
|
45fea40dbd | ||
|
|
e5d516d182 | ||
|
|
db88ce172a | ||
|
|
4a9a1708b3 | ||
|
|
43bbd51b72 | ||
|
|
c02799eede | ||
|
|
6ff6db02e7 | ||
|
|
032aeb34e6 | ||
|
|
8b636c6a87 | ||
|
|
26d9a0794c | ||
|
|
7744fb099e | ||
|
|
f66a1f1263 | ||
|
|
bc73e009cc | ||
|
|
ff5966de7f | ||
|
|
6ab1ed5817 | ||
|
|
075e1321e3 | ||
|
|
6a57e1fd9c | ||
|
|
2e6bdc171a | ||
|
|
72cac62f89 | ||
|
|
98743762dd | ||
|
|
f0445c24e8 | ||
|
|
d0b2ad3e82 | ||
|
|
32a1a537f0 | ||
|
|
5199fb702d | ||
|
|
3bd02981db | ||
|
|
8a1132d3a2 | ||
|
|
3174bd2c75 | ||
|
|
6e24ac5e09 | ||
|
|
6d8ae023f2 | ||
|
|
c8002d297a | ||
|
|
3b48643a82 | ||
|
|
07ac868b77 | ||
|
|
a2d1099854 | ||
|
|
96a52e96de | ||
|
|
57e1ab737d | ||
|
|
7bc2660967 | ||
|
|
c4ef423d8e | ||
|
|
269e7e98e6 | ||
|
|
136f957e05 | ||
|
|
364be79d47 | ||
|
|
2ad73d2e67 | ||
|
|
a941e59035 | ||
|
|
c4baadb3c9 | ||
|
|
e2d1e4c804 | ||
|
|
dee4009a97 | ||
|
|
e682c5129a | ||
|
|
cdcb094b65 | ||
|
|
537653bd49 | ||
|
|
4fd7c3c449 | ||
|
|
2ec02181fa | ||
|
|
14e6b1244c | ||
|
|
24bff4e701 | ||
|
|
18b550e872 | ||
|
|
fab846163c | ||
|
|
03aa3101a1 | ||
|
|
c8b91c2d3f | ||
|
|
5b3c412357 | ||
|
|
95b69fe529 | ||
|
|
535fff0dac | ||
|
|
bbfac12c68 | ||
|
|
1768149951 | ||
|
|
49ca894f15 | ||
|
|
0f76adc28d | ||
|
|
cfc96d96f7 | ||
|
|
4921d927e0 | ||
|
|
61aeca21c1 | ||
|
|
fda678bef9 | ||
|
|
aba2c30d1e | ||
|
|
3ecd356574 | ||
|
|
762853fe8f | ||
|
|
f879fa4e34 | ||
|
|
6c8022b1ee | ||
|
|
d691007acc | ||
|
|
9f250e53c8 | ||
|
|
7cba2b956a | ||
|
|
c4ee724176 | ||
|
|
393e924d2d | ||
|
|
fcba1675a7 | ||
|
|
493e7d102a | ||
|
|
54f1e4ec23 | ||
|
|
a59e9ab2ac | ||
|
|
6bd87cb96f | ||
|
|
7a448bc74d | ||
|
|
b5cc29da48 | ||
|
|
d98d18b297 | ||
|
|
1441538b23 |
38
.jcheck/conf
38
.jcheck/conf
@@ -1,2 +1,36 @@
|
|||||||
project=jdk
|
;
|
||||||
bugids=dup
|
; Copyright (c) 2020, 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.
|
||||||
|
;
|
||||||
|
; 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.
|
||||||
|
;
|
||||||
|
|
||||||
|
[general]
|
||||||
|
project=lanai
|
||||||
|
jbs=JDK
|
||||||
|
|
||||||
|
[checks]
|
||||||
|
error=author,whitespace,executable
|
||||||
|
|
||||||
|
[census]
|
||||||
|
version=0
|
||||||
|
domain=openjdk.org
|
||||||
|
|
||||||
|
[checks "whitespace"]
|
||||||
|
files=.*\.java$|.*\.c$|.*\.h$|.*\.cpp$|.*\.hpp$
|
||||||
|
|||||||
@@ -565,6 +565,8 @@ CXXFILT:=@CXXFILT@
|
|||||||
|
|
||||||
LIPO:=@LIPO@
|
LIPO:=@LIPO@
|
||||||
INSTALL_NAME_TOOL:=@INSTALL_NAME_TOOL@
|
INSTALL_NAME_TOOL:=@INSTALL_NAME_TOOL@
|
||||||
|
METAL := @METAL@
|
||||||
|
METALLIB := @METALLIB@
|
||||||
|
|
||||||
# Options to linker to specify a mapfile.
|
# Options to linker to specify a mapfile.
|
||||||
# (Note absence of := assignment, because we do not want to evaluate the macro body here)
|
# (Note absence of := assignment, because we do not want to evaluate the macro body here)
|
||||||
|
|||||||
@@ -807,6 +807,32 @@ AC_DEFUN_ONCE([TOOLCHAIN_DETECT_TOOLCHAIN_EXTRA],
|
|||||||
UTIL_FIXUP_EXECUTABLE(OTOOL)
|
UTIL_FIXUP_EXECUTABLE(OTOOL)
|
||||||
UTIL_REQUIRE_PROGS(INSTALL_NAME_TOOL, install_name_tool)
|
UTIL_REQUIRE_PROGS(INSTALL_NAME_TOOL, install_name_tool)
|
||||||
UTIL_FIXUP_EXECUTABLE(INSTALL_NAME_TOOL)
|
UTIL_FIXUP_EXECUTABLE(INSTALL_NAME_TOOL)
|
||||||
|
|
||||||
|
UTIL_PATH_PROGS(METAL, metal)
|
||||||
|
if test "x$METAL" = x; then
|
||||||
|
AC_MSG_CHECKING([if metal can be run using xcrun])
|
||||||
|
METAL="xcrun -sdk macosx metal"
|
||||||
|
test_metal=`$METAL --version 2>&1`
|
||||||
|
if test $? -ne 0; then
|
||||||
|
AC_MSG_RESULT([no])
|
||||||
|
AC_MSG_ERROR([XCode tool 'metal' neither found in path nor with xcrun])
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT([yes, will be using '$METAL'])
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
UTIL_PATH_PROGS(METALLIB, metallib)
|
||||||
|
if test "x$METALLIB" = x; then
|
||||||
|
AC_MSG_CHECKING([if metallib can be run using xcrun])
|
||||||
|
METALLIB="xcrun -sdk macosx metallib"
|
||||||
|
test_metallib=`$METALLIB --version 2>&1`
|
||||||
|
if test $? -ne 0; then
|
||||||
|
AC_MSG_RESULT([no])
|
||||||
|
AC_MSG_ERROR([XCode tool 'metallib' neither found in path nor with xcrun])
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT([yes, will be using '$METALLIB'])
|
||||||
|
fi
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
|
if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
|
||||||
|
|||||||
@@ -245,6 +245,7 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBAWT, \
|
|||||||
LIBS_macosx := -lmlib_image \
|
LIBS_macosx := -lmlib_image \
|
||||||
-framework Cocoa \
|
-framework Cocoa \
|
||||||
-framework OpenGL \
|
-framework OpenGL \
|
||||||
|
-framework Metal \
|
||||||
-framework JavaNativeFoundation \
|
-framework JavaNativeFoundation \
|
||||||
-framework JavaRuntimeSupport \
|
-framework JavaRuntimeSupport \
|
||||||
-framework ApplicationServices \
|
-framework ApplicationServices \
|
||||||
@@ -821,6 +822,7 @@ ifeq ($(ENABLE_HEADLESS_ONLY), false)
|
|||||||
-framework Foundation \
|
-framework Foundation \
|
||||||
-framework Security \
|
-framework Security \
|
||||||
-framework Cocoa \
|
-framework Cocoa \
|
||||||
|
-framework Metal \
|
||||||
-framework JavaNativeFoundation
|
-framework JavaNativeFoundation
|
||||||
else ifeq ($(call isTargetOs, windows), true)
|
else ifeq ($(call isTargetOs, windows), true)
|
||||||
LIBSPLASHSCREEN_LIBS += kernel32.lib user32.lib gdi32.lib delayimp.lib $(WIN_JAVA_LIB) jvm.lib
|
LIBSPLASHSCREEN_LIBS += kernel32.lib user32.lib gdi32.lib delayimp.lib $(WIN_JAVA_LIB) jvm.lib
|
||||||
@@ -882,6 +884,7 @@ ifeq ($(call isTargetOs, macosx), true)
|
|||||||
libawt_lwawt/awt \
|
libawt_lwawt/awt \
|
||||||
libawt_lwawt/font \
|
libawt_lwawt/font \
|
||||||
libawt_lwawt/java2d/opengl \
|
libawt_lwawt/java2d/opengl \
|
||||||
|
libawt_lwawt/java2d/metal \
|
||||||
include \
|
include \
|
||||||
common/awt/debug \
|
common/awt/debug \
|
||||||
common/java2d/opengl \
|
common/java2d/opengl \
|
||||||
@@ -917,6 +920,7 @@ ifeq ($(call isTargetOs, macosx), true)
|
|||||||
-framework AudioToolbox \
|
-framework AudioToolbox \
|
||||||
-framework Carbon \
|
-framework Carbon \
|
||||||
-framework Cocoa \
|
-framework Cocoa \
|
||||||
|
-framework Metal \
|
||||||
-framework Security \
|
-framework Security \
|
||||||
-framework ExceptionHandling \
|
-framework ExceptionHandling \
|
||||||
-framework JavaNativeFoundation \
|
-framework JavaNativeFoundation \
|
||||||
@@ -940,6 +944,28 @@ endif
|
|||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
ifeq ($(call isTargetOs, macosx), true)
|
ifeq ($(call isTargetOs, macosx), true)
|
||||||
|
SHADERS_SRC := $(TOPDIR)/src/java.desktop/macosx/native/libawt_lwawt/awt/shaders.metal
|
||||||
|
SHADERS_SUPPORT_DIR := $(SUPPORT_OUTPUTDIR)/native/java.desktop/libosxui
|
||||||
|
SHADERS_AIR := $(SHADERS_SUPPORT_DIR)/shaders.air
|
||||||
|
SHADERS_LIB := $(INSTALL_LIBRARIES_HERE)/shaders.metallib
|
||||||
|
|
||||||
|
$(eval $(call SetupExecute, metal_shaders, \
|
||||||
|
INFO := Running metal on $(notdir $(SHADERS_SRC)) (for libosxui.dylib), \
|
||||||
|
DEPS := $(SHADERS_SRC), \
|
||||||
|
OUTPUT_FILE := $(SHADERS_AIR), \
|
||||||
|
SUPPORT_DIR := $(SHADERS_SUPPORT_DIR), \
|
||||||
|
COMMAND := $(METAL) -c -o $(SHADERS_AIR) $(SHADERS_SRC), \
|
||||||
|
))
|
||||||
|
|
||||||
|
$(eval $(call SetupExecute, metallib_shaders, \
|
||||||
|
INFO := Running metallib on $(notdir $(SHADERS_AIR)) (for libosxui.dylib), \
|
||||||
|
DEPS := $(SHADERS_AIR), \
|
||||||
|
OUTPUT_FILE := $(SHADERS_LIB), \
|
||||||
|
SUPPORT_DIR := $(SHADERS_SUPPORT_DIR), \
|
||||||
|
COMMAND := $(METALLIB) -o $(SHADERS_LIB) $(SHADERS_AIR), \
|
||||||
|
))
|
||||||
|
|
||||||
|
TARGETS += $(SHADERS_LIB)
|
||||||
|
|
||||||
$(eval $(call SetupJdkLibrary, BUILD_LIBOSXUI, \
|
$(eval $(call SetupJdkLibrary, BUILD_LIBOSXUI, \
|
||||||
NAME := osxui, \
|
NAME := osxui, \
|
||||||
@@ -955,6 +981,7 @@ ifeq ($(call isTargetOs, macosx), true)
|
|||||||
-L$(INSTALL_LIBRARIES_HERE), \
|
-L$(INSTALL_LIBRARIES_HERE), \
|
||||||
LIBS := -lawt -losxapp -lawt_lwawt \
|
LIBS := -lawt -losxapp -lawt_lwawt \
|
||||||
-framework Cocoa \
|
-framework Cocoa \
|
||||||
|
-framework Metal \
|
||||||
-framework Carbon \
|
-framework Carbon \
|
||||||
-framework ApplicationServices \
|
-framework ApplicationServices \
|
||||||
-framework JavaNativeFoundation \
|
-framework JavaNativeFoundation \
|
||||||
@@ -963,6 +990,7 @@ ifeq ($(call isTargetOs, macosx), true)
|
|||||||
))
|
))
|
||||||
|
|
||||||
TARGETS += $(BUILD_LIBOSXUI)
|
TARGETS += $(BUILD_LIBOSXUI)
|
||||||
|
$(BUILD_LIBOSXUI): $(SHADERS_LIB)
|
||||||
|
|
||||||
$(BUILD_LIBOSXUI): $(BUILD_LIBAWT)
|
$(BUILD_LIBOSXUI): $(BUILD_LIBAWT)
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
include LibCommon.gmk
|
include LibCommon.gmk
|
||||||
|
include Execute.gmk
|
||||||
|
|
||||||
# Hook to include the corresponding custom file, if present.
|
# Hook to include the corresponding custom file, if present.
|
||||||
$(eval $(call IncludeCustomExtension, lib/Lib-java.desktop.gmk))
|
$(eval $(call IncludeCustomExtension, lib/Lib-java.desktop.gmk))
|
||||||
|
|||||||
86
src/demo/share/java2d/RenderPerfTest/Makefile
Normal file
86
src/demo/share/java2d/RenderPerfTest/Makefile
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions
|
||||||
|
# are met:
|
||||||
|
#
|
||||||
|
# - Redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer.
|
||||||
|
#
|
||||||
|
# - Redistributions in binary form must reproduce the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer in the
|
||||||
|
# documentation and/or other materials provided with the distribution.
|
||||||
|
#
|
||||||
|
# - Neither the name of Oracle nor the names of its
|
||||||
|
# contributors may be used to endorse or promote products derived
|
||||||
|
# from this software without specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||||
|
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#
|
||||||
|
|
||||||
|
SOURCEPATH=src
|
||||||
|
CLASSES=build
|
||||||
|
DIST=dist
|
||||||
|
RESOURCES=resources
|
||||||
|
|
||||||
|
RENDERPERF_CLASSES = $(CLASSES)/renderperf/RenderPerfTest.class
|
||||||
|
RENDERPERFLCD_CLASSES = $(CLASSES)/renderperf/RenderPerfLCDTest.class
|
||||||
|
RENDERPERF_SOURCES = $(SOURCEPATH)/renderperf/RenderPerfTest.java
|
||||||
|
RENDERPERFLCD_SOURCES = $(SOURCEPATH)/renderperf/RenderPerfLCDTest.java
|
||||||
|
|
||||||
|
RENDERPERF_RESOURCES = $(CLASSES)/renderperf/images/duke.png
|
||||||
|
|
||||||
|
all: mkdirs $(DIST)/RenderPerfTest.jar $(DIST)/RenderPerfLCDTest.jar
|
||||||
|
|
||||||
|
run: mkdirs $(DIST)/RenderPerfTest.jar
|
||||||
|
java -jar $(DIST)/RenderPerfTest.jar
|
||||||
|
|
||||||
|
$(DIST)/RenderPerfTest.jar: \
|
||||||
|
$(RENDERPERF_CLASSES) $(RENDERPERF_RESOURCES) \
|
||||||
|
$(CLASSES)/renderperf.manifest
|
||||||
|
jar cvmf $(CLASSES)/renderperf.manifest $(DIST)/RenderPerfTest.jar -C $(CLASSES) .
|
||||||
|
|
||||||
|
$(DIST)/RenderPerfLCDTest.jar: \
|
||||||
|
$(RENDERPERFLCD_CLASSES) $(RENDERPERFLCD_RESOURCES) \
|
||||||
|
$(CLASSES)/renderperflcd.manifest
|
||||||
|
jar cvmf $(CLASSES)/renderperflcd.manifest $(DIST)/RenderPerfLCDTest.jar -C $(CLASSES) .
|
||||||
|
|
||||||
|
$(CLASSES)/renderperf/images/%: $(RESOURCES)/renderperf/images/%
|
||||||
|
cp -r $< $@
|
||||||
|
|
||||||
|
|
||||||
|
$(CLASSES)/renderperf.manifest:
|
||||||
|
echo "Main-Class: renderperf.RenderPerfTest" > $@
|
||||||
|
|
||||||
|
$(CLASSES)/renderperflcd.manifest:
|
||||||
|
echo "Main-Class: renderperf.RenderPerfLCDTest" > $@
|
||||||
|
|
||||||
|
$(DIST):
|
||||||
|
mkdir $(DIST)
|
||||||
|
|
||||||
|
$(CLASSES):
|
||||||
|
mkdir $(CLASSES)
|
||||||
|
mkdir -p $(CLASSES)/renderperf/images
|
||||||
|
|
||||||
|
mkdirs: $(DIST) $(CLASSES)
|
||||||
|
|
||||||
|
$(RENDERPERF_CLASSES): $(RENDERPERF_SOURCES)
|
||||||
|
javac -g:none -d $(CLASSES) -sourcepath $(SOURCEPATH) $<
|
||||||
|
|
||||||
|
$(RENDERPERFLCD_CLASSES): $(RENDERPERFLCD_SOURCES)
|
||||||
|
javac -g:none -d $(CLASSES) -sourcepath $(SOURCEPATH) $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(CLASSES)
|
||||||
|
rm -rf $(DIST)
|
||||||
34
src/demo/share/java2d/RenderPerfTest/README
Normal file
34
src/demo/share/java2d/RenderPerfTest/README
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
-----------------------------------------------------------------------
|
||||||
|
Introduction
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
RenderPerfTest is a set of on-screen rendering microbenchmarks to
|
||||||
|
analyze the performance of Java2D graphical primitives rendering
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
How To Compile
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
#> cd RenderPerfTest
|
||||||
|
|
||||||
|
The benchmark can be compiled by using either ant:
|
||||||
|
|
||||||
|
#> ant
|
||||||
|
|
||||||
|
or gnumake (assuming there's 'javac' in the path):
|
||||||
|
|
||||||
|
#> gnumake
|
||||||
|
|
||||||
|
The jar files will be generated into RenderPerfTest/dist directory.
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
How To Run RenderPerfTest
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
Run all tests
|
||||||
|
#> ant run
|
||||||
|
or
|
||||||
|
#> java -jar dist/RenderPerfTest.jar
|
||||||
|
|
||||||
|
Run particular test cases
|
||||||
|
|
||||||
|
#> java -jar dist/RenderPerfTest.jar testWhiteTextBubblesGray ...
|
||||||
94
src/demo/share/java2d/RenderPerfTest/build.xml
Normal file
94
src/demo/share/java2d/RenderPerfTest/build.xml
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
<!--
|
||||||
|
Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
- Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
- Neither the name of Oracle nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||||
|
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<project name="RenderPerfTest" default="dist" basedir=".">
|
||||||
|
<description>
|
||||||
|
simple example build file
|
||||||
|
</description>
|
||||||
|
<!-- set global properties for this build -->
|
||||||
|
<property name="src" location="src"/>
|
||||||
|
<property name="build" location="build"/>
|
||||||
|
<property name="dist" location="dist"/>
|
||||||
|
<property name="resources" location="resources"/>
|
||||||
|
|
||||||
|
<target name="init">
|
||||||
|
<!-- Create the time stamp -->
|
||||||
|
<tstamp/>
|
||||||
|
<!-- Create the build directory structure used by compile -->
|
||||||
|
<mkdir dir="${build}"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="compile" depends="init"
|
||||||
|
description="compile the source " >
|
||||||
|
<!-- Compile the java code from ${src} into ${build} -->
|
||||||
|
<javac includeantruntime="false" debug="off" srcdir="${src}" destdir="${build}"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="run" depends="dist"
|
||||||
|
description="run RenderPerfTest" >
|
||||||
|
<java jar="${dist}/RenderPerfTest.jar"
|
||||||
|
fork="true"
|
||||||
|
>
|
||||||
|
</java>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="resources" depends="init"
|
||||||
|
description="copy resources into build dir" >
|
||||||
|
<!-- Copy the resource files from ${resources} into ${build}/ -->
|
||||||
|
<mkdir dir="${dist}"/>
|
||||||
|
<mkdir dir="${dist}/renderperf"/>
|
||||||
|
<mkdir dir="${build}/renderperf/images"/>
|
||||||
|
<copy todir="${build}/renderperf/images">
|
||||||
|
<fileset dir="resources/renderperf/images" />
|
||||||
|
</copy>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="dist" depends="compile, resources"
|
||||||
|
description="generate the distribution" >
|
||||||
|
<!-- Create the distribution directory -->
|
||||||
|
<mkdir dir="${dist}"/>
|
||||||
|
|
||||||
|
<!-- Put everything in ${build} into the J2DBench.jar file -->
|
||||||
|
<jar jarfile="${dist}/RenderPerfTest.jar" basedir="${build}">
|
||||||
|
<manifest>
|
||||||
|
<attribute name="Built-By" value="${user.name}"/>
|
||||||
|
<attribute name="Main-Class" value="renderperf.RenderPerfTest"/>
|
||||||
|
</manifest>
|
||||||
|
</jar>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="clean"
|
||||||
|
description="clean up" >
|
||||||
|
<!-- Delete the ${build} and ${dist} directory trees -->
|
||||||
|
<delete dir="${build}"/>
|
||||||
|
<delete dir="${dist}"/>
|
||||||
|
</target>
|
||||||
|
</project>
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 2.1 KiB |
@@ -0,0 +1,367 @@
|
|||||||
|
/*
|
||||||
|
* 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 renderperf;
|
||||||
|
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
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.awt.image.BufferedImage;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
|
||||||
|
public class RenderPerfLCDTest {
|
||||||
|
private static HashSet<String> ignoredTests = new HashSet<>();
|
||||||
|
|
||||||
|
private final static int N = 1000;
|
||||||
|
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;
|
||||||
|
private final static int MAX_MEASURE_TIME = 5000;
|
||||||
|
|
||||||
|
|
||||||
|
interface Configurable {
|
||||||
|
void configure(Graphics2D g2d);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Renderable {
|
||||||
|
void setup(Graphics2D g2d);
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ParticleRenderable createPR(ParticleRenderer renderer) {
|
||||||
|
return new ParticleRenderable(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ParticleRenderable implements Renderable {
|
||||||
|
ParticleRenderer renderer;
|
||||||
|
Configurable configure;
|
||||||
|
|
||||||
|
ParticleRenderable(ParticleRenderer renderer, Configurable configure) {
|
||||||
|
this.renderer = renderer;
|
||||||
|
this.configure = configure;
|
||||||
|
}
|
||||||
|
|
||||||
|
ParticleRenderable(ParticleRenderer renderer) {
|
||||||
|
this(renderer, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setup(Graphics2D g2d) {
|
||||||
|
if (configure != null) configure.configure(g2d);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(Graphics2D g2d) {
|
||||||
|
balls.render(g2d, renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update() {
|
||||||
|
balls.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ParticleRenderable configure(Configurable configure) {
|
||||||
|
this.configure = configure;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ParticleRenderer {
|
||||||
|
void render(Graphics2D g2d, int id, float[] x, float[] y, float[] vx, float[] vy);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static class WhiteTextParticleRenderer implements ParticleRenderer {
|
||||||
|
float r;
|
||||||
|
|
||||||
|
WhiteTextParticleRenderer(float r) {
|
||||||
|
this.r = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPaint(Graphics2D g2d, int id) {
|
||||||
|
g2d.setColor(Color.WHITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(Graphics2D g2d, int id, float[] x, float[] y, float[] vx, float[] vy) {
|
||||||
|
setPaint(g2d, id);
|
||||||
|
g2d.drawString("The quick brown fox jumps over the lazy dog",
|
||||||
|
(int)(x[id] - r), (int)(y[id] - r));
|
||||||
|
g2d.drawString("The quick brown fox jumps over the lazy dog",
|
||||||
|
(int)(x[id] - r), (int)y[id]);
|
||||||
|
g2d.drawString("The quick brown fox jumps over the lazy dog",
|
||||||
|
(int)(x[id] - r), (int)(y[id] + r));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class TextParticleRenderer extends WhiteTextParticleRenderer {
|
||||||
|
Color[] colors;
|
||||||
|
|
||||||
|
float r;
|
||||||
|
|
||||||
|
TextParticleRenderer(int n, float r) {
|
||||||
|
super(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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPaint(Graphics2D g2d, int id) {
|
||||||
|
g2d.setColor(colors[id % colors.length]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class PerfMeter {
|
||||||
|
private String name;
|
||||||
|
private int frame = 0;
|
||||||
|
|
||||||
|
private JPanel panel;
|
||||||
|
|
||||||
|
private long time;
|
||||||
|
private double execTime = 0;
|
||||||
|
private Color expColor = Color.RED;
|
||||||
|
AtomicBoolean waiting = new AtomicBoolean(false);
|
||||||
|
private double fps;
|
||||||
|
|
||||||
|
PerfMeter(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
PerfMeter exec(final Renderable renderable) throws Exception {
|
||||||
|
final CountDownLatch latch = new CountDownLatch(COUNT);
|
||||||
|
final CountDownLatch latchFrame = new CountDownLatch(1);
|
||||||
|
final long endTime = System.currentTimeMillis() + MAX_MEASURE_TIME;
|
||||||
|
|
||||||
|
final Frame f = new Frame();
|
||||||
|
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.create();
|
||||||
|
renderable.setup(g2d);
|
||||||
|
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() + panel.getTopLevelAncestor().getInsets().left + BW / 2,
|
||||||
|
panel.getTopLevelAncestor().getY() + panel.getTopLevelAncestor().getInsets().top + BW / 2);
|
||||||
|
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() + panel.getTopLevelAncestor().getInsets().left + BW/2,
|
||||||
|
panel.getTopLevelAncestor().getY() + panel.getTopLevelAncestor().getInsets().top + BH/2),
|
||||||
|
expColor))
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Thread.sleep(RESOLUTION);
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
time = System.nanoTime() - time;
|
||||||
|
execTime += time;
|
||||||
|
frame++;
|
||||||
|
waiting.set(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (System.currentTimeMillis() < endTime) {
|
||||||
|
latch.countDown();
|
||||||
|
} else {
|
||||||
|
while(latch.getCount() > 0) latch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
timer.start();
|
||||||
|
latch.await();
|
||||||
|
SwingUtilities.invokeAndWait(() -> {
|
||||||
|
timer.stop();
|
||||||
|
f.setVisible(false);
|
||||||
|
f.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
|
latchFrame.await();
|
||||||
|
if (execTime != 0 && frame != 0) {
|
||||||
|
fps = 1e9 / (execTime / frame);
|
||||||
|
} else {
|
||||||
|
fps = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void report() {
|
||||||
|
System.err.println(name + " : " + String.format("%.2f FPS", fps));
|
||||||
|
}
|
||||||
|
|
||||||
|
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 textRenderer = new TextParticleRenderer(N, R);
|
||||||
|
|
||||||
|
private static final Configurable TextLCD = (Graphics2D g2d) ->
|
||||||
|
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
|
||||||
|
RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);
|
||||||
|
|
||||||
|
public void testTextBubblesLCD() throws Exception {
|
||||||
|
(new PerfMeter("TextLCD")).exec(createPR(textRenderer).configure(TextLCD)).report();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args)
|
||||||
|
throws InvocationTargetException, IllegalAccessException, NoSuchMethodException
|
||||||
|
{
|
||||||
|
RenderPerfLCDTest test = new RenderPerfLCDTest();
|
||||||
|
|
||||||
|
if (args.length > 0) {
|
||||||
|
for (String testCase : args) {
|
||||||
|
Method m = RenderPerfLCDTest.class.getDeclaredMethod(testCase);
|
||||||
|
m.invoke(test);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Method[] methods = RenderPerfLCDTest.class.getDeclaredMethods();
|
||||||
|
for (Method m : methods) {
|
||||||
|
if (m.getName().startsWith("test") && !ignoredTests.contains(m.getName())) {
|
||||||
|
m.invoke(test);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,748 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, 2020 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 renderperf;
|
||||||
|
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
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.awt.image.BufferedImage;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
|
||||||
|
public class RenderPerfTest {
|
||||||
|
private static HashSet<String> ignoredTests = new HashSet<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
ignoredTests.add("testWhiteTextBubblesNoAA");
|
||||||
|
ignoredTests.add("testWhiteTextBubblesLCD");
|
||||||
|
ignoredTests.add("testWhiteTextBubblesGray");
|
||||||
|
ignoredTests.add("testLinGradOvalRotBubblesAA");
|
||||||
|
ignoredTests.add("testWiredBoxBubblesAA");
|
||||||
|
ignoredTests.add("testLinesAA");
|
||||||
|
}
|
||||||
|
|
||||||
|
private final static int N = 1000;
|
||||||
|
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;
|
||||||
|
private final static int MAX_MEASURE_TIME = 5000;
|
||||||
|
|
||||||
|
|
||||||
|
interface Configurable {
|
||||||
|
void configure(Graphics2D g2d);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Renderable {
|
||||||
|
void setup(Graphics2D g2d);
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ParticleRenderable createPR(ParticleRenderer renderer) {
|
||||||
|
return new ParticleRenderable(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ParticleRenderable implements Renderable {
|
||||||
|
ParticleRenderer renderer;
|
||||||
|
Configurable configure;
|
||||||
|
|
||||||
|
ParticleRenderable(ParticleRenderer renderer, Configurable configure) {
|
||||||
|
this.renderer = renderer;
|
||||||
|
this.configure = configure;
|
||||||
|
}
|
||||||
|
|
||||||
|
ParticleRenderable(ParticleRenderer renderer) {
|
||||||
|
this(renderer, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setup(Graphics2D g2d) {
|
||||||
|
if (configure != null) configure.configure(g2d);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(Graphics2D g2d) {
|
||||||
|
balls.render(g2d, renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update() {
|
||||||
|
balls.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ParticleRenderable configure(Configurable configure) {
|
||||||
|
this.configure = configure;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 WhiteTextParticleRenderer implements ParticleRenderer {
|
||||||
|
float r;
|
||||||
|
|
||||||
|
WhiteTextParticleRenderer(float r) {
|
||||||
|
this.r = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPaint(Graphics2D g2d, int id) {
|
||||||
|
g2d.setColor(Color.WHITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(Graphics2D g2d, int id, float[] x, float[] y, float[] vx, float[] vy) {
|
||||||
|
setPaint(g2d, id);
|
||||||
|
g2d.drawString("The quick brown fox jumps over the lazy dog",
|
||||||
|
(int)(x[id] - r), (int)(y[id] - r));
|
||||||
|
g2d.drawString("The quick brown fox jumps over the lazy dog",
|
||||||
|
(int)(x[id] - r), (int)y[id]);
|
||||||
|
g2d.drawString("The quick brown fox jumps over the lazy dog",
|
||||||
|
(int)(x[id] - r), (int)(y[id] + r));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class TextParticleRenderer extends WhiteTextParticleRenderer {
|
||||||
|
Color[] colors;
|
||||||
|
|
||||||
|
float r;
|
||||||
|
|
||||||
|
TextParticleRenderer(int n, float r) {
|
||||||
|
super(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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPaint(Graphics2D g2d, int id) {
|
||||||
|
g2d.setColor(colors[id % colors.length]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class LargeTextParticleRenderer extends TextParticleRenderer {
|
||||||
|
|
||||||
|
LargeTextParticleRenderer(int n, float r) {
|
||||||
|
super(n, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(Graphics2D g2d, int id, float[] x, float[] y, float[] vx, float[] vy) {
|
||||||
|
setPaint(g2d, id);
|
||||||
|
Font font = new Font("LucidaGrande", Font.PLAIN, 32);
|
||||||
|
g2d.setFont(font);
|
||||||
|
g2d.drawString("The quick brown fox jumps over the lazy dog",
|
||||||
|
(int)(x[id] - r), (int)(y[id] - r));
|
||||||
|
g2d.drawString("The quick brown fox jumps over the lazy dog",
|
||||||
|
(int)(x[id] - r), (int)y[id]);
|
||||||
|
g2d.drawString("The quick brown fox jumps over the lazy dog",
|
||||||
|
(int)(x[id] - r), (int)(y[id] + 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], colors[(colors.length - id) %colors.length]};
|
||||||
|
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 ImgParticleRenderer extends FlatParticleRenderer {
|
||||||
|
BufferedImage dukeImg;
|
||||||
|
|
||||||
|
ImgParticleRenderer(int n, float r) {
|
||||||
|
super(n, r);
|
||||||
|
try {
|
||||||
|
dukeImg = ImageIO.read(
|
||||||
|
Objects.requireNonNull(
|
||||||
|
RenderPerfTest.class.getClassLoader().getResourceAsStream(
|
||||||
|
"renderperf/images/duke.png")));
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(Graphics2D g2d, int id, float[] x, float[] y, float[] vx, float[] vy) {
|
||||||
|
g2d.setColor(colors[id % colors.length]);
|
||||||
|
g2d.drawImage(dukeImg, (int)(x[id] - r), (int)(y[id] - r), (int)(2*r), (int)(2*r), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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]));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class PerfMeter {
|
||||||
|
private String name;
|
||||||
|
private int frame = 0;
|
||||||
|
|
||||||
|
private JPanel panel;
|
||||||
|
|
||||||
|
private long time;
|
||||||
|
private double execTime = 0;
|
||||||
|
private Color expColor = Color.RED;
|
||||||
|
AtomicBoolean waiting = new AtomicBoolean(false);
|
||||||
|
private double fps;
|
||||||
|
|
||||||
|
PerfMeter(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
PerfMeter exec(final Renderable renderable) throws Exception {
|
||||||
|
final CountDownLatch latch = new CountDownLatch(COUNT);
|
||||||
|
final CountDownLatch latchFrame = new CountDownLatch(1);
|
||||||
|
final long endTime = System.currentTimeMillis() + MAX_MEASURE_TIME;
|
||||||
|
|
||||||
|
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.create();
|
||||||
|
renderable.setup(g2d);
|
||||||
|
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() + panel.getTopLevelAncestor().getInsets().left + BW / 2,
|
||||||
|
panel.getTopLevelAncestor().getY() + panel.getTopLevelAncestor().getInsets().top + BW / 2);
|
||||||
|
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() + panel.getTopLevelAncestor().getInsets().left + BW/2,
|
||||||
|
panel.getTopLevelAncestor().getY() + panel.getTopLevelAncestor().getInsets().top + BH/2),
|
||||||
|
expColor))
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Thread.sleep(RESOLUTION);
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
time = System.nanoTime() - time;
|
||||||
|
execTime += time;
|
||||||
|
frame++;
|
||||||
|
waiting.set(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (System.currentTimeMillis() < endTime) {
|
||||||
|
latch.countDown();
|
||||||
|
} else {
|
||||||
|
while(latch.getCount() > 0) latch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
timer.start();
|
||||||
|
latch.await();
|
||||||
|
SwingUtilities.invokeAndWait(() -> {
|
||||||
|
timer.stop();
|
||||||
|
f.setVisible(false);
|
||||||
|
f.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
|
latchFrame.await();
|
||||||
|
if (execTime != 0 && frame != 0) {
|
||||||
|
fps = 1e9 / (execTime / frame);
|
||||||
|
} else {
|
||||||
|
fps = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void report() {
|
||||||
|
System.err.println(name + " : " + String.format("%.2f FPS", fps));
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
private static final ParticleRenderer imgRenderer = new ImgParticleRenderer(N, R);
|
||||||
|
private static final ParticleRenderer textRenderer = new TextParticleRenderer(N, R);
|
||||||
|
private static final ParticleRenderer largeTextRenderer = new LargeTextParticleRenderer(N, R);
|
||||||
|
private static final ParticleRenderer whiteTextRenderer = new WhiteTextParticleRenderer(R);
|
||||||
|
|
||||||
|
private static final Configurable AA = (Graphics2D g2d) ->
|
||||||
|
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
|
||||||
|
RenderingHints.VALUE_ANTIALIAS_ON);
|
||||||
|
|
||||||
|
private static final Configurable TextLCD = (Graphics2D g2d) ->
|
||||||
|
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
|
||||||
|
RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);
|
||||||
|
|
||||||
|
private static final Configurable TextAA = (Graphics2D g2d) ->
|
||||||
|
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
|
||||||
|
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
||||||
|
|
||||||
|
public void testFlatBubbles() throws Exception {
|
||||||
|
(new PerfMeter("FlatOval")).exec(createPR(flatRenderer)).report();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testFlatBubblesAA() throws Exception {
|
||||||
|
(new PerfMeter("FlatOvalAA")).exec(createPR(flatRenderer).configure(AA)).report();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testFlatBoxBubbles() throws Exception {
|
||||||
|
(new PerfMeter("FlatBox")).exec(createPR(flatBoxRenderer)).report();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testFlatBoxBubblesAA() throws Exception {
|
||||||
|
(new PerfMeter("FlatBoxAA")).exec(createPR(flatBoxRenderer).configure(AA)).report();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testImgBubbles() throws Exception {
|
||||||
|
(new PerfMeter("Image")).exec(createPR(imgRenderer)).report();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testImgBubblesAA() throws Exception {
|
||||||
|
(new PerfMeter("ImageAA")).exec(createPR(imgRenderer).configure(AA)).report();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testFlatBoxRotBubbles() throws Exception {
|
||||||
|
(new PerfMeter("RotatedBox")).exec(createPR(flatBoxRotRenderer)).report();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testFlatBoxRotBubblesAA() throws Exception {
|
||||||
|
(new PerfMeter("RotatedBoxAA")).exec(createPR(flatBoxRotRenderer).configure(AA)).report();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testFlatOvalRotBubbles() throws Exception {
|
||||||
|
(new PerfMeter("RotatedOval")).exec(createPR(flatOvalRotRenderer)).report();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testFlatOvalRotBubblesAA() throws Exception {
|
||||||
|
(new PerfMeter("RotatedOvalAA")).exec(createPR(flatOvalRotRenderer).configure(AA)).report();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testLinGradOvalRotBubbles() throws Exception {
|
||||||
|
(new PerfMeter("LinGradRotatedOval")).exec(createPR(linGradOvalRotRenderer)).report();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testLinGradOvalRotBubblesAA() throws Exception {
|
||||||
|
(new PerfMeter("LinGradRotatedOvalAA")).exec(createPR(linGradOvalRotRenderer).configure(AA)).report();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testWiredBubbles() throws Exception {
|
||||||
|
(new PerfMeter("WiredBubbles")).exec(createPR(wiredRenderer)).report();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testWiredBubblesAA() throws Exception {
|
||||||
|
(new PerfMeter("WiredBubblesAA")).exec(createPR(wiredRenderer).configure(AA)).report();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testWiredBoxBubbles() throws Exception {
|
||||||
|
(new PerfMeter("WiredBox")).exec(createPR(wiredBoxRenderer)).report();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testWiredBoxBubblesAA() throws Exception {
|
||||||
|
(new PerfMeter("WiredBoxAA")).exec(createPR(wiredBoxRenderer).configure(AA)).report();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testLines() throws Exception {
|
||||||
|
(new PerfMeter("Lines")).exec(createPR(segRenderer)).report();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testLinesAA() throws Exception {
|
||||||
|
(new PerfMeter("LinesAA")).exec(createPR(segRenderer).configure(AA)).report();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testFlatQuad() throws Exception {
|
||||||
|
(new PerfMeter("FlatQuad")).exec(createPR(flatQuadRenderer)).report();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testFlatQuadAA() throws Exception {
|
||||||
|
(new PerfMeter("FlatQuadAA")).exec(createPR(flatQuadRenderer).configure(AA)).report();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testWiredQuad() throws Exception {
|
||||||
|
(new PerfMeter("WiredQuad")).exec(createPR(wiredQuadRenderer)).report();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testWiredQuadAA() throws Exception {
|
||||||
|
(new PerfMeter("WiredQuadAA")).exec(createPR(wiredQuadRenderer).configure(AA)).report();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testTextBubblesNoAA() throws Exception {
|
||||||
|
(new PerfMeter("TextNoAA")).exec(createPR(textRenderer)).report();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testTextBubblesLCD() throws Exception {
|
||||||
|
(new PerfMeter("TextLCD")).exec(createPR(textRenderer).configure(TextLCD)).report();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testTextBubblesGray() throws Exception {
|
||||||
|
(new PerfMeter("TextGray")).exec(createPR(textRenderer).configure(TextAA)).report();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testLargeTextBubblesNoAA() throws Exception {
|
||||||
|
(new PerfMeter("LargeTextNoAA")).exec(createPR(largeTextRenderer)).report();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testLargeTextBubblesLCD() throws Exception {
|
||||||
|
(new PerfMeter("LargeTextLCD")).exec(createPR(largeTextRenderer).configure(TextLCD)).report();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testLargeTextBubblesGray() throws Exception {
|
||||||
|
(new PerfMeter("LargeTextGray")).exec(createPR(largeTextRenderer).configure(TextAA)).report();
|
||||||
|
}
|
||||||
|
public void testWhiteTextBubblesNoAA() throws Exception {
|
||||||
|
(new PerfMeter("WhiteTextNoAA")).exec(createPR(whiteTextRenderer)).report();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testWhiteTextBubblesLCD() throws Exception {
|
||||||
|
(new PerfMeter("WhiteTextLCD")).exec(createPR(whiteTextRenderer).configure(TextLCD)).report();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testWhiteTextBubblesGray() throws Exception {
|
||||||
|
(new PerfMeter("WhiteTextGray")).exec(createPR(whiteTextRenderer).configure(TextAA)).report();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args)
|
||||||
|
throws InvocationTargetException, IllegalAccessException, NoSuchMethodException
|
||||||
|
{
|
||||||
|
RenderPerfTest test = new RenderPerfTest();
|
||||||
|
|
||||||
|
if (args.length > 0) {
|
||||||
|
for (String testCase : args) {
|
||||||
|
Method m = RenderPerfTest.class.getDeclaredMethod(testCase);
|
||||||
|
m.invoke(test);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Method[] methods = RenderPerfTest.class.getDeclaredMethods();
|
||||||
|
for (Method m : methods) {
|
||||||
|
if (m.getName().startsWith("test") && !ignoredTests.contains(m.getName())) {
|
||||||
|
m.invoke(test);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -34,6 +34,7 @@ import java.awt.image.ColorModel;
|
|||||||
import sun.java2d.SurfaceData;
|
import sun.java2d.SurfaceData;
|
||||||
import sun.java2d.opengl.CGLLayer;
|
import sun.java2d.opengl.CGLLayer;
|
||||||
import sun.lwawt.LWGraphicsConfig;
|
import sun.lwawt.LWGraphicsConfig;
|
||||||
|
import sun.lwawt.macosx.CFRetainedResource;
|
||||||
|
|
||||||
public abstract class CGraphicsConfig extends GraphicsConfiguration
|
public abstract class CGraphicsConfig extends GraphicsConfiguration
|
||||||
implements LWGraphicsConfig {
|
implements LWGraphicsConfig {
|
||||||
@@ -80,7 +81,7 @@ public abstract class CGraphicsConfig extends GraphicsConfiguration
|
|||||||
* Creates a new SurfaceData that will be associated with the given
|
* Creates a new SurfaceData that will be associated with the given
|
||||||
* CGLLayer.
|
* CGLLayer.
|
||||||
*/
|
*/
|
||||||
public abstract SurfaceData createSurfaceData(CGLLayer layer);
|
public abstract SurfaceData createSurfaceData(CFRetainedResource layer);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final boolean isTranslucencyCapable() {
|
public final boolean isTranslucencyCapable() {
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ import java.awt.peer.WindowPeer;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import sun.java2d.SunGraphicsEnvironment;
|
import sun.java2d.SunGraphicsEnvironment;
|
||||||
|
import sun.java2d.macos.MacOSFlags;
|
||||||
|
import sun.java2d.metal.MTLGraphicsConfig;
|
||||||
import sun.java2d.opengl.CGLGraphicsConfig;
|
import sun.java2d.opengl.CGLGraphicsConfig;
|
||||||
|
|
||||||
import static java.awt.peer.ComponentPeer.SET_BOUNDS;
|
import static java.awt.peer.ComponentPeer.SET_BOUNDS;
|
||||||
@@ -63,7 +65,9 @@ public final class CGraphicsDevice extends GraphicsDevice
|
|||||||
|
|
||||||
public CGraphicsDevice(final int displayID) {
|
public CGraphicsDevice(final int displayID) {
|
||||||
this.displayID = displayID;
|
this.displayID = displayID;
|
||||||
config = CGLGraphicsConfig.getConfig(this);
|
config = MacOSFlags.isMetalEnabled() ?
|
||||||
|
MTLGraphicsConfig.getConfig(this, displayID, 0) :
|
||||||
|
CGLGraphicsConfig.getConfig(this);
|
||||||
// initializes default device state, might be redundant step since we
|
// initializes default device state, might be redundant step since we
|
||||||
// call "displayChanged()" later anyway, but we do not want to leave the
|
// call "displayChanged()" later anyway, but we do not want to leave the
|
||||||
// device in an inconsistent state after construction
|
// device in an inconsistent state after construction
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@@ -27,6 +27,8 @@ package sun.java2d;
|
|||||||
|
|
||||||
import sun.awt.image.SunVolatileImage;
|
import sun.awt.image.SunVolatileImage;
|
||||||
import sun.awt.image.VolatileSurfaceManager;
|
import sun.awt.image.VolatileSurfaceManager;
|
||||||
|
import sun.java2d.macos.MacOSFlags;
|
||||||
|
import sun.java2d.metal.MTLVolatileSurfaceManager;
|
||||||
import sun.java2d.opengl.CGLVolatileSurfaceManager;
|
import sun.java2d.opengl.CGLVolatileSurfaceManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -49,6 +51,7 @@ public class MacosxSurfaceManagerFactory extends SurfaceManagerFactory {
|
|||||||
public VolatileSurfaceManager createVolatileManager(SunVolatileImage vImg,
|
public VolatileSurfaceManager createVolatileManager(SunVolatileImage vImg,
|
||||||
Object context)
|
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: "-Dsun.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("sun.java2d.metal", false);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isMetalEnabled() {
|
||||||
|
return metalEnabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,951 @@
|
|||||||
|
/*
|
||||||
|
* 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),
|
||||||
|
// TODO: Provide native implementation
|
||||||
|
// It may not be effective/possible. For example, there is no direct
|
||||||
|
// support in Metal for SurfaceType.ThreeByteBgr
|
||||||
|
// 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),
|
||||||
|
// TODO: Provide native implementation
|
||||||
|
// 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),
|
||||||
|
// TODO: Provide native implementation
|
||||||
|
// 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),
|
||||||
|
// TODO: Provide native implementation
|
||||||
|
// 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 /*unused*/, xform != null,
|
||||||
|
hint, srctype);
|
||||||
|
enqueueBlit(rq, srcData, dstData,
|
||||||
|
packedParams,
|
||||||
|
sx1, sy1, sx2, sy2,
|
||||||
|
dx1, dy1, dx2, dy2);
|
||||||
|
|
||||||
|
// always flush immediately, since we (currently) have no means
|
||||||
|
// of tracking changes to the system memory surface
|
||||||
|
rq.flushNow();
|
||||||
|
} finally {
|
||||||
|
rq.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note: The srcImg and biop parameters are only used when invoked
|
||||||
|
* from the 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,
|
||||||
|
false /*unused*/, 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
183
src/java.desktop/macosx/classes/sun/java2d/metal/MTLContext.java
Normal file
183
src/java.desktop/macosx/classes/sun/java2d/metal/MTLContext.java
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
final class MTLContext extends BufferedContext {
|
||||||
|
|
||||||
|
public MTLContext(RenderQueue rq) {
|
||||||
|
super(rq);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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();
|
||||||
|
|
||||||
|
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,402 @@
|
|||||||
|
/*
|
||||||
|
* 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 java.awt.*;
|
||||||
|
import java.awt.color.ColorSpace;
|
||||||
|
import java.awt.image.*;
|
||||||
|
import java.io.File;
|
||||||
|
import java.security.AccessController;
|
||||||
|
import java.security.PrivilegedAction;
|
||||||
|
|
||||||
|
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 final 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();
|
||||||
|
|
||||||
|
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());
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) {
|
||||||
|
MTLRenderQueue.disposeGraphicsConfig(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(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);
|
||||||
|
}
|
||||||
|
}
|
||||||
149
src/java.desktop/macosx/classes/sun/java2d/metal/MTLLayer.java
Normal file
149
src/java.desktop/macosx/classes/sun/java2d/metal/MTLLayer.java
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
/*
|
||||||
|
* 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 nativeSetInsets(long layerPtr, int top, int left);
|
||||||
|
private static native void validate(long layerPtr, MTLSurfaceData cglsd);
|
||||||
|
private static native void blitTexture(long layerPtr);
|
||||||
|
|
||||||
|
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());
|
||||||
|
Insets insets = peer.getInsets();
|
||||||
|
execute(ptr -> nativeSetInsets(ptr, insets.top, insets.left));
|
||||||
|
// 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);
|
||||||
|
SurfaceData oldData = surfaceData;
|
||||||
|
surfaceData = NullSurfaceData.theInstance;;
|
||||||
|
if (oldData != null) {
|
||||||
|
oldData.flush();
|
||||||
|
}
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setScale(final int _scale) {
|
||||||
|
if (scale != _scale) {
|
||||||
|
scale = _scale;
|
||||||
|
execute(ptr -> nativeSetScale(ptr, scale));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
// NATIVE CALLBACKS
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
private void drawInMTLContext() {
|
||||||
|
// tell the flusher thread not to update the intermediate buffer
|
||||||
|
// until we are done blitting from it
|
||||||
|
MTLRenderQueue rq = MTLRenderQueue.getInstance();
|
||||||
|
rq.lock();
|
||||||
|
try {
|
||||||
|
execute(ptr -> blitTexture(ptr));
|
||||||
|
} finally {
|
||||||
|
rq.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
197
src/java.desktop/macosx/classes/sun/java2d/metal/MTLPaints.java
Normal file
197
src/java.desktop/macosx/classes/sun/java2d/metal/MTLPaints.java
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
/*
|
||||||
|
* 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();
|
||||||
|
|
||||||
|
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,695 @@
|
|||||||
|
/*
|
||||||
|
* 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 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.*;
|
||||||
|
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 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private native void initOps(MTLGraphicsConfig gc, long pConfigInfo, long pPeerData, long layerPtr,
|
||||||
|
int xoff, int yoff, boolean isOpaque);
|
||||||
|
|
||||||
|
private MTLSurfaceData(MTLLayer layer, 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;
|
||||||
|
|
||||||
|
long pConfigInfo = gc.getNativeConfigInfo();
|
||||||
|
long layerPtr = 0L;
|
||||||
|
boolean isOpaque = true;
|
||||||
|
if (layer != null) {
|
||||||
|
layerPtr = layer.getPointer();
|
||||||
|
isOpaque = layer.isOpaque();
|
||||||
|
}
|
||||||
|
initOps(gc, pConfigInfo, 0, layerPtr, 0, 0, isOpaque);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override //SurfaceData
|
||||||
|
public GraphicsConfiguration getDeviceConfiguration() {
|
||||||
|
return graphicsConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 = (MTLGraphicsConfig)layer.getGraphicsConfiguration();
|
||||||
|
Rectangle r = layer.getBounds();
|
||||||
|
return new MTLLayerSurfaceData(layer, gc, r.width, r.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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(gc, width, height, image, cm,
|
||||||
|
type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getDefaultScaleX() {
|
||||||
|
return scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getDefaultScaleY() {
|
||||||
|
return scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Rectangle getBounds() {
|
||||||
|
return new Rectangle(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected native void clearWindow();
|
||||||
|
|
||||||
|
protected native boolean initTexture(long pData, boolean isOpaque, int width, int height);
|
||||||
|
|
||||||
|
protected native boolean initRTexture(long pData, boolean isOpaque, 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, width, height);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RT_TEXTURE:
|
||||||
|
success = initRTexture(getNativeOps(), isOpaque, 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
|
||||||
|
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 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 long getMTLTexturePointer(long pData);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 getMTLTexturePointer(getNativeOps());
|
||||||
|
}
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 final MTLLayer layer;
|
||||||
|
|
||||||
|
private 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 Object getDestination() {
|
||||||
|
return layer.getDestination();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTransparency() {
|
||||||
|
return layer.getTransparency();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void invalidate() {
|
||||||
|
super.invalidate();
|
||||||
|
clearWindow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SurfaceData object representing an off-screen buffer (either a FBO or
|
||||||
|
* Texture).
|
||||||
|
+ */
|
||||||
|
public static class MTLOffScreenSurfaceData extends MTLSurfaceData {
|
||||||
|
private final Image offscreenImage;
|
||||||
|
|
||||||
|
public MTLOffScreenSurfaceData(MTLGraphicsConfig gc, int width,
|
||||||
|
int height, Image image,
|
||||||
|
ColorModel cm, int type) {
|
||||||
|
super(null, gc, cm, type, width, height);
|
||||||
|
offscreenImage = image;
|
||||||
|
initSurface(this.width, this.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SurfaceData getReplacement() {
|
||||||
|
return restoreContents(offscreenImage);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disposes the native resources associated with the given MTLSurfaceData
|
||||||
|
* (referenced by the pData parameter). This method is invoked from
|
||||||
|
* the native Dispose() method from the Disposer thread when the
|
||||||
|
* Java-level MTLSurfaceData object is about to go away.
|
||||||
|
*/
|
||||||
|
public static void dispose(long pData, MTLGraphicsConfig gc) {
|
||||||
|
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(gc);
|
||||||
|
RenderBuffer buf = rq.getBuffer();
|
||||||
|
rq.ensureCapacityAndAlignment(12, 4);
|
||||||
|
buf.putInt(DISPOSE_SURFACE);
|
||||||
|
buf.putLong(pData);
|
||||||
|
|
||||||
|
// this call is expected to complete synchronously, so flush now
|
||||||
|
rq.flushNow();
|
||||||
|
} finally {
|
||||||
|
rq.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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,278 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* 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.image.SunVolatileImage;
|
||||||
|
import sun.awt.image.VolatileSurfaceManager;
|
||||||
|
import sun.java2d.SurfaceData;
|
||||||
|
import sun.java2d.opengl.OGLSurfaceData;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.image.ColorModel;
|
||||||
|
|
||||||
|
import static java.awt.BufferCapabilities.FlipContents.COPIED;
|
||||||
|
|
||||||
|
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() {
|
||||||
|
try {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
return MTLSurfaceData.createData(gc,
|
||||||
|
vImg.getWidth(),
|
||||||
|
vImg.getHeight(),
|
||||||
|
cm, vImg, type);
|
||||||
|
} catch (NullPointerException | OutOfMemoryError ignored) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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.AccelTypedVolatileImage;
|
||||||
import sun.java2d.pipe.hw.ContextCapabilities;
|
import sun.java2d.pipe.hw.ContextCapabilities;
|
||||||
import sun.lwawt.LWComponentPeer;
|
import sun.lwawt.LWComponentPeer;
|
||||||
|
import sun.lwawt.macosx.CFRetainedResource;
|
||||||
|
|
||||||
import static sun.java2d.opengl.OGLContext.OGLContextCaps.CAPS_DOUBLEBUFFERED;
|
import static sun.java2d.opengl.OGLContext.OGLContextCaps.CAPS_DOUBLEBUFFERED;
|
||||||
import static sun.java2d.opengl.OGLContext.OGLContextCaps.CAPS_EXT_FBOBJECT;
|
import static sun.java2d.opengl.OGLContext.OGLContextCaps.CAPS_EXT_FBOBJECT;
|
||||||
@@ -62,7 +63,7 @@ import static sun.java2d.opengl.OGLSurfaceData.FBOBJECT;
|
|||||||
import static sun.java2d.opengl.OGLSurfaceData.TEXTURE;
|
import static sun.java2d.opengl.OGLSurfaceData.TEXTURE;
|
||||||
|
|
||||||
public final class CGLGraphicsConfig extends CGraphicsConfig
|
public final class CGLGraphicsConfig extends CGraphicsConfig
|
||||||
implements OGLGraphicsConfig
|
implements OGLGraphicsConfig
|
||||||
{
|
{
|
||||||
private static boolean cglAvailable;
|
private static boolean cglAvailable;
|
||||||
private static ImageCapabilities imageCaps = new CGLImageCaps();
|
private static ImageCapabilities imageCaps = new CGLImageCaps();
|
||||||
@@ -101,7 +102,7 @@ public final class CGLGraphicsConfig extends CGraphicsConfig
|
|||||||
// add a record to the Disposer so that we destroy the native
|
// add a record to the Disposer so that we destroy the native
|
||||||
// CGLGraphicsConfigInfo data when this object goes away
|
// CGLGraphicsConfigInfo data when this object goes away
|
||||||
Disposer.addRecord(disposerReferent,
|
Disposer.addRecord(disposerReferent,
|
||||||
new CGLGCDisposerRecord(pConfigInfo));
|
new CGLGCDisposerRecord(pConfigInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -112,9 +113,9 @@ public final class CGLGraphicsConfig extends CGraphicsConfig
|
|||||||
@Override
|
@Override
|
||||||
public SurfaceData createManagedSurface(int w, int h, int transparency) {
|
public SurfaceData createManagedSurface(int w, int h, int transparency) {
|
||||||
return CGLSurfaceData.createData(this, w, h,
|
return CGLSurfaceData.createData(this, w, h,
|
||||||
getColorModel(transparency),
|
getColorModel(transparency),
|
||||||
null,
|
null,
|
||||||
OGLSurfaceData.TEXTURE);
|
OGLSurfaceData.TEXTURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CGLGraphicsConfig getConfig(CGraphicsDevice device)
|
public static CGLGraphicsConfig getConfig(CGraphicsDevice device)
|
||||||
@@ -184,27 +185,27 @@ public final class CGLGraphicsConfig extends CGraphicsConfig
|
|||||||
public BufferedImage createCompatibleImage(int width, int height) {
|
public BufferedImage createCompatibleImage(int width, int height) {
|
||||||
ColorModel model = new DirectColorModel(24, 0xff0000, 0xff00, 0xff);
|
ColorModel model = new DirectColorModel(24, 0xff0000, 0xff00, 0xff);
|
||||||
WritableRaster
|
WritableRaster
|
||||||
raster = model.createCompatibleWritableRaster(width, height);
|
raster = model.createCompatibleWritableRaster(width, height);
|
||||||
return new BufferedImage(model, raster, model.isAlphaPremultiplied(),
|
return new BufferedImage(model, raster, model.isAlphaPremultiplied(),
|
||||||
null);
|
null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ColorModel getColorModel(int transparency) {
|
public ColorModel getColorModel(int transparency) {
|
||||||
switch (transparency) {
|
switch (transparency) {
|
||||||
case Transparency.OPAQUE:
|
case Transparency.OPAQUE:
|
||||||
// REMIND: once the ColorModel spec is changed, this should be
|
// REMIND: once the ColorModel spec is changed, this should be
|
||||||
// an opaque premultiplied DCM...
|
// an opaque premultiplied DCM...
|
||||||
return new DirectColorModel(24, 0xff0000, 0xff00, 0xff);
|
return new DirectColorModel(24, 0xff0000, 0xff00, 0xff);
|
||||||
case Transparency.BITMASK:
|
case Transparency.BITMASK:
|
||||||
return new DirectColorModel(25, 0xff0000, 0xff00, 0xff, 0x1000000);
|
return new DirectColorModel(25, 0xff0000, 0xff00, 0xff, 0x1000000);
|
||||||
case Transparency.TRANSLUCENT:
|
case Transparency.TRANSLUCENT:
|
||||||
ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
|
ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
|
||||||
return new DirectColorModel(cs, 32,
|
return new DirectColorModel(cs, 32,
|
||||||
0xff0000, 0xff00, 0xff, 0xff000000,
|
0xff0000, 0xff00, 0xff, 0xff000000,
|
||||||
true, DataBuffer.TYPE_INT);
|
true, DataBuffer.TYPE_INT);
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,8 +249,8 @@ public final class CGLGraphicsConfig extends CGraphicsConfig
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SurfaceData createSurfaceData(CGLLayer layer) {
|
public SurfaceData createSurfaceData(CFRetainedResource layer) {
|
||||||
return CGLSurfaceData.createData(layer);
|
return CGLSurfaceData.createData((CGLLayer) layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -259,7 +260,7 @@ public final class CGLGraphicsConfig extends CGraphicsConfig
|
|||||||
ColorModel model = getColorModel(Transparency.OPAQUE);
|
ColorModel model = getColorModel(Transparency.OPAQUE);
|
||||||
WritableRaster wr = model.createCompatibleWritableRaster(width, height);
|
WritableRaster wr = model.createCompatibleWritableRaster(width, height);
|
||||||
return new OffScreenImage(target, model, wr,
|
return new OffScreenImage(target, model, wr,
|
||||||
model.isAlphaPremultiplied());
|
model.isAlphaPremultiplied());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -290,7 +291,7 @@ public final class CGLGraphicsConfig extends CGraphicsConfig
|
|||||||
final int w = Math.max(1, r.width);
|
final int w = Math.max(1, r.width);
|
||||||
final int h = Math.max(1, r.height);
|
final int h = Math.max(1, r.height);
|
||||||
final int transparency = peer.isTranslucent() ? Transparency.TRANSLUCENT
|
final int transparency = peer.isTranslucent() ? Transparency.TRANSLUCENT
|
||||||
: Transparency.OPAQUE;
|
: Transparency.OPAQUE;
|
||||||
return new SunVolatileImage(this, w, h, transparency, null);
|
return new SunVolatileImage(this, w, h, transparency, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,7 +317,7 @@ public final class CGLGraphicsConfig extends CGraphicsConfig
|
|||||||
try {
|
try {
|
||||||
bg.setBackground(peer.getBackground());
|
bg.setBackground(peer.getBackground());
|
||||||
bg.clearRect(0, 0, backBuffer.getWidth(null),
|
bg.clearRect(0, 0, backBuffer.getWidth(null),
|
||||||
backBuffer.getHeight(null));
|
backBuffer.getHeight(null));
|
||||||
} finally {
|
} finally {
|
||||||
bg.dispose();
|
bg.dispose();
|
||||||
}
|
}
|
||||||
@@ -326,7 +327,7 @@ public final class CGLGraphicsConfig extends CGraphicsConfig
|
|||||||
private static class CGLBufferCaps extends BufferCapabilities {
|
private static class CGLBufferCaps extends BufferCapabilities {
|
||||||
public CGLBufferCaps(boolean dblBuf) {
|
public CGLBufferCaps(boolean dblBuf) {
|
||||||
super(imageCaps, imageCaps,
|
super(imageCaps, imageCaps,
|
||||||
dblBuf ? FlipContents.UNDEFINED : null);
|
dblBuf ? FlipContents.UNDEFINED : null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -362,10 +363,10 @@ public final class CGLGraphicsConfig extends CGraphicsConfig
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
SunVolatileImage vi = new AccelTypedVolatileImage(this, width, height,
|
SunVolatileImage vi = new AccelTypedVolatileImage(this, width, height,
|
||||||
transparency, type);
|
transparency, type);
|
||||||
Surface sd = vi.getDestSurface();
|
Surface sd = vi.getDestSurface();
|
||||||
if (!(sd instanceof AccelSurface) ||
|
if (!(sd instanceof AccelSurface) ||
|
||||||
((AccelSurface)sd).getType() != type)
|
((AccelSurface)sd).getType() != type)
|
||||||
{
|
{
|
||||||
vi.flush();
|
vi.flush();
|
||||||
vi = null;
|
vi = null;
|
||||||
@@ -382,12 +383,12 @@ public final class CGLGraphicsConfig extends CGraphicsConfig
|
|||||||
@Override
|
@Override
|
||||||
public int getMaxTextureWidth() {
|
public int getMaxTextureWidth() {
|
||||||
return Math.max(maxTextureSize / getDevice().getScaleFactor(),
|
return Math.max(maxTextureSize / getDevice().getScaleFactor(),
|
||||||
getBounds().width);
|
getBounds().width);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getMaxTextureHeight() {
|
public int getMaxTextureHeight() {
|
||||||
return Math.max(maxTextureSize / getDevice().getScaleFactor(),
|
return Math.max(maxTextureSize / getDevice().getScaleFactor(),
|
||||||
getBounds().height);
|
getBounds().height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,8 +74,11 @@ import sun.awt.SunToolkit;
|
|||||||
import sun.awt.event.IgnorePaintEvent;
|
import sun.awt.event.IgnorePaintEvent;
|
||||||
import sun.awt.image.SunVolatileImage;
|
import sun.awt.image.SunVolatileImage;
|
||||||
import sun.java2d.SunGraphics2D;
|
import sun.java2d.SunGraphics2D;
|
||||||
|
import sun.java2d.macos.MacOSFlags;
|
||||||
|
import sun.java2d.metal.MTLRenderQueue;
|
||||||
import sun.java2d.opengl.OGLRenderQueue;
|
import sun.java2d.opengl.OGLRenderQueue;
|
||||||
import sun.java2d.pipe.Region;
|
import sun.java2d.pipe.Region;
|
||||||
|
import sun.java2d.pipe.RenderQueue;
|
||||||
import sun.util.logging.PlatformLogger;
|
import sun.util.logging.PlatformLogger;
|
||||||
|
|
||||||
public abstract class LWComponentPeer<T extends Component, D extends JComponent>
|
public abstract class LWComponentPeer<T extends Component, D extends JComponent>
|
||||||
@@ -1414,7 +1417,8 @@ public abstract class LWComponentPeer<T extends Component, D extends JComponent>
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected static final void flushOnscreenGraphics(){
|
protected static final void flushOnscreenGraphics(){
|
||||||
final OGLRenderQueue rq = OGLRenderQueue.getInstance();
|
RenderQueue rq = MacOSFlags.isMetalEnabled() ?
|
||||||
|
MTLRenderQueue.getInstance() : OGLRenderQueue.getInstance();
|
||||||
rq.lock();
|
rq.lock();
|
||||||
try {
|
try {
|
||||||
rq.flushNow();
|
rq.flushNow();
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@@ -29,11 +29,15 @@ import java.awt.*;
|
|||||||
import java.awt.event.FocusEvent;
|
import java.awt.event.FocusEvent;
|
||||||
|
|
||||||
import sun.java2d.SurfaceData;
|
import sun.java2d.SurfaceData;
|
||||||
|
import sun.java2d.macos.MacOSFlags;
|
||||||
|
import sun.java2d.metal.MTLLayer;
|
||||||
import sun.java2d.opengl.CGLLayer;
|
import sun.java2d.opengl.CGLLayer;
|
||||||
import sun.lwawt.LWWindowPeer;
|
import sun.lwawt.LWWindowPeer;
|
||||||
import sun.lwawt.PlatformWindow;
|
import sun.lwawt.PlatformWindow;
|
||||||
|
import sun.lwawt.macosx.CFRetainedResource;
|
||||||
import sun.util.logging.PlatformLogger;
|
import sun.util.logging.PlatformLogger;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Provides a lightweight implementation of the EmbeddedFrame.
|
* Provides a lightweight implementation of the EmbeddedFrame.
|
||||||
*/
|
*/
|
||||||
@@ -42,7 +46,7 @@ public class CPlatformEmbeddedFrame implements PlatformWindow {
|
|||||||
private static final PlatformLogger focusLogger = PlatformLogger.getLogger(
|
private static final PlatformLogger focusLogger = PlatformLogger.getLogger(
|
||||||
"sun.lwawt.macosx.focus.CPlatformEmbeddedFrame");
|
"sun.lwawt.macosx.focus.CPlatformEmbeddedFrame");
|
||||||
|
|
||||||
private CGLLayer windowLayer;
|
private CFRetainedResource windowLayer;
|
||||||
private LWWindowPeer peer;
|
private LWWindowPeer peer;
|
||||||
private CEmbeddedFrame target;
|
private CEmbeddedFrame target;
|
||||||
|
|
||||||
@@ -52,7 +56,11 @@ public class CPlatformEmbeddedFrame implements PlatformWindow {
|
|||||||
@Override // PlatformWindow
|
@Override // PlatformWindow
|
||||||
public void initialize(Window target, final LWWindowPeer peer, PlatformWindow owner) {
|
public void initialize(Window target, final LWWindowPeer peer, PlatformWindow owner) {
|
||||||
this.peer = peer;
|
this.peer = peer;
|
||||||
this.windowLayer = new CGLLayer(peer);
|
if (MacOSFlags.isMetalEnabled()) {
|
||||||
|
this.windowLayer = new MTLLayer(peer);
|
||||||
|
} else {
|
||||||
|
this.windowLayer = new CGLLayer(peer);
|
||||||
|
}
|
||||||
this.target = (CEmbeddedFrame)target;
|
this.target = (CEmbeddedFrame)target;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,12 +71,20 @@ public class CPlatformEmbeddedFrame implements PlatformWindow {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getLayerPtr() {
|
public long getLayerPtr() {
|
||||||
return windowLayer.getPointer();
|
if (MacOSFlags.isMetalEnabled()) {
|
||||||
|
return ((MTLLayer)windowLayer).getPointer();
|
||||||
|
} else {
|
||||||
|
return ((CGLLayer)windowLayer).getPointer();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
windowLayer.dispose();
|
if (MacOSFlags.isMetalEnabled()) {
|
||||||
|
((MTLLayer)windowLayer).dispose();
|
||||||
|
} else {
|
||||||
|
((CGLLayer)windowLayer).dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -99,12 +115,20 @@ public class CPlatformEmbeddedFrame implements PlatformWindow {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SurfaceData getScreenSurface() {
|
public SurfaceData getScreenSurface() {
|
||||||
return windowLayer.getSurfaceData();
|
if (MacOSFlags.isMetalEnabled()) {
|
||||||
|
return ((MTLLayer)windowLayer).getSurfaceData();
|
||||||
|
} else {
|
||||||
|
return ((CGLLayer)windowLayer).getSurfaceData();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SurfaceData replaceSurfaceData() {
|
public SurfaceData replaceSurfaceData() {
|
||||||
return windowLayer.replaceSurfaceData();
|
if (MacOSFlags.isMetalEnabled()) {
|
||||||
|
return ((MTLLayer)windowLayer).replaceSurfaceData();
|
||||||
|
} else {
|
||||||
|
return ((CGLLayer)windowLayer).replaceSurfaceData();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -35,9 +35,12 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
import sun.awt.CGraphicsEnvironment;
|
import sun.awt.CGraphicsEnvironment;
|
||||||
|
import sun.java2d.macos.MacOSFlags;
|
||||||
|
import sun.java2d.metal.MTLLayer;
|
||||||
|
import sun.lwawt.LWWindowPeer;
|
||||||
|
|
||||||
import sun.java2d.SurfaceData;
|
import sun.java2d.SurfaceData;
|
||||||
import sun.java2d.opengl.CGLLayer;
|
import sun.java2d.opengl.CGLLayer;
|
||||||
import sun.lwawt.LWWindowPeer;
|
|
||||||
|
|
||||||
public class CPlatformView extends CFRetainedResource {
|
public class CPlatformView extends CFRetainedResource {
|
||||||
private native long nativeCreateView(int x, int y, int width, int height, long windowLayerPtr);
|
private native long nativeCreateView(int x, int y, int width, int height, long windowLayerPtr);
|
||||||
@@ -48,7 +51,7 @@ public class CPlatformView extends CFRetainedResource {
|
|||||||
|
|
||||||
private LWWindowPeer peer;
|
private LWWindowPeer peer;
|
||||||
private SurfaceData surfaceData;
|
private SurfaceData surfaceData;
|
||||||
private CGLLayer windowLayer;
|
private CFRetainedResource windowLayer;
|
||||||
private CPlatformResponder responder;
|
private CPlatformResponder responder;
|
||||||
|
|
||||||
public CPlatformView() {
|
public CPlatformView() {
|
||||||
@@ -58,7 +61,7 @@ public class CPlatformView extends CFRetainedResource {
|
|||||||
public void initialize(LWWindowPeer peer, CPlatformResponder responder) {
|
public void initialize(LWWindowPeer peer, CPlatformResponder responder) {
|
||||||
initializeBase(peer, responder);
|
initializeBase(peer, responder);
|
||||||
|
|
||||||
this.windowLayer = createCGLayer();
|
this.windowLayer = MacOSFlags.isMetalEnabled()? createMTLLayer() : createCGLayer();
|
||||||
setPtr(nativeCreateView(0, 0, 0, 0, getWindowLayerPtr()));
|
setPtr(nativeCreateView(0, 0, 0, 0, getWindowLayerPtr()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,6 +69,11 @@ public class CPlatformView extends CFRetainedResource {
|
|||||||
return new CGLLayer(peer);
|
return new CGLLayer(peer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MTLLayer createMTLLayer() {
|
||||||
|
return new MTLLayer(peer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
protected void initializeBase(LWWindowPeer peer, CPlatformResponder responder) {
|
protected void initializeBase(LWWindowPeer peer, CPlatformResponder responder) {
|
||||||
this.peer = peer;
|
this.peer = peer;
|
||||||
this.responder = responder;
|
this.responder = responder;
|
||||||
@@ -96,7 +104,10 @@ public class CPlatformView extends CFRetainedResource {
|
|||||||
// PAINTING METHODS
|
// PAINTING METHODS
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
public SurfaceData replaceSurfaceData() {
|
public SurfaceData replaceSurfaceData() {
|
||||||
surfaceData = windowLayer.replaceSurfaceData();
|
surfaceData = (MacOSFlags.isMetalEnabled()) ?
|
||||||
|
((MTLLayer)windowLayer).replaceSurfaceData() :
|
||||||
|
((CGLLayer)windowLayer).replaceSurfaceData()
|
||||||
|
;
|
||||||
return surfaceData;
|
return surfaceData;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,7 +122,9 @@ public class CPlatformView extends CFRetainedResource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public long getWindowLayerPtr() {
|
public long getWindowLayerPtr() {
|
||||||
return windowLayer.getPointer();
|
return MacOSFlags.isMetalEnabled() ?
|
||||||
|
((MTLLayer)windowLayer).getPointer() :
|
||||||
|
((CGLLayer)windowLayer).getPointer();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAutoResizable(boolean toResize) {
|
public void setAutoResizable(boolean toResize) {
|
||||||
@@ -176,18 +189,18 @@ public class CPlatformView extends CFRetainedResource {
|
|||||||
|
|
||||||
if (event.getType() == CocoaConstants.NSScrollWheel) {
|
if (event.getType() == CocoaConstants.NSScrollWheel) {
|
||||||
responder.handleScrollEvent(x, y, absX, absY, event.getModifierFlags(),
|
responder.handleScrollEvent(x, y, absX, absY, event.getModifierFlags(),
|
||||||
event.getScrollDeltaX(), event.getScrollDeltaY(),
|
event.getScrollDeltaX(), event.getScrollDeltaY(),
|
||||||
event.getScrollPhase());
|
event.getScrollPhase());
|
||||||
} else {
|
} else {
|
||||||
responder.handleMouseEvent(event.getType(), event.getModifierFlags(), event.getButtonNumber(),
|
responder.handleMouseEvent(event.getType(), event.getModifierFlags(), event.getButtonNumber(),
|
||||||
event.getClickCount(), x, y,
|
event.getClickCount(), x, y,
|
||||||
absX, absY);
|
absX, absY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void deliverKeyEvent(NSEvent event) {
|
private void deliverKeyEvent(NSEvent event) {
|
||||||
responder.handleKeyEvent(event.getType(), event.getModifierFlags(), event.getCharacters(),
|
responder.handleKeyEvent(event.getType(), event.getModifierFlags(), event.getCharacters(),
|
||||||
event.getCharactersIgnoringModifiers(), event.getKeyCode(), true, false);
|
event.getCharactersIgnoringModifiers(), event.getKeyCode(), true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import sun.awt.AWTAccessor;
|
|||||||
import sun.awt.IconInfo;
|
import sun.awt.IconInfo;
|
||||||
import sun.java2d.SunGraphics2D;
|
import sun.java2d.SunGraphics2D;
|
||||||
import sun.java2d.SurfaceData;
|
import sun.java2d.SurfaceData;
|
||||||
|
import sun.java2d.metal.MTLLayer;
|
||||||
import sun.java2d.opengl.CGLLayer;
|
import sun.java2d.opengl.CGLLayer;
|
||||||
import sun.lwawt.LWWindowPeer;
|
import sun.lwawt.LWWindowPeer;
|
||||||
import sun.lwawt.PlatformEventNotifier;
|
import sun.lwawt.PlatformEventNotifier;
|
||||||
@@ -222,8 +223,8 @@ public final class CWarningWindow extends CPlatformWindow
|
|||||||
owner.execute(ownerPtr -> {
|
owner.execute(ownerPtr -> {
|
||||||
execute(ptr -> {
|
execute(ptr -> {
|
||||||
CWrapper.NSWindow.orderWindow(ptr,
|
CWrapper.NSWindow.orderWindow(ptr,
|
||||||
CWrapper.NSWindow.NSWindowAbove,
|
CWrapper.NSWindow.NSWindowAbove,
|
||||||
ownerPtr);
|
ownerPtr);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,7 +367,7 @@ public final class CWarningWindow extends CPlatformWindow
|
|||||||
currentSize = newSize;
|
currentSize = newSize;
|
||||||
IconInfo ico = getSecurityIconInfo(currentSize, 0);
|
IconInfo ico = getSecurityIconInfo(currentSize, 0);
|
||||||
AWTAccessor.getWindowAccessor().setSecurityWarningSize(
|
AWTAccessor.getWindowAccessor().setSecurityWarningSize(
|
||||||
ownerWindow, ico.getWidth(), ico.getHeight());
|
ownerWindow, ico.getWidth(), ico.getHeight());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -361,7 +379,7 @@ public final class CWarningWindow extends CPlatformWindow
|
|||||||
}
|
}
|
||||||
|
|
||||||
return new SunGraphics2D(sd, SystemColor.windowText, SystemColor.window,
|
return new SunGraphics2D(sd, SystemColor.windowText, SystemColor.window,
|
||||||
ownerWindow.getFont());
|
ownerWindow.getFont());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -108,6 +108,8 @@ import sun.awt.PlatformGraphicsInfo;
|
|||||||
import sun.awt.SunToolkit;
|
import sun.awt.SunToolkit;
|
||||||
import sun.awt.datatransfer.DataTransferer;
|
import sun.awt.datatransfer.DataTransferer;
|
||||||
import sun.awt.util.ThreadGroupUtils;
|
import sun.awt.util.ThreadGroupUtils;
|
||||||
|
import sun.java2d.macos.MacOSFlags;
|
||||||
|
import sun.java2d.metal.MTLRenderQueue;
|
||||||
import sun.java2d.opengl.OGLRenderQueue;
|
import sun.java2d.opengl.OGLRenderQueue;
|
||||||
import sun.lwawt.LWComponentPeer;
|
import sun.lwawt.LWComponentPeer;
|
||||||
import sun.lwawt.LWCursorManager;
|
import sun.lwawt.LWCursorManager;
|
||||||
@@ -488,7 +490,11 @@ public final class LWCToolkit extends LWToolkit {
|
|||||||
@Override
|
@Override
|
||||||
public void sync() {
|
public void sync() {
|
||||||
// flush the OGL pipeline (this is a no-op if OGL is not enabled)
|
// 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
|
// setNeedsDisplay() selector was sent to the appropriate CALayer so now
|
||||||
// we have to flush the native selectors queue.
|
// we have to flush the native selectors queue.
|
||||||
flushNativeSelectors();
|
flushNativeSelectors();
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@@ -29,6 +29,7 @@
|
|||||||
|
|
||||||
#import <JavaNativeFoundation/JavaNativeFoundation.h>
|
#import <JavaNativeFoundation/JavaNativeFoundation.h>
|
||||||
#import <QuartzCore/CATransaction.h>
|
#import <QuartzCore/CATransaction.h>
|
||||||
|
#import <QuartzCore/CAMetalLayer.h>
|
||||||
|
|
||||||
@implementation AWTSurfaceLayers
|
@implementation AWTSurfaceLayers
|
||||||
|
|
||||||
@@ -67,10 +68,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Updates back buffer size of the layer if it's an OpenGL layer
|
// Updates back buffer size of the layer if it's an OpenGL/Metal layer
|
||||||
// including all OpenGL sublayers
|
// including all OpenGL/Metal sublayers
|
||||||
+ (void) repaintLayersRecursively:(CALayer*)aLayer {
|
+ (void) repaintLayersRecursively:(CALayer*)aLayer {
|
||||||
if ([aLayer isKindOfClass:[CAOpenGLLayer class]]) {
|
if ([aLayer isKindOfClass:[CAOpenGLLayer class]] ||
|
||||||
|
[aLayer isKindOfClass:[CAMetalLayer class]]) {
|
||||||
[aLayer setNeedsDisplay];
|
[aLayer setNeedsDisplay];
|
||||||
}
|
}
|
||||||
for(CALayer *child in aLayer.sublayers) {
|
for(CALayer *child in aLayer.sublayers) {
|
||||||
@@ -92,7 +94,7 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Class: sun_lwawt_macosx_CPlatformComponent
|
* Class: sun_lwawt_macosx_CPlatformComponent
|
||||||
* Method: nativeCreateLayer
|
* Method: nativeCreateComponent
|
||||||
* Signature: ()J
|
* Signature: ()J
|
||||||
*/
|
*/
|
||||||
JNIEXPORT jlong JNICALL
|
JNIEXPORT jlong JNICALL
|
||||||
|
|||||||
@@ -37,6 +37,8 @@
|
|||||||
#import <Carbon/Carbon.h>
|
#import <Carbon/Carbon.h>
|
||||||
#import <JavaNativeFoundation/JavaNativeFoundation.h>
|
#import <JavaNativeFoundation/JavaNativeFoundation.h>
|
||||||
|
|
||||||
|
jboolean metalEnabled = JNI_FALSE;
|
||||||
|
|
||||||
@interface AWTView()
|
@interface AWTView()
|
||||||
@property (retain) CDropTarget *_dropTarget;
|
@property (retain) CDropTarget *_dropTarget;
|
||||||
@property (retain) CDragSource *_dragSource;
|
@property (retain) CDragSource *_dragSource;
|
||||||
@@ -52,6 +54,8 @@
|
|||||||
//#define IM_DEBUG TRUE
|
//#define IM_DEBUG TRUE
|
||||||
//#define EXTRA_DEBUG
|
//#define EXTRA_DEBUG
|
||||||
|
|
||||||
|
#define METAL_DEBUG
|
||||||
|
|
||||||
static BOOL shouldUsePressAndHold() {
|
static BOOL shouldUsePressAndHold() {
|
||||||
static int shouldUsePressAndHold = -1;
|
static int shouldUsePressAndHold = -1;
|
||||||
if (shouldUsePressAndHold != -1) return shouldUsePressAndHold;
|
if (shouldUsePressAndHold != -1) return shouldUsePressAndHold;
|
||||||
@@ -66,6 +70,7 @@ static BOOL shouldUsePressAndHold() {
|
|||||||
@synthesize cglLayer;
|
@synthesize cglLayer;
|
||||||
@synthesize mouseIsOver;
|
@synthesize mouseIsOver;
|
||||||
|
|
||||||
|
|
||||||
// Note: Must be called on main (AppKit) thread only
|
// Note: Must be called on main (AppKit) thread only
|
||||||
- (id) initWithRect: (NSRect) rect
|
- (id) initWithRect: (NSRect) rect
|
||||||
platformView: (jobject) cPlatformView
|
platformView: (jobject) cPlatformView
|
||||||
@@ -1499,3 +1504,19 @@ JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_CPlatformView_nativeIsViewUnder
|
|||||||
|
|
||||||
return underMouse;
|
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);
|
JNF_COCOA_EXIT(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern jboolean metalEnabled;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Class: sun_lwawt_macosx_CPlatformWindow
|
* Class: sun_lwawt_macosx_CPlatformWindow
|
||||||
* Method: nativeGetNSWindowInsets
|
* Method: nativeGetNSWindowInsets
|
||||||
|
|||||||
86
src/java.desktop/macosx/native/libawt_lwawt/awt/common.h
Normal file
86
src/java.desktop/macosx/native/libawt_lwawt/awt/common.h
Normal file
@@ -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 COMMON_H
|
||||||
|
#define COMMON_H
|
||||||
|
|
||||||
|
#include <simd/SIMD.h>
|
||||||
|
|
||||||
|
#define PGRAM_VERTEX_COUNT 6
|
||||||
|
#define QUAD_VERTEX_COUNT 4
|
||||||
|
|
||||||
|
enum VertexAttributes {
|
||||||
|
VertexAttributePosition = 0,
|
||||||
|
VertexAttributeTexPos = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
enum BufferIndex {
|
||||||
|
MeshVertexBuffer = 0,
|
||||||
|
FrameUniformBuffer = 1,
|
||||||
|
MatrixBuffer = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FrameUniforms {
|
||||||
|
vector_float4 color;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TransformMatrix {
|
||||||
|
matrix_float4x4 transformMatrix;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GradFrameUniforms {
|
||||||
|
vector_float3 params;
|
||||||
|
vector_float4 color1;
|
||||||
|
vector_float4 color2;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Vertex {
|
||||||
|
float position[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TxtVertex {
|
||||||
|
float position[2];
|
||||||
|
float txtpos[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TxtFrameUniforms {
|
||||||
|
vector_float4 color;
|
||||||
|
int mode;
|
||||||
|
int isSrcOpaque;
|
||||||
|
int isDstOpaque;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AnchorData
|
||||||
|
{
|
||||||
|
vector_float3 xParams;
|
||||||
|
vector_float3 yParams;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LCDFrameUniforms {
|
||||||
|
vector_float3 src_adj;
|
||||||
|
vector_float3 gamma;
|
||||||
|
vector_float3 invgamma;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
307
src/java.desktop/macosx/native/libawt_lwawt/awt/shaders.metal
Normal file
307
src/java.desktop/macosx/native/libawt_lwawt/awt/shaders.metal
Normal file
@@ -0,0 +1,307 @@
|
|||||||
|
/*
|
||||||
|
* 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 {
|
||||||
|
float2 position [[attribute(VertexAttributePosition)]];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TxtVertexInput {
|
||||||
|
float2 position [[attribute(VertexAttributePosition)]];
|
||||||
|
float2 texCoords [[attribute(VertexAttributeTexPos)]];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ColShaderInOut {
|
||||||
|
float4 position [[position]];
|
||||||
|
half4 color;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StencilShaderInOut {
|
||||||
|
float4 position [[position]];
|
||||||
|
char color;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TxtShaderInOut {
|
||||||
|
float4 position [[position]];
|
||||||
|
float2 texCoords;
|
||||||
|
float2 tpCoords;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GradShaderInOut {
|
||||||
|
float4 position [[position]];
|
||||||
|
float2 texCoords;
|
||||||
|
};
|
||||||
|
|
||||||
|
vertex ColShaderInOut vert_col(VertexInput in [[stage_in]],
|
||||||
|
constant FrameUniforms& uniforms [[buffer(FrameUniformBuffer)]],
|
||||||
|
constant TransformMatrix& transform [[buffer(MatrixBuffer)]]) {
|
||||||
|
ColShaderInOut out;
|
||||||
|
float4 pos4 = float4(in.position, 0.0, 1.0);
|
||||||
|
out.position = transform.transformMatrix*pos4;
|
||||||
|
out.color = half4(uniforms.color.r, uniforms.color.g, uniforms.color.b, uniforms.color.a);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
vertex StencilShaderInOut vert_stencil(VertexInput in [[stage_in]],
|
||||||
|
constant FrameUniforms& uniforms [[buffer(FrameUniformBuffer)]],
|
||||||
|
constant TransformMatrix& transform [[buffer(MatrixBuffer)]]) {
|
||||||
|
StencilShaderInOut out;
|
||||||
|
float4 pos4 = float4(in.position, 0.0, 1.0);
|
||||||
|
out.position = transform.transformMatrix * pos4;
|
||||||
|
out.color = 0xFF;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
vertex GradShaderInOut vert_grad(VertexInput in [[stage_in]], constant TransformMatrix& transform [[buffer(MatrixBuffer)]]) {
|
||||||
|
GradShaderInOut out;
|
||||||
|
float4 pos4 = float4(in.position, 0.0, 1.0);
|
||||||
|
out.position = transform.transformMatrix*pos4;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
vertex TxtShaderInOut vert_txt(TxtVertexInput in [[stage_in]], constant TransformMatrix& transform [[buffer(MatrixBuffer)]]) {
|
||||||
|
TxtShaderInOut out;
|
||||||
|
float4 pos4 = float4(in.position, 0.0, 1.0);
|
||||||
|
out.position = transform.transformMatrix*pos4;
|
||||||
|
out.texCoords = in.texCoords;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
vertex TxtShaderInOut vert_txt_tp(TxtVertexInput in [[stage_in]], constant AnchorData& anchorData [[buffer(FrameUniformBuffer)]], constant TransformMatrix& transform [[buffer(MatrixBuffer)]])
|
||||||
|
{
|
||||||
|
TxtShaderInOut out;
|
||||||
|
float4 pos4 = float4(in.position, 0.0, 1.0);
|
||||||
|
out.position = transform.transformMatrix * pos4;
|
||||||
|
|
||||||
|
// Compute texture coordinates here w.r.t. anchor rect of texture paint
|
||||||
|
out.tpCoords.x = (anchorData.xParams[0] * in.position.x) +
|
||||||
|
(anchorData.xParams[1] * in.position.y) +
|
||||||
|
(anchorData.xParams[2] * out.position.w);
|
||||||
|
out.tpCoords.y = (anchorData.yParams[0] * in.position.x) +
|
||||||
|
(anchorData.yParams[1] * in.position.y) +
|
||||||
|
(anchorData.yParams[2] * out.position.w);
|
||||||
|
out.texCoords = in.texCoords;
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
vertex GradShaderInOut vert_txt_grad(TxtVertexInput in [[stage_in]],
|
||||||
|
constant TransformMatrix& transform [[buffer(MatrixBuffer)]]) {
|
||||||
|
GradShaderInOut out;
|
||||||
|
float4 pos4 = float4(in.position, 0.0, 1.0);
|
||||||
|
out.position = transform.transformMatrix*pos4;
|
||||||
|
out.texCoords = in.texCoords;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment half4 frag_col(ColShaderInOut in [[stage_in]]) {
|
||||||
|
return in.color;
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment unsigned int frag_stencil(StencilShaderInOut in [[stage_in]]) {
|
||||||
|
return in.color;
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment half4 frag_txt(
|
||||||
|
TxtShaderInOut vert [[stage_in]],
|
||||||
|
texture2d<float, access::sample> renderTexture [[texture(0)]],
|
||||||
|
constant TxtFrameUniforms& uniforms [[buffer(1)]]
|
||||||
|
)
|
||||||
|
{
|
||||||
|
constexpr sampler textureSampler (mag_filter::linear,
|
||||||
|
min_filter::linear);
|
||||||
|
float4 pixelColor = renderTexture.sample(textureSampler, vert.texCoords);
|
||||||
|
float srcA = uniforms.isSrcOpaque ? 1 : pixelColor.a;
|
||||||
|
// TODO: consider to make shaders without IF-conditions
|
||||||
|
if (uniforms.mode) {
|
||||||
|
float4 c = mix(pixelColor, uniforms.color, srcA);
|
||||||
|
return half4(c.r, c.g, c.b , c.a);
|
||||||
|
}
|
||||||
|
return half4(pixelColor.r, pixelColor.g, pixelColor.b, srcA);
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment half4 frag_txt_tp(TxtShaderInOut vert [[stage_in]],
|
||||||
|
texture2d<float, access::sample> renderTexture [[texture(0)]],
|
||||||
|
texture2d<float, access::sample> paintTexture [[texture(1)]])
|
||||||
|
{
|
||||||
|
constexpr sampler textureSampler (address::repeat,
|
||||||
|
mag_filter::nearest,
|
||||||
|
min_filter::nearest);
|
||||||
|
|
||||||
|
float4 renderColor = renderTexture.sample(textureSampler, vert.texCoords);
|
||||||
|
float4 paintColor = paintTexture.sample(textureSampler, vert.tpCoords);
|
||||||
|
return half4(paintColor.r*renderColor.a,
|
||||||
|
paintColor.g*renderColor.a,
|
||||||
|
paintColor.b*renderColor.a,
|
||||||
|
renderColor.a);
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment half4 frag_txt_grad(GradShaderInOut in [[stage_in]],
|
||||||
|
constant GradFrameUniforms& uniforms [[buffer(0)]],
|
||||||
|
texture2d<float, access::sample> renderTexture [[texture(0)]])
|
||||||
|
{
|
||||||
|
constexpr sampler textureSampler (address::repeat, mag_filter::nearest,
|
||||||
|
min_filter::nearest);
|
||||||
|
|
||||||
|
float4 renderColor = renderTexture.sample(textureSampler, in.texCoords);
|
||||||
|
|
||||||
|
float3 v = float3(in.position.x, in.position.y, 1);
|
||||||
|
float a = (dot(v,uniforms.params)-0.25)*2.0;
|
||||||
|
float4 c = mix(uniforms.color1, uniforms.color2, a);
|
||||||
|
return half4(c.r*renderColor.a,
|
||||||
|
c.g*renderColor.a,
|
||||||
|
c.b*renderColor.a,
|
||||||
|
renderColor.a);
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment half4 aa_frag_txt(
|
||||||
|
TxtShaderInOut vert [[stage_in]],
|
||||||
|
texture2d<float, access::sample> renderTexture [[texture(0)]],
|
||||||
|
constant TxtFrameUniforms& uniforms [[buffer(1)]]
|
||||||
|
)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment half4 frag_grad(GradShaderInOut in [[stage_in]],
|
||||||
|
constant GradFrameUniforms& uniforms [[buffer(0)]]) {
|
||||||
|
float3 v = float3(in.position.x, in.position.y, 1);
|
||||||
|
float a = (dot(v,uniforms.params)-0.25)*2.0;
|
||||||
|
float4 c = mix(uniforms.color1, uniforms.color2, a);
|
||||||
|
return half4(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
vertex TxtShaderInOut vert_tp(VertexInput in [[stage_in]],
|
||||||
|
constant AnchorData& anchorData [[buffer(FrameUniformBuffer)]],
|
||||||
|
constant TransformMatrix& transform [[buffer(MatrixBuffer)]])
|
||||||
|
{
|
||||||
|
TxtShaderInOut out;
|
||||||
|
float4 pos4 = float4(in.position, 0.0, 1.0);
|
||||||
|
out.position = transform.transformMatrix * pos4;
|
||||||
|
|
||||||
|
// Compute texture coordinates here w.r.t. anchor rect of texture paint
|
||||||
|
out.texCoords.x = (anchorData.xParams[0] * in.position.x) +
|
||||||
|
(anchorData.xParams[1] * in.position.y) +
|
||||||
|
(anchorData.xParams[2] * out.position.w);
|
||||||
|
out.texCoords.y = (anchorData.yParams[0] * in.position.x) +
|
||||||
|
(anchorData.yParams[1] * in.position.y) +
|
||||||
|
(anchorData.yParams[2] * out.position.w);
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment half4 frag_tp(
|
||||||
|
TxtShaderInOut vert [[stage_in]],
|
||||||
|
texture2d<float, access::sample> renderTexture [[texture(0)]])
|
||||||
|
{
|
||||||
|
constexpr sampler textureSampler (address::repeat,
|
||||||
|
mag_filter::nearest,
|
||||||
|
min_filter::nearest);
|
||||||
|
|
||||||
|
float4 pixelColor = renderTexture.sample(textureSampler, vert.texCoords);
|
||||||
|
return half4(pixelColor.r, pixelColor.g, pixelColor.b, 1.0);
|
||||||
|
|
||||||
|
// This implementation defaults alpha to 1.0 as if source is opaque
|
||||||
|
//TODO : implement alpha component value if source is transparent
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment half4 frag_tp_xorMode(
|
||||||
|
TxtShaderInOut vert [[stage_in]],
|
||||||
|
texture2d<float, access::sample> renderTexture [[texture(0)]],
|
||||||
|
constant int& xorColor[[buffer(0)]])
|
||||||
|
{
|
||||||
|
constexpr sampler textureSampler (address::repeat,
|
||||||
|
mag_filter::nearest,
|
||||||
|
min_filter::nearest);
|
||||||
|
|
||||||
|
float4 pixelColor = renderTexture.sample(textureSampler, vert.texCoords);
|
||||||
|
|
||||||
|
pixelColor.r = float( (unsigned char)(pixelColor.r * 255.0) ^ ((xorColor >> 16) & 0xFF) ) / 255.0f;
|
||||||
|
pixelColor.g = float( (unsigned char)(pixelColor.g * 255.0) ^ ((xorColor >> 8) & 0xFF)) / 255.0f;
|
||||||
|
pixelColor.b = float( (unsigned char)(pixelColor.b * 255.0) ^ (xorColor & 0xFF)) / 255.0f;
|
||||||
|
pixelColor.a = 1.0;
|
||||||
|
|
||||||
|
return half4(pixelColor.r, pixelColor.g, pixelColor.b, 1.0);
|
||||||
|
|
||||||
|
// This implementation defaults alpha to 1.0 as if source is opaque
|
||||||
|
//TODO : implement alpha component value if source is transparent
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The variables involved in the equation can be expressed as follows:
|
||||||
|
*
|
||||||
|
* Cs = Color component of the source (foreground color) [0.0, 1.0]
|
||||||
|
* Cd = Color component of the destination (background color) [0.0, 1.0]
|
||||||
|
* Cr = Color component to be written to the destination [0.0, 1.0]
|
||||||
|
* Ag = Glyph alpha (aka intensity or coverage) [0.0, 1.0]
|
||||||
|
* Ga = Gamma adjustment in the range [1.0, 2.5]
|
||||||
|
* (^ means raised to the power)
|
||||||
|
*
|
||||||
|
* And here is the theoretical equation approximated by this shader:
|
||||||
|
*
|
||||||
|
* Cr = (Ag*(Cs^Ga) + (1-Ag)*(Cd^Ga)) ^ (1/Ga)
|
||||||
|
*/
|
||||||
|
fragment float4 lcd_color(
|
||||||
|
TxtShaderInOut vert [[stage_in]],
|
||||||
|
texture2d<float, access::sample> glyphTexture [[texture(0)]],
|
||||||
|
texture2d<float, access::sample> dstTexture [[texture(1)]],
|
||||||
|
constant LCDFrameUniforms& uniforms [[buffer(1)]])
|
||||||
|
{
|
||||||
|
float3 src_adj = uniforms.src_adj;
|
||||||
|
float3 gamma = uniforms.gamma;
|
||||||
|
float3 invgamma = uniforms.invgamma;
|
||||||
|
|
||||||
|
constexpr sampler glyphTextureSampler (mag_filter::linear,
|
||||||
|
min_filter::linear);
|
||||||
|
|
||||||
|
// load the RGB value from the glyph image at the current texcoord
|
||||||
|
float3 glyph_clr = float3(glyphTexture.sample(glyphTextureSampler, vert.texCoords));
|
||||||
|
|
||||||
|
if (glyph_clr.r == 0.0f && glyph_clr.g == 0.0f && glyph_clr.b == 0.0f) {
|
||||||
|
// zero coverage, so skip this fragment
|
||||||
|
discard_fragment();
|
||||||
|
}
|
||||||
|
constexpr sampler dstTextureSampler (mag_filter::linear,
|
||||||
|
min_filter::linear);
|
||||||
|
// load the RGB value from the corresponding destination pixel
|
||||||
|
float3 dst_clr = float3(dstTexture.sample(dstTextureSampler, vert.texCoords));
|
||||||
|
|
||||||
|
// gamma adjust the dest color
|
||||||
|
float3 dst_adj = pow(dst_clr.rgb, gamma);
|
||||||
|
|
||||||
|
// linearly interpolate the three color values
|
||||||
|
float3 result = mix(dst_adj, src_adj, glyph_clr);
|
||||||
|
|
||||||
|
// gamma re-adjust the resulting color (alpha is always set to 1.0)
|
||||||
|
return float4(pow(result.rgb, invgamma), 1.0);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
#ifndef EncoderManager_h_Included
|
||||||
|
#define EncoderManager_h_Included
|
||||||
|
|
||||||
|
#import <Metal/Metal.h>
|
||||||
|
|
||||||
|
#include <jni.h>
|
||||||
|
#include "MTLSurfaceDataBase.h"
|
||||||
|
|
||||||
|
@class MTLContex;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The EncoderManager class used to obtain MTLRenderCommandEncoder (or MTLBlitCommandEncoder) corresponding
|
||||||
|
* to the current state of MTLContext.
|
||||||
|
*
|
||||||
|
* Due to performance issues (creation of MTLRenderCommandEncoder isn't cheap), each getXXXEncoder invocation
|
||||||
|
* updates properties of common (cached) encoder and returns this encoder.
|
||||||
|
*
|
||||||
|
* Base method getEncoder does the following:
|
||||||
|
* 1. Checks whether common encoder must be closed and recreated (some of encoder properties is 'persistent',
|
||||||
|
* for example destination, stencil, or any other property of MTLRenderPassDescriptor)
|
||||||
|
* 2. Updates 'mutable' properties encoder: pipelineState (with corresponding buffers), clip, transform, e.t.c. To avoid
|
||||||
|
* unnecessary calls of [encoder setXXX] this manager compares requested state with cached one.
|
||||||
|
* */
|
||||||
|
@interface EncoderManager : NSObject
|
||||||
|
- (id _Nonnull)init;
|
||||||
|
- (void)dealloc;
|
||||||
|
|
||||||
|
- (void)setContext:(MTLContex * _Nonnull)mtlc;
|
||||||
|
|
||||||
|
// returns encoder that renders/fills geometry with current paint and composite
|
||||||
|
- (id<MTLRenderCommandEncoder> _Nonnull)getRenderEncoder:(const BMTLSDOps * _Nonnull)dstOps;
|
||||||
|
|
||||||
|
- (id<MTLRenderCommandEncoder> _Nonnull)getAARenderEncoder:(const BMTLSDOps * _Nonnull)dstOps;
|
||||||
|
|
||||||
|
- (id<MTLRenderCommandEncoder> _Nonnull)getRenderEncoder:(id<MTLTexture> _Nonnull)dest
|
||||||
|
isDstOpaque:(bool)isOpaque;
|
||||||
|
|
||||||
|
// returns encoder that renders/fills geometry with current composite and with given texture
|
||||||
|
// (user must call [encoder setFragmentTexture] before any rendering)
|
||||||
|
- (id<MTLRenderCommandEncoder> _Nonnull)getTextureEncoder:(const BMTLSDOps * _Nonnull)dstOps
|
||||||
|
isSrcOpaque:(bool)isSrcOpaque;
|
||||||
|
|
||||||
|
- (id<MTLRenderCommandEncoder> _Nonnull)getTextureEncoder:(id<MTLTexture> _Nonnull)dest
|
||||||
|
isSrcOpaque:(bool)isSrcOpaque
|
||||||
|
isDstOpaque:(bool)isDstOpaque;
|
||||||
|
|
||||||
|
- (id<MTLRenderCommandEncoder> _Nonnull)getTextureEncoder:(id<MTLTexture> _Nonnull)dest
|
||||||
|
isSrcOpaque:(bool)isSrcOpaque
|
||||||
|
isDstOpaque:(bool)isDstOpaque
|
||||||
|
isAA:(jboolean)isAA;
|
||||||
|
|
||||||
|
// Base method to obtain any MTLRenderCommandEncoder
|
||||||
|
- (id<MTLRenderCommandEncoder> _Nonnull)
|
||||||
|
getEncoder:(id<MTLTexture> _Nonnull)dest
|
||||||
|
isOpaque:(jboolean)isOpaque
|
||||||
|
isTexture:(jboolean)isTexture
|
||||||
|
isAA:(jboolean)isAA
|
||||||
|
srcFlags:(const SurfaceRasterFlags *_Nullable)srcFlags;
|
||||||
|
|
||||||
|
- (id<MTLBlitCommandEncoder> _Nonnull)createBlitEncoder;
|
||||||
|
|
||||||
|
- (void)endEncoder;
|
||||||
|
@end
|
||||||
|
|
||||||
|
#endif // EncoderManager_h_Included
|
||||||
@@ -0,0 +1,462 @@
|
|||||||
|
#include "EncoderManager.h"
|
||||||
|
#include "MTLContext.h"
|
||||||
|
#include "sun_java2d_SunGraphics2D.h"
|
||||||
|
#import "common.h"
|
||||||
|
|
||||||
|
// NOTE: uncomment to disable comparing cached encoder states with requested (for debugging)
|
||||||
|
// #define ALWAYS_UPDATE_ENCODER_STATES
|
||||||
|
|
||||||
|
const SurfaceRasterFlags defaultRasterFlags = { JNI_FALSE, JNI_TRUE };
|
||||||
|
|
||||||
|
// Internal utility class that represents the set of 'mutable' encoder properties
|
||||||
|
@interface EncoderStates : NSObject
|
||||||
|
@property (readonly) MTLClip * clip;
|
||||||
|
|
||||||
|
- (id)init;
|
||||||
|
- (void)dealloc;
|
||||||
|
|
||||||
|
- (void)reset:(id<MTLTexture>)destination
|
||||||
|
isDstOpaque:(jboolean)isDstOpaque
|
||||||
|
isDstPremultiplied:(jboolean)isDstPremultiplied
|
||||||
|
isAA:(jboolean)isAA;
|
||||||
|
|
||||||
|
- (void)updateEncoder:(id<MTLRenderCommandEncoder>)encoder
|
||||||
|
paint:(MTLPaint *)paint
|
||||||
|
composite:(MTLComposite *)composite
|
||||||
|
isTexture:(jboolean)isTexture
|
||||||
|
isAA:(jboolean)isAA
|
||||||
|
srcFlags:(const SurfaceRasterFlags * _Nullable)srcFlags
|
||||||
|
clip:(MTLClip *)clip
|
||||||
|
transform:(MTLTransform *)transform
|
||||||
|
forceUpdate:(jboolean)forceUpdate;
|
||||||
|
@property jboolean aa;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation EncoderStates {
|
||||||
|
MTLPipelineStatesStorage * _pipelineStateStorage;
|
||||||
|
id<MTLDevice> _device;
|
||||||
|
|
||||||
|
// Persistent encoder properties
|
||||||
|
id<MTLTexture> _destination;
|
||||||
|
SurfaceRasterFlags _dstFlags;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Cached 'mutable' states of encoder
|
||||||
|
//
|
||||||
|
|
||||||
|
// Composite rule and source raster flags (it affects the CAD-multipliers (of pipelineState))
|
||||||
|
MTLComposite * _composite;
|
||||||
|
SurfaceRasterFlags _srcFlags;
|
||||||
|
|
||||||
|
// Paint mode (it affects shaders (of pipelineState) and corresponding buffers)
|
||||||
|
MTLPaint * _paint;
|
||||||
|
|
||||||
|
// If true, indicates that encoder is used for texture drawing (user must do [encoder setFragmentTexture:] before drawing)
|
||||||
|
jboolean _isTexture;
|
||||||
|
jboolean _isAA;
|
||||||
|
|
||||||
|
// Clip rect or stencil
|
||||||
|
MTLClip * _clip;
|
||||||
|
|
||||||
|
// Transform (affects transformation inside vertex shader)
|
||||||
|
MTLTransform * _transform;
|
||||||
|
}
|
||||||
|
@synthesize aa = _isAA;
|
||||||
|
|
||||||
|
- (id)init {
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
_destination = nil;
|
||||||
|
_composite = [[MTLComposite alloc] init];
|
||||||
|
_paint = [[MTLPaint alloc] init];
|
||||||
|
_transform = [[MTLTransform alloc] init];
|
||||||
|
_clip = [[MTLClip alloc] init];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)dealloc {
|
||||||
|
[_composite release];
|
||||||
|
[_paint release];
|
||||||
|
[_transform release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setContext:(MTLContext * _Nonnull)mtlc {
|
||||||
|
self->_pipelineStateStorage = mtlc.pipelineStateStorage;
|
||||||
|
self->_device = mtlc.device;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)reset:(id<MTLTexture>)destination
|
||||||
|
isDstOpaque:(jboolean)isDstOpaque
|
||||||
|
isDstPremultiplied:(jboolean)isDstPremultiplied
|
||||||
|
isAA:(jboolean)isAA {
|
||||||
|
_destination = destination;
|
||||||
|
_dstFlags.isOpaque = isDstOpaque;
|
||||||
|
_dstFlags.isPremultiplied = isDstPremultiplied;
|
||||||
|
_isAA = isAA;
|
||||||
|
// NOTE: probably it's better to invalidate/reset all cached states now
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)updateEncoder:(id<MTLRenderCommandEncoder>)encoder
|
||||||
|
paint:(MTLPaint *)paint
|
||||||
|
composite:(MTLComposite *)composite
|
||||||
|
isTexture:(jboolean)isTexture
|
||||||
|
isAA:(jboolean)isAA
|
||||||
|
srcFlags:(const SurfaceRasterFlags * _Nullable)srcFlags
|
||||||
|
clip:(MTLClip *)clip
|
||||||
|
transform:(MTLTransform *)transform
|
||||||
|
forceUpdate:(jboolean)forceUpdate
|
||||||
|
{
|
||||||
|
// 1. Process special case for stencil mask generation
|
||||||
|
if (clip.stencilMaskGenerationInProgress == JNI_TRUE) {
|
||||||
|
// use separate pipeline state for stencil generation
|
||||||
|
if (forceUpdate || (_clip.stencilMaskGenerationInProgress != JNI_TRUE)) {
|
||||||
|
[_clip copyFrom:clip];
|
||||||
|
[_clip setMaskGenerationPipelineState:encoder
|
||||||
|
destWidth:_destination.width
|
||||||
|
destHeight:_destination.height
|
||||||
|
pipelineStateStorage:_pipelineStateStorage];
|
||||||
|
}
|
||||||
|
|
||||||
|
[self updateTransform:encoder transform:transform forceUpdate:forceUpdate];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Otherwise update all 'mutable' properties of encoder
|
||||||
|
[self updatePipelineState:encoder
|
||||||
|
paint:paint
|
||||||
|
composite:composite
|
||||||
|
isStencilUsed:[clip isShape]
|
||||||
|
isTexture:isTexture
|
||||||
|
isAA:isAA
|
||||||
|
srcFlags:srcFlags
|
||||||
|
forceUpdate:forceUpdate];
|
||||||
|
[self updateTransform:encoder transform:transform forceUpdate:forceUpdate];
|
||||||
|
[self updateClip:encoder clip:clip forceUpdate:forceUpdate];
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Internal methods that update states when necessary (compare with cached states)
|
||||||
|
//
|
||||||
|
|
||||||
|
// Updates pipelineState (and corresponding buffers) with use of paint+composite+flags
|
||||||
|
- (void)updatePipelineState:(id<MTLRenderCommandEncoder>)encoder
|
||||||
|
paint:(MTLPaint *)paint
|
||||||
|
composite:(MTLComposite *)composite
|
||||||
|
isStencilUsed:(jboolean)isStencilUsed
|
||||||
|
isTexture:(jboolean)isTexture
|
||||||
|
isAA:(jboolean)isAA
|
||||||
|
srcFlags:(const SurfaceRasterFlags * _Nullable)srcFlags
|
||||||
|
forceUpdate:(jboolean)forceUpdate
|
||||||
|
{
|
||||||
|
if (srcFlags == NULL)
|
||||||
|
srcFlags = &defaultRasterFlags;
|
||||||
|
|
||||||
|
if (!forceUpdate
|
||||||
|
&& [_paint isEqual:paint]
|
||||||
|
&& [_composite isEqual:composite]
|
||||||
|
&& _isTexture == isTexture
|
||||||
|
&& _isAA == isAA
|
||||||
|
&& _srcFlags.isOpaque == srcFlags->isOpaque && _srcFlags.isPremultiplied == srcFlags->isPremultiplied)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[_paint copyFrom:paint];
|
||||||
|
[_composite copyFrom:composite];
|
||||||
|
_isTexture = isTexture;
|
||||||
|
_isAA = isAA;
|
||||||
|
_srcFlags = *srcFlags;
|
||||||
|
|
||||||
|
if ((jint)[composite getCompositeState] == sun_java2d_SunGraphics2D_COMP_XOR) {
|
||||||
|
[paint setXorModePipelineState:encoder
|
||||||
|
composite:_composite
|
||||||
|
isStencilUsed:isStencilUsed
|
||||||
|
isTexture:_isTexture
|
||||||
|
srcFlags:&_srcFlags
|
||||||
|
dstFlags:&_dstFlags
|
||||||
|
pipelineStateStorage:_pipelineStateStorage];
|
||||||
|
} else {
|
||||||
|
[paint setPipelineState:encoder
|
||||||
|
composite:_composite
|
||||||
|
isStencilUsed:isStencilUsed
|
||||||
|
isTexture:_isTexture
|
||||||
|
isAA:isAA
|
||||||
|
srcFlags:&_srcFlags
|
||||||
|
dstFlags:&_dstFlags
|
||||||
|
pipelineStateStorage:_pipelineStateStorage];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) updateClip:(id<MTLRenderCommandEncoder>)encoder clip:(MTLClip *)clip forceUpdate:(jboolean)forceUpdate
|
||||||
|
{
|
||||||
|
if (clip.stencilMaskGenerationInProgress == JNI_TRUE) {
|
||||||
|
// don't set setScissorOrStencil when generateion in progress
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!forceUpdate && [_clip isEqual:clip])
|
||||||
|
return;
|
||||||
|
|
||||||
|
[_clip copyFrom:clip];
|
||||||
|
[_clip setScissorOrStencil:encoder
|
||||||
|
destWidth:_destination.width
|
||||||
|
destHeight:_destination.height
|
||||||
|
device:_device];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)updateTransform:(id <MTLRenderCommandEncoder>)encoder
|
||||||
|
transform:(MTLTransform *)transform
|
||||||
|
forceUpdate:(jboolean)forceUpdate
|
||||||
|
{
|
||||||
|
if (!forceUpdate
|
||||||
|
&& [_transform isEqual:transform])
|
||||||
|
return;
|
||||||
|
|
||||||
|
[_transform copyFrom:transform];
|
||||||
|
[_transform setVertexMatrix:encoder
|
||||||
|
destWidth:_destination.width
|
||||||
|
destHeight:_destination.height];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation EncoderManager {
|
||||||
|
MTLContext * _mtlc; // used to obtain CommandBufferWrapper and Composite/Paint/Transform
|
||||||
|
|
||||||
|
id<MTLRenderCommandEncoder> _encoder;
|
||||||
|
|
||||||
|
// 'Persistent' properties of encoder
|
||||||
|
id<MTLTexture> _destination;
|
||||||
|
id<MTLTexture> _aaDestination;
|
||||||
|
BOOL _useStencil;
|
||||||
|
|
||||||
|
// 'Mutable' states of encoder
|
||||||
|
EncoderStates * _encoderStates;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id _Nonnull)init {
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
_encoder = nil;
|
||||||
|
_destination = nil;
|
||||||
|
_aaDestination = nil;
|
||||||
|
_useStencil = NO;
|
||||||
|
_encoderStates = [[EncoderStates alloc] init];
|
||||||
|
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)dealloc {
|
||||||
|
[_encoderStates release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setContext:(MTLContex * _Nonnull)mtlc {
|
||||||
|
self->_mtlc = mtlc;
|
||||||
|
[self->_encoderStates setContext:mtlc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id<MTLRenderCommandEncoder> _Nonnull) getRenderEncoder:(const BMTLSDOps * _Nonnull)dstOps
|
||||||
|
{
|
||||||
|
return [self getRenderEncoder:dstOps->pTexture isDstOpaque:dstOps->isOpaque];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id<MTLRenderCommandEncoder> _Nonnull)getAARenderEncoder:(const BMTLSDOps * _Nonnull)dstOps {
|
||||||
|
id<MTLTexture> dstTxt = dstOps->pTexture;
|
||||||
|
return [self getEncoder:dstTxt
|
||||||
|
isOpaque:dstOps->isOpaque
|
||||||
|
isTexture:JNI_FALSE
|
||||||
|
isAA:JNI_TRUE
|
||||||
|
srcFlags:NULL];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id<MTLRenderCommandEncoder> _Nonnull)getRenderEncoder:(id<MTLTexture> _Nonnull)dest
|
||||||
|
isDstOpaque:(bool)isOpaque
|
||||||
|
{
|
||||||
|
return [self getEncoder:dest
|
||||||
|
isOpaque:isOpaque
|
||||||
|
isTexture:JNI_FALSE
|
||||||
|
isAA:JNI_FALSE
|
||||||
|
srcFlags:NULL];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id<MTLRenderCommandEncoder> _Nonnull) getTextureEncoder:(const BMTLSDOps * _Nonnull)dstOps
|
||||||
|
isSrcOpaque:(bool)isSrcOpaque
|
||||||
|
{
|
||||||
|
return [self getTextureEncoder:dstOps->pTexture isSrcOpaque:isSrcOpaque isDstOpaque:dstOps->isOpaque];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id<MTLRenderCommandEncoder> _Nonnull) getTextureEncoder:(id<MTLTexture> _Nonnull)dest
|
||||||
|
isSrcOpaque:(bool)isSrcOpaque
|
||||||
|
isDstOpaque:(bool)isDstOpaque
|
||||||
|
isAA:(jboolean)isAA
|
||||||
|
{
|
||||||
|
SurfaceRasterFlags srcFlags = { isSrcOpaque, JNI_TRUE };
|
||||||
|
return [self getEncoder:dest
|
||||||
|
isOpaque:isDstOpaque
|
||||||
|
isTexture:JNI_TRUE
|
||||||
|
isAA:isAA
|
||||||
|
srcFlags:&srcFlags];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id<MTLRenderCommandEncoder> _Nonnull) getTextureEncoder:(id<MTLTexture> _Nonnull)dest
|
||||||
|
isSrcOpaque:(bool)isSrcOpaque
|
||||||
|
isDstOpaque:(bool)isDstOpaque
|
||||||
|
{
|
||||||
|
return [self getTextureEncoder:dest isSrcOpaque:isSrcOpaque isDstOpaque:isDstOpaque isAA:JNI_FALSE];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id<MTLRenderCommandEncoder> _Nonnull)
|
||||||
|
getEncoder:(id<MTLTexture> _Nonnull)dest
|
||||||
|
isOpaque:(jboolean)isOpaque
|
||||||
|
isTexture:(jboolean)isTexture
|
||||||
|
isAA:(jboolean)isAA
|
||||||
|
srcFlags:(const SurfaceRasterFlags *_Nullable)srcFlags {
|
||||||
|
//
|
||||||
|
// 1. check whether it's necessary to call endEncoder
|
||||||
|
//
|
||||||
|
jboolean needEnd = JNI_FALSE;
|
||||||
|
if (_encoder != nil) {
|
||||||
|
if (_destination != dest || isAA != _encoderStates.aa) {
|
||||||
|
J2dTraceLn2(J2D_TRACE_VERBOSE,
|
||||||
|
"end common encoder because of dest change: %p -> %p",
|
||||||
|
_destination, dest);
|
||||||
|
needEnd = JNI_TRUE;
|
||||||
|
} else if ((_useStencil == NO) != ([_mtlc.clip isShape] == NO)) {
|
||||||
|
// 1. When mode changes RECT -> SHAPE we must recreate encoder with
|
||||||
|
// stencilAttachment (todo: consider the case when current encoder already
|
||||||
|
// has stencil)
|
||||||
|
//
|
||||||
|
// 2. When mode changes SHAPE -> RECT it seems that we can use the same
|
||||||
|
// encoder with disabled stencil test, but [encoder
|
||||||
|
// setDepthStencilState:nil] causes crash, so we have to recreate encoder
|
||||||
|
// in such case
|
||||||
|
J2dTraceLn2(J2D_TRACE_VERBOSE,
|
||||||
|
"end common encoder because toggle stencil: %d -> %d",
|
||||||
|
(int)_useStencil, (int)[_mtlc.clip isShape]);
|
||||||
|
needEnd = JNI_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (needEnd)
|
||||||
|
[self endEncoder];
|
||||||
|
|
||||||
|
//
|
||||||
|
// 2. recreate encoder if necessary
|
||||||
|
//
|
||||||
|
jboolean forceUpdate = JNI_FALSE;
|
||||||
|
#ifdef ALWAYS_UPDATE_ENCODER_STATES
|
||||||
|
forceUpdate = JNI_TRUE;
|
||||||
|
#endif // ALWAYS_UPDATE_ENCODER_STATES
|
||||||
|
|
||||||
|
if (_encoder == nil) {
|
||||||
|
_destination = dest;
|
||||||
|
_useStencil = [_mtlc.clip isShape];
|
||||||
|
forceUpdate = JNI_TRUE;
|
||||||
|
|
||||||
|
MTLCommandBufferWrapper *cbw = [_mtlc getCommandBufferWrapper];
|
||||||
|
MTLRenderPassDescriptor *rpd =
|
||||||
|
[MTLRenderPassDescriptor renderPassDescriptor];
|
||||||
|
MTLRenderPassColorAttachmentDescriptor *ca = rpd.colorAttachments[0];
|
||||||
|
if (isAA && !isTexture) {
|
||||||
|
MTLTexturePoolItem *tiBuf = [_mtlc.texturePool getTexture:dest.width
|
||||||
|
height:dest.height
|
||||||
|
format:MTLPixelFormatBGRA8Unorm];
|
||||||
|
[cbw registerPooledTexture:tiBuf];
|
||||||
|
[tiBuf release];
|
||||||
|
_aaDestination = tiBuf.texture;
|
||||||
|
|
||||||
|
MTLTexturePoolItem *ti = [_mtlc.texturePool getTexture:dest.width
|
||||||
|
height:dest.height
|
||||||
|
format:_aaDestination.pixelFormat
|
||||||
|
isMultiSample:YES];
|
||||||
|
[cbw registerPooledTexture:ti];
|
||||||
|
[ti release];
|
||||||
|
ca.texture = ti.texture;
|
||||||
|
ca.resolveTexture = _aaDestination;
|
||||||
|
ca.clearColor = MTLClearColorMake(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
ca.loadAction = MTLLoadActionClear;
|
||||||
|
ca.storeAction = MTLStoreActionMultisampleResolve;
|
||||||
|
} else {
|
||||||
|
ca.texture = dest;
|
||||||
|
ca.loadAction = MTLLoadActionLoad;
|
||||||
|
ca.storeAction = MTLStoreActionStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_useStencil) {
|
||||||
|
// If you enable stencil testing or stencil writing, the
|
||||||
|
// MTLRenderPassDescriptor must include a stencil attachment.
|
||||||
|
rpd.stencilAttachment.texture = _mtlc.clip.stencilTextureRef;
|
||||||
|
rpd.stencilAttachment.loadAction = MTLLoadActionLoad;
|
||||||
|
rpd.stencilAttachment.storeAction = MTLStoreActionDontCare;
|
||||||
|
}
|
||||||
|
|
||||||
|
// J2dTraceLn1(J2D_TRACE_VERBOSE, "created render encoder to draw on
|
||||||
|
// tex=%p", dest);
|
||||||
|
_encoder = [[cbw getCommandBuffer] renderCommandEncoderWithDescriptor:rpd];
|
||||||
|
[rpd release];
|
||||||
|
|
||||||
|
[_encoderStates reset:dest
|
||||||
|
isDstOpaque:isOpaque
|
||||||
|
isDstPremultiplied:YES
|
||||||
|
isAA:isAA];
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// 3. update encoder states
|
||||||
|
//
|
||||||
|
[_encoderStates updateEncoder:_encoder
|
||||||
|
paint:_mtlc.paint
|
||||||
|
composite:_mtlc.composite
|
||||||
|
isTexture:isTexture
|
||||||
|
isAA:isAA
|
||||||
|
srcFlags:srcFlags
|
||||||
|
clip:_mtlc.clip
|
||||||
|
transform:_mtlc.transform
|
||||||
|
forceUpdate:forceUpdate];
|
||||||
|
|
||||||
|
return _encoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id<MTLBlitCommandEncoder> _Nonnull) createBlitEncoder {
|
||||||
|
[self endEncoder];
|
||||||
|
return [[[_mtlc getCommandBufferWrapper] getCommandBuffer] blitCommandEncoder];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) endEncoder {
|
||||||
|
if (_encoder != nil) {
|
||||||
|
[_encoder endEncoding];
|
||||||
|
[_encoder release];
|
||||||
|
_encoder = nil;
|
||||||
|
if (_aaDestination != nil) {
|
||||||
|
id<MTLTexture> aaDest = _aaDestination;
|
||||||
|
_aaDestination = nil;
|
||||||
|
NSUInteger _w = _destination.width;
|
||||||
|
NSUInteger _h = _destination.height;
|
||||||
|
_encoder = [self getTextureEncoder:_destination
|
||||||
|
isSrcOpaque:JNI_FALSE
|
||||||
|
isDstOpaque:JNI_TRUE
|
||||||
|
isAA:JNI_TRUE];
|
||||||
|
|
||||||
|
struct TxtVertex quadTxVerticesBuffer[] = {
|
||||||
|
{{0, 0}, {0, 0}},
|
||||||
|
{{0,_h}, {0, 1}},
|
||||||
|
{{_w, 0},{1, 0}},
|
||||||
|
{{0, _h},{0, 1}},
|
||||||
|
{{_w, _h}, {1, 1}},
|
||||||
|
{{_w, 0}, {1, 0}}
|
||||||
|
};
|
||||||
|
|
||||||
|
[_encoder setVertexBytes:quadTxVerticesBuffer length:sizeof(quadTxVerticesBuffer) atIndex:MeshVertexBuffer];
|
||||||
|
[_encoder setFragmentTexture:aaDest atIndex: 0];
|
||||||
|
[_encoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:6];
|
||||||
|
[_encoder endEncoding];
|
||||||
|
[_encoder release];
|
||||||
|
}
|
||||||
|
|
||||||
|
_encoder = nil;
|
||||||
|
_destination = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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,
|
||||||
|
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);
|
||||||
|
|
||||||
|
void drawTex2Tex(MTLContext *mtlc,
|
||||||
|
id<MTLTexture> src, id<MTLTexture> dst,
|
||||||
|
jboolean isSrcOpaque, jboolean isDstOpaque,
|
||||||
|
jint sx1, jint sy1, jint sx2, jint sy2,
|
||||||
|
jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2);
|
||||||
|
|
||||||
|
#endif /* MTLBlitLoops_h_Included */
|
||||||
@@ -0,0 +1,662 @@
|
|||||||
|
/*
|
||||||
|
* 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"
|
||||||
|
|
||||||
|
#import <Accelerate/Accelerate.h>
|
||||||
|
|
||||||
|
//#define TRACE_ISOBLIT
|
||||||
|
//#define TRACE_BLIT
|
||||||
|
//#define DEBUG_ISOBLIT
|
||||||
|
//#define DEBUG_BLIT
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
MTLPixelFormat format;
|
||||||
|
jboolean hasAlpha;
|
||||||
|
jboolean isPremult;
|
||||||
|
const uint8_t * permuteMap;
|
||||||
|
} MTLRasterFormatInfo;
|
||||||
|
|
||||||
|
// 0 denotes the alpha channel, 1 the red channel, 2 the green channel, and 3 the blue channel.
|
||||||
|
const uint8_t permuteMap_rgbx[4] = { 1, 2, 3, 0 };
|
||||||
|
const uint8_t permuteMap_bgrx[4] = { 3, 2, 1, 0 };
|
||||||
|
|
||||||
|
static uint8_t revertPerm(const uint8_t * perm, uint8_t pos) {
|
||||||
|
for (int c = 0; c < 4; ++c) {
|
||||||
|
if (perm[c] == pos)
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define uint2swizzle(channel) (channel == 0 ? MTLTextureSwizzleAlpha : (channel == 1 ? MTLTextureSwizzleRed : (channel == 2 ? MTLTextureSwizzleGreen : (channel == 3 ? MTLTextureSwizzleBlue : MTLTextureSwizzleZero))))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This table contains the "pixel formats" for all system memory surfaces
|
||||||
|
* that Metal is capable of handling, indexed by the "PF_" constants defined
|
||||||
|
* in MTLLSurfaceData.java. These pixel formats contain information that is
|
||||||
|
* passed to Metal when copying from a system memory ("Sw") surface to
|
||||||
|
* an Metal surface
|
||||||
|
*/
|
||||||
|
MTLRasterFormatInfo RasterFormatInfos[] = {
|
||||||
|
{ MTLPixelFormatBGRA8Unorm, 1, 0, NULL }, /* 0 - IntArgb */ // Argb (in java notation)
|
||||||
|
{ MTLPixelFormatBGRA8Unorm, 1, 1, NULL }, /* 1 - IntArgbPre */
|
||||||
|
{ MTLPixelFormatBGRA8Unorm, 0, 1, NULL }, /* 2 - IntRgb */ // xrgb
|
||||||
|
{ MTLPixelFormatBGRA8Unorm, 0, 1, permuteMap_rgbx }, /* 3 - IntRgbx */
|
||||||
|
{ MTLPixelFormatRGBA8Unorm, 0, 1, NULL }, /* 4 - IntBgr */ // xbgr
|
||||||
|
{ MTLPixelFormatBGRA8Unorm, 0, 1, permuteMap_bgrx }, /* 5 - IntBgrx */
|
||||||
|
|
||||||
|
// TODO: support 2-byte formats
|
||||||
|
// { GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV,
|
||||||
|
// 2, 0, 1, }, /* 7 - Ushort555Rgb */
|
||||||
|
// { GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1,
|
||||||
|
// 2, 0, 1, }, /* 8 - Ushort555Rgbx*/
|
||||||
|
// { GL_LUMINANCE, GL_UNSIGNED_BYTE,
|
||||||
|
// 1, 0, 1, }, /* 9 - ByteGray */
|
||||||
|
// { GL_LUMINANCE, GL_UNSIGNED_SHORT,
|
||||||
|
// 2, 0, 1, }, /*10 - UshortGray */
|
||||||
|
// { GL_BGR, GL_UNSIGNED_BYTE,
|
||||||
|
// 1, 0, 1, }, /*11 - ThreeByteBgr */
|
||||||
|
};
|
||||||
|
|
||||||
|
extern void J2dTraceImpl(int level, jboolean cr, const char *string, ...);
|
||||||
|
|
||||||
|
void fillTxQuad(
|
||||||
|
struct TxtVertex * txQuadVerts,
|
||||||
|
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;
|
||||||
|
|
||||||
|
txQuadVerts[0].position[0] = dx1;
|
||||||
|
txQuadVerts[0].position[1] = dy1;
|
||||||
|
txQuadVerts[0].txtpos[0] = nsx1;
|
||||||
|
txQuadVerts[0].txtpos[1] = nsy1;
|
||||||
|
|
||||||
|
txQuadVerts[1].position[0] = dx2;
|
||||||
|
txQuadVerts[1].position[1] = dy1;
|
||||||
|
txQuadVerts[1].txtpos[0] = nsx2;
|
||||||
|
txQuadVerts[1].txtpos[1] = nsy1;
|
||||||
|
|
||||||
|
txQuadVerts[2].position[0] = dx2;
|
||||||
|
txQuadVerts[2].position[1] = dy2;
|
||||||
|
txQuadVerts[2].txtpos[0] = nsx2;
|
||||||
|
txQuadVerts[2].txtpos[1] = nsy2;
|
||||||
|
|
||||||
|
txQuadVerts[3].position[0] = dx2;
|
||||||
|
txQuadVerts[3].position[1] = dy2;
|
||||||
|
txQuadVerts[3].txtpos[0] = nsx2;
|
||||||
|
txQuadVerts[3].txtpos[1] = nsy2;
|
||||||
|
|
||||||
|
txQuadVerts[4].position[0] = dx1;
|
||||||
|
txQuadVerts[4].position[1] = dy2;
|
||||||
|
txQuadVerts[4].txtpos[0] = nsx1;
|
||||||
|
txQuadVerts[4].txtpos[1] = nsy2;
|
||||||
|
|
||||||
|
txQuadVerts[5].position[0] = dx1;
|
||||||
|
txQuadVerts[5].position[1] = dy1;
|
||||||
|
txQuadVerts[5].txtpos[0] = nsx1;
|
||||||
|
txQuadVerts[5].txtpos[1] = nsy1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//#define TRACE_drawTex2Tex
|
||||||
|
|
||||||
|
void drawTex2Tex(MTLContext *mtlc,
|
||||||
|
id<MTLTexture> src, id<MTLTexture> dst,
|
||||||
|
jboolean isSrcOpaque, jboolean isDstOpaque,
|
||||||
|
jint sx1, jint sy1, jint sx2, jint sy2,
|
||||||
|
jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
|
||||||
|
{
|
||||||
|
#ifdef TRACE_drawTex2Tex
|
||||||
|
J2dRlsTraceLn2(J2D_TRACE_VERBOSE, "drawTex2Tex: src tex=%p, dst tex=%p", src, dst);
|
||||||
|
J2dRlsTraceLn4(J2D_TRACE_VERBOSE, " sw=%d sh=%d dw=%d dh=%d", src.width, src.height, dst.width, dst.height);
|
||||||
|
J2dRlsTraceLn4(J2D_TRACE_VERBOSE, " sx1=%d sy1=%d sx2=%d sy2=%d", sx1, sy1, sx2, sy2);
|
||||||
|
J2dRlsTraceLn4(J2D_TRACE_VERBOSE, " dx1=%f dy1=%f dx2=%f dy2=%f", dx1, dy1, dx2, dy2);
|
||||||
|
#endif //TRACE_drawTex2Tex
|
||||||
|
|
||||||
|
id<MTLRenderCommandEncoder> encoder = [mtlc.encoderManager getTextureEncoder:dst
|
||||||
|
isSrcOpaque:isSrcOpaque
|
||||||
|
isDstOpaque:isDstOpaque];
|
||||||
|
|
||||||
|
struct TxtVertex quadTxVerticesBuffer[6];
|
||||||
|
fillTxQuad(quadTxVerticesBuffer, 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];
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
id<MTLTexture> replaceTextureRegion(id<MTLTexture> dest, const SurfaceDataRasInfo * srcInfo, const MTLRasterFormatInfo * rfi, int dx1, int dy1, int dx2, int dy2) {
|
||||||
|
const int dw = dx2 - dx1;
|
||||||
|
const int dh = dy2 - dy1;
|
||||||
|
|
||||||
|
const void * raster = srcInfo->rasBase;
|
||||||
|
id<MTLTexture> result = nil;
|
||||||
|
if (rfi->permuteMap != NULL) {
|
||||||
|
#if defined(__MAC_10_15) && __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_15
|
||||||
|
if (@available(macOS 10.15, *)) {
|
||||||
|
@autoreleasepool {
|
||||||
|
const uint8_t swzRed = revertPerm(rfi->permuteMap, 1);
|
||||||
|
const uint8_t swzGreen = revertPerm(rfi->permuteMap, 2);
|
||||||
|
const uint8_t swzBlue = revertPerm(rfi->permuteMap, 3);
|
||||||
|
const uint8_t swzAlpha = revertPerm(rfi->permuteMap, 0);
|
||||||
|
MTLTextureSwizzleChannels swizzle = MTLTextureSwizzleChannelsMake(
|
||||||
|
uint2swizzle(swzRed),
|
||||||
|
uint2swizzle(swzGreen),
|
||||||
|
uint2swizzle(swzBlue),
|
||||||
|
rfi->hasAlpha ? uint2swizzle(swzAlpha) : MTLTextureSwizzleOne
|
||||||
|
);
|
||||||
|
result = [dest
|
||||||
|
newTextureViewWithPixelFormat:MTLPixelFormatBGRA8Unorm
|
||||||
|
textureType:MTLTextureType2D
|
||||||
|
levels:NSMakeRange(0, 1) slices:NSMakeRange(0, 1)
|
||||||
|
swizzle:swizzle];
|
||||||
|
J2dTraceLn5(J2D_TRACE_VERBOSE, "replaceTextureRegion [use swizzle for pooled]: %d, %d, %d, %d, hasA=%d",
|
||||||
|
swizzle.red, swizzle.green, swizzle.blue, swizzle.alpha, rfi->hasAlpha);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
#endif // __MAC_10_15 && __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_15
|
||||||
|
{
|
||||||
|
// perform raster conversion
|
||||||
|
// invoked only from rq-thread, so use static buffers
|
||||||
|
// but it's better to use thread-local buffers (or special buffer manager)
|
||||||
|
const int destRasterSize = dw*dh*4;
|
||||||
|
|
||||||
|
static int bufferSize = 0;
|
||||||
|
static void * buffer = NULL;
|
||||||
|
if (buffer == NULL || bufferSize < destRasterSize) {
|
||||||
|
bufferSize = destRasterSize;
|
||||||
|
buffer = realloc(buffer, bufferSize);
|
||||||
|
}
|
||||||
|
if (buffer == NULL) {
|
||||||
|
J2dTraceLn1(J2D_TRACE_ERROR, "replaceTextureRegion: can't alloc buffer for raster conversion, size=%d", bufferSize);
|
||||||
|
bufferSize = 0;
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
vImage_Buffer srcBuf;
|
||||||
|
srcBuf.height = dw;
|
||||||
|
srcBuf.width = dh;
|
||||||
|
srcBuf.rowBytes = srcInfo->scanStride;
|
||||||
|
srcBuf.data = srcInfo->rasBase;
|
||||||
|
|
||||||
|
vImage_Buffer destBuf;
|
||||||
|
destBuf.height = dw;
|
||||||
|
destBuf.width = dh;
|
||||||
|
destBuf.rowBytes = dw*4;
|
||||||
|
destBuf.data = buffer;
|
||||||
|
|
||||||
|
vImagePermuteChannels_ARGB8888(&srcBuf, &destBuf, rfi->permuteMap, kvImageNoFlags);
|
||||||
|
raster = buffer;
|
||||||
|
|
||||||
|
J2dTraceLn5(J2D_TRACE_VERBOSE, "replaceTextureRegion [use conversion]: %d, %d, %d, %d, hasA=%d",
|
||||||
|
rfi->permuteMap[0], rfi->permuteMap[1], rfi->permuteMap[2], rfi->permuteMap[3], rfi->hasAlpha);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MTLRegion region = MTLRegionMake2D(dx1, dy1, dw, dh);
|
||||||
|
if (result != nil)
|
||||||
|
dest = result;
|
||||||
|
[dest replaceRegion:region mipmapLevel:0 withBytes:raster bytesPerRow:srcInfo->scanStride];
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inner loop used for copying a source system memory ("Sw") surface to a
|
||||||
|
* destination MTL "Surface". This method is invoked from
|
||||||
|
* MTLBlitLoops_Blit().
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
MTLBlitSwToTextureViaPooledTexture(
|
||||||
|
MTLContext *mtlc, SurfaceDataRasInfo *srcInfo, BMTLSDOps * bmtlsdOps,
|
||||||
|
MTLRasterFormatInfo * rfi, jboolean useBlitEncoder,
|
||||||
|
jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
|
||||||
|
{
|
||||||
|
const int sw = srcInfo->bounds.x2 - srcInfo->bounds.x1;
|
||||||
|
const int sh = srcInfo->bounds.y2 - srcInfo->bounds.y1;
|
||||||
|
id<MTLTexture> dest = bmtlsdOps->pTexture;
|
||||||
|
|
||||||
|
MTLPooledTextureHandle * texHandle = [mtlc.texturePool getTexture:sw height:sh format:rfi->format];
|
||||||
|
if (texHandle == nil) {
|
||||||
|
J2dTraceLn(J2D_TRACE_ERROR, "MTLBlitSwToTextureViaPooledTexture: can't obtain temporary texture object from pool");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
[[mtlc getCommandBufferWrapper] registerPooledTexture:texHandle];
|
||||||
|
[texHandle release];
|
||||||
|
|
||||||
|
id<MTLTexture> texBuff = texHandle.texture;
|
||||||
|
id<MTLTexture> swizzledTexture = replaceTextureRegion(texBuff, srcInfo, rfi, 0, 0, sw, sh);
|
||||||
|
if (useBlitEncoder) {
|
||||||
|
id <MTLBlitCommandEncoder> blitEncoder = [mtlc.encoderManager createBlitEncoder];
|
||||||
|
[blitEncoder copyFromTexture:swizzledTexture != nil ? swizzledTexture : texBuff
|
||||||
|
sourceSlice:0
|
||||||
|
sourceLevel:0
|
||||||
|
sourceOrigin:MTLOriginMake(0, 0, 0)
|
||||||
|
sourceSize:MTLSizeMake(sw, sh, 1)
|
||||||
|
toTexture:dest
|
||||||
|
destinationSlice:0
|
||||||
|
destinationLevel:0
|
||||||
|
destinationOrigin:MTLOriginMake(dx1, dy1, 0)];
|
||||||
|
[blitEncoder endEncoding];
|
||||||
|
} else {
|
||||||
|
drawTex2Tex(mtlc, swizzledTexture != nil ? swizzledTexture : texBuff, dest, !rfi->hasAlpha, bmtlsdOps->isOpaque,
|
||||||
|
0, 0, sw, sh, dx1, dy1, dx2, dy2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (swizzledTexture != nil) {
|
||||||
|
[swizzledTexture release];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
jboolean isIntegerAndUnscaled(
|
||||||
|
jint sx1, jint sy1, jint sx2, jint sy2,
|
||||||
|
jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2
|
||||||
|
) {
|
||||||
|
const jdouble epsilon = 0.0001f;
|
||||||
|
|
||||||
|
// check that dx1,dy1 is integer
|
||||||
|
if (fabs(dx1 - (int)dx1) > epsilon || fabs(dy1 - (int)dy1) > epsilon) {
|
||||||
|
return JNI_FALSE;
|
||||||
|
}
|
||||||
|
// check that destSize equals srcSize
|
||||||
|
if (fabs(dx2 - dx1 - sx2 + sx1) > epsilon || fabs(dy2 - dy1 - sy2 + sy1) > epsilon) {
|
||||||
|
return JNI_FALSE;
|
||||||
|
}
|
||||||
|
return JNI_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
jboolean clipDestCoords(
|
||||||
|
jdouble *dx1, jdouble *dy1, jdouble *dx2, jdouble *dy2,
|
||||||
|
jint *sx1, jint *sy1, jint *sx2, jint *sy2,
|
||||||
|
jint destW, jint destH, const MTLScissorRect * clipRect
|
||||||
|
) {
|
||||||
|
// Trim destination rect by clip-rect (or dest.bounds)
|
||||||
|
const jint sw = *sx2 - *sx1;
|
||||||
|
const jint sh = *sy2 - *sy1;
|
||||||
|
const jdouble dw = *dx2 - *dx1;
|
||||||
|
const jdouble dh = *dy2 - *dy1;
|
||||||
|
|
||||||
|
jdouble dcx1 = 0;
|
||||||
|
jdouble dcx2 = destW;
|
||||||
|
jdouble dcy1 = 0;
|
||||||
|
jdouble dcy2 = destH;
|
||||||
|
if (clipRect != NULL) {
|
||||||
|
if (clipRect->x > dcx1)
|
||||||
|
dcx1 = clipRect->x;
|
||||||
|
const int maxX = clipRect->x + clipRect->width;
|
||||||
|
if (dcx2 > maxX)
|
||||||
|
dcx2 = maxX;
|
||||||
|
if (clipRect->y > dcy1)
|
||||||
|
dcy1 = clipRect->y;
|
||||||
|
const int maxY = clipRect->y + clipRect->height;
|
||||||
|
if (dcy2 > maxY)
|
||||||
|
dcy2 = maxY;
|
||||||
|
|
||||||
|
if (dcx1 >= dcx2) {
|
||||||
|
J2dTraceLn2(J2D_TRACE_ERROR, "\tclipDestCoords: dcx1=%1.2f, dcx2=%1.2f", dcx1, dcx2);
|
||||||
|
dcx1 = dcx2;
|
||||||
|
}
|
||||||
|
if (dcy1 >= dcy2) {
|
||||||
|
J2dTraceLn2(J2D_TRACE_ERROR, "\tclipDestCoords: dcy1=%1.2f, dcy2=%1.2f", dcy1, dcy2);
|
||||||
|
dcy1 = dcy2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (*dx2 <= dcx1 || *dx1 >= dcx2 || *dy2 <= dcy1 || *dy1 >= dcy2) {
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "\tclipDestCoords: dest rect doesn't intersect clip area");
|
||||||
|
return JNI_FALSE;
|
||||||
|
}
|
||||||
|
if (*dx1 < dcx1) {
|
||||||
|
J2dTraceLn2(J2D_TRACE_VERBOSE, "\t\tdx1=%1.2f, will be clipped to %1.2f", *dx1, dcx1);
|
||||||
|
*sx1 += (jint)((dcx1 - *dx1) * (sw/dw));
|
||||||
|
*dx1 = dcx1;
|
||||||
|
}
|
||||||
|
if (*dx2 > dcx2) {
|
||||||
|
J2dTraceLn2(J2D_TRACE_VERBOSE, "\t\tdx2=%1.2f, will be clipped to %1.2f", *dx2, dcx2);
|
||||||
|
*sx2 -= (jint)((*dx2 - dcx2) * (sw/dw));
|
||||||
|
*dx2 = dcx2;
|
||||||
|
}
|
||||||
|
if (*dy1 < dcy1) {
|
||||||
|
J2dTraceLn2(J2D_TRACE_VERBOSE, "\t\tdy1=%1.2f, will be clipped to %1.2f", *dy1, dcy1);
|
||||||
|
*sy1 += (jint)((dcy1 - *dy1) * (sh/dh));
|
||||||
|
*dy1 = dcy1;
|
||||||
|
}
|
||||||
|
if (*dy2 > dcy2) {
|
||||||
|
J2dTraceLn2(J2D_TRACE_VERBOSE, "\t\tdy2=%1.2f, will be clipped to %1.2f", *dy2, dcy2);
|
||||||
|
*sy2 -= (jint)((*dy2 - dcy2) * (sh/dh));
|
||||||
|
*dy2 = dcy2;
|
||||||
|
}
|
||||||
|
return JNI_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* General blit method for copying a native MTL surface to another MTL "Surface".
|
||||||
|
* Parameter texture == true forces to use 'texture' codepath (dest coordinates will always be integers).
|
||||||
|
* Parameter xform == true only when AffineTransform is used (invoked only from TransformBlit, dest coordinates will always be integers).
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
MTLBlitLoops_IsoBlit(JNIEnv *env,
|
||||||
|
MTLContext *mtlc, jlong pSrcOps, jlong pDstOps,
|
||||||
|
jboolean xform, jint hint, jboolean texture,
|
||||||
|
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(mtlc);
|
||||||
|
RETURN_IF_NULL(srcOps);
|
||||||
|
RETURN_IF_NULL(dstOps);
|
||||||
|
|
||||||
|
id<MTLTexture> srcTex = srcOps->pTexture;
|
||||||
|
id<MTLTexture> dstTex = dstOps->pTexture;
|
||||||
|
if (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;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_ISOBLIT
|
||||||
|
if ((xform == JNI_TRUE) != (mtlc.useTransform == JNI_TRUE)) {
|
||||||
|
J2dTraceImpl(J2D_TRACE_ERROR, JNI_TRUE,
|
||||||
|
"MTLBlitLoops_IsoBlit state error: xform=%d, mtlc.useTransform=%d, texture=%d",
|
||||||
|
xform, mtlc.useTransform, texture);
|
||||||
|
}
|
||||||
|
#endif // DEBUG_ISOBLIT
|
||||||
|
|
||||||
|
clipDestCoords(
|
||||||
|
&dx1, &dy1, &dx2, &dy2,
|
||||||
|
&sx1, &sy1, &sx2, &sy2,
|
||||||
|
dstTex.width, dstTex.height, [mtlc.clip getRect]
|
||||||
|
);
|
||||||
|
|
||||||
|
SurfaceDataBounds bounds;
|
||||||
|
bounds.x1 = sx1;
|
||||||
|
bounds.y1 = sy1;
|
||||||
|
bounds.x2 = sx2;
|
||||||
|
bounds.y2 = sy2;
|
||||||
|
SurfaceData_IntersectBoundsXYXY(&bounds, 0, 0, srcOps->width, srcOps->height);
|
||||||
|
|
||||||
|
if (bounds.x2 <= bounds.x1 || bounds.y2 <= 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 (bounds.x1 != sx1) {
|
||||||
|
dx1 += (bounds.x1 - sx1) * (dw / sw);
|
||||||
|
sx1 = bounds.x1;
|
||||||
|
}
|
||||||
|
if (bounds.y1 != sy1) {
|
||||||
|
dy1 += (bounds.y1 - sy1) * (dh / sh);
|
||||||
|
sy1 = bounds.y1;
|
||||||
|
}
|
||||||
|
if (bounds.x2 != sx2) {
|
||||||
|
dx2 += (bounds.x2 - sx2) * (dw / sw);
|
||||||
|
sx2 = bounds.x2;
|
||||||
|
}
|
||||||
|
if (bounds.y2 != sy2) {
|
||||||
|
dy2 += (bounds.y2 - sy2) * (dh / sh);
|
||||||
|
sy2 = bounds.y2;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef TRACE_ISOBLIT
|
||||||
|
J2dTraceImpl(J2D_TRACE_VERBOSE, JNI_FALSE,
|
||||||
|
"MTLBlitLoops_IsoBlit [tx=%d, xf=%d, AC=%s]: src=%s, dst=%s | (%d, %d, %d, %d)->(%1.2f, %1.2f, %1.2f, %1.2f)",
|
||||||
|
texture, xform, [mtlc getCompositeDescription].cString,
|
||||||
|
getSurfaceDescription(srcOps).cString, getSurfaceDescription(dstOps).cString,
|
||||||
|
sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2);
|
||||||
|
#endif //TRACE_ISOBLIT
|
||||||
|
|
||||||
|
if (!texture && !xform
|
||||||
|
&& [mtlc isBlendingDisabled:srcOps->isOpaque]
|
||||||
|
&& isIntegerAndUnscaled(sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2)
|
||||||
|
&& (dstOps->isOpaque || !srcOps->isOpaque)
|
||||||
|
) {
|
||||||
|
#ifdef TRACE_ISOBLIT
|
||||||
|
J2dTraceImpl(J2D_TRACE_VERBOSE, JNI_TRUE," [via blitEncoder]");
|
||||||
|
#endif //TRACE_ISOBLIT
|
||||||
|
|
||||||
|
id <MTLBlitCommandEncoder> blitEncoder = [mtlc.encoderManager createBlitEncoder];
|
||||||
|
[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];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef TRACE_ISOBLIT
|
||||||
|
J2dTraceImpl(J2D_TRACE_VERBOSE, JNI_TRUE," [via sampling]");
|
||||||
|
#endif //TRACE_ISOBLIT
|
||||||
|
drawTex2Tex(mtlc, srcTex, dstTex, srcOps->isOpaque, dstOps->isOpaque, sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* General blit method for copying a system memory ("Sw") surface to a native MTL surface.
|
||||||
|
* Parameter texture == true only in SwToTextureBlit (straight copy from sw to texture), dest coordinates will always be integers.
|
||||||
|
* Parameter xform == true only when AffineTransform is used (invoked only from TransformBlit, dest coordinates will always be integers).
|
||||||
|
*/
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
SurfaceDataOps *srcOps = (SurfaceDataOps *)jlong_to_ptr(pSrcOps);
|
||||||
|
BMTLSDOps *dstOps = (BMTLSDOps *)jlong_to_ptr(pDstOps);
|
||||||
|
|
||||||
|
RETURN_IF_NULL(mtlc);
|
||||||
|
RETURN_IF_NULL(srcOps);
|
||||||
|
RETURN_IF_NULL(dstOps);
|
||||||
|
|
||||||
|
id<MTLTexture> dest = dstOps->pTexture;
|
||||||
|
if (dest == NULL) {
|
||||||
|
J2dTraceLn(J2D_TRACE_ERROR, "MTLBlitLoops_Blit: dest is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (srctype < 0 || srctype >= sizeof(RasterFormatInfos)/ sizeof(MTLRasterFormatInfo)) {
|
||||||
|
J2dTraceLn1(J2D_TRACE_ERROR, "MTLBlitLoops_Blit: source pixel format %d isn't supported", srctype);
|
||||||
|
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) {
|
||||||
|
J2dTraceLn(J2D_TRACE_ERROR, "MTLBlitLoops_Blit: invalid dimensions");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_BLIT
|
||||||
|
if (
|
||||||
|
(xform == JNI_TRUE) != (mtlc.useTransform == JNI_TRUE)
|
||||||
|
|| (xform && texture)
|
||||||
|
) {
|
||||||
|
J2dTraceImpl(J2D_TRACE_ERROR, JNI_TRUE,
|
||||||
|
"MTLBlitLoops_Blit state error: xform=%d, mtlc.useTransform=%d, texture=%d",
|
||||||
|
xform, mtlc.useTransform, texture);
|
||||||
|
}
|
||||||
|
if (texture) {
|
||||||
|
if (!isIntegerAndUnscaled(sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2)) {
|
||||||
|
J2dTraceImpl(J2D_TRACE_ERROR, JNI_TRUE,
|
||||||
|
"MTLBlitLoops_Blit state error: texture=true, but src and dst dimensions aren't equal or dest coords aren't integers");
|
||||||
|
}
|
||||||
|
if (!dstOps->isOpaque && !RasterFormatInfos[srctype].hasAlpha) {
|
||||||
|
J2dTraceImpl(J2D_TRACE_ERROR, JNI_TRUE,
|
||||||
|
"MTLBlitLoops_Blit state error: texture=true, but dest has alpha and source hasn't alpha, can't use texture-codepath");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // DEBUG_BLIT
|
||||||
|
|
||||||
|
clipDestCoords(
|
||||||
|
&dx1, &dy1, &dx2, &dy2,
|
||||||
|
&sx1, &sy1, &sx2, &sy2,
|
||||||
|
dest.width, dest.height, texture ? NULL : [mtlc.clip getRect]
|
||||||
|
);
|
||||||
|
|
||||||
|
SurfaceDataRasInfo srcInfo;
|
||||||
|
srcInfo.bounds.x1 = sx1;
|
||||||
|
srcInfo.bounds.y1 = sy1;
|
||||||
|
srcInfo.bounds.x2 = sx2;
|
||||||
|
srcInfo.bounds.y2 = sy2;
|
||||||
|
|
||||||
|
// NOTE: This function will modify the contents of the bounds field to represent the maximum available raster data.
|
||||||
|
if (srcOps->Lock(env, srcOps, &srcInfo, SD_LOCK_READ) != SD_SUCCESS) {
|
||||||
|
J2dTraceLn(J2D_TRACE_WARNING, "MTLBlitLoops_Blit: could not acquire lock");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
const int dx = srcInfo.bounds.x1 - sx1;
|
||||||
|
dx1 += dx * (dw / sw);
|
||||||
|
}
|
||||||
|
if (srcInfo.bounds.y1 != sy1) {
|
||||||
|
const int dy = srcInfo.bounds.y1 - sy1;
|
||||||
|
dy1 += dy * (dh / sh);
|
||||||
|
}
|
||||||
|
if (srcInfo.bounds.x2 != sx2) {
|
||||||
|
const int dx = srcInfo.bounds.x2 - sx2;
|
||||||
|
dx2 += dx * (dw / sw);
|
||||||
|
}
|
||||||
|
if (srcInfo.bounds.y2 != sy2) {
|
||||||
|
const int dy = srcInfo.bounds.y2 - sy2;
|
||||||
|
dy2 += dy * (dh / sh);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef TRACE_BLIT
|
||||||
|
J2dTraceImpl(J2D_TRACE_VERBOSE, JNI_FALSE,
|
||||||
|
"MTLBlitLoops_Blit [tx=%d, xf=%d, AC=%s]: bdst=%s, src=%p (%dx%d) O=%d premul=%d | (%d, %d, %d, %d)->(%1.2f, %1.2f, %1.2f, %1.2f)",
|
||||||
|
texture, xform, [mtlc getCompositeDescription].cString,
|
||||||
|
getSurfaceDescription(dstOps).cString, srcOps,
|
||||||
|
sx2 - sx1, sy2 - sy1,
|
||||||
|
RasterFormatInfos[srctype].hasAlpha ? 0 : 1, RasterFormatInfos[srctype].isPremult ? 1 : 0,
|
||||||
|
sx1, sy1, sx2, sy2,
|
||||||
|
dx1, dy1, dx2, dy2);
|
||||||
|
#endif //TRACE_BLIT
|
||||||
|
|
||||||
|
MTLRasterFormatInfo rfi = RasterFormatInfos[srctype];
|
||||||
|
const jboolean useReplaceRegion = texture ||
|
||||||
|
([mtlc isBlendingDisabled:!rfi.hasAlpha]
|
||||||
|
&& !xform
|
||||||
|
&& isIntegerAndUnscaled(sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2));
|
||||||
|
|
||||||
|
if (useReplaceRegion) {
|
||||||
|
if (dstOps->isOpaque || rfi.hasAlpha) {
|
||||||
|
#ifdef TRACE_BLIT
|
||||||
|
J2dTraceImpl(J2D_TRACE_VERBOSE, JNI_TRUE," [replaceTextureRegion]");
|
||||||
|
#endif //TRACE_BLIT
|
||||||
|
replaceTextureRegion(dest, &srcInfo, &rfi, (int) dx1, (int) dy1, (int) dx2, (int) dy2);
|
||||||
|
} else {
|
||||||
|
#ifdef TRACE_BLIT
|
||||||
|
J2dTraceImpl(J2D_TRACE_VERBOSE, JNI_TRUE," [via pooled + blit]");
|
||||||
|
#endif //TRACE_BLIT
|
||||||
|
MTLBlitSwToTextureViaPooledTexture(mtlc, &srcInfo, dstOps, &rfi, true, dx1, dy1, dx2, dy2);
|
||||||
|
}
|
||||||
|
} else { // !useReplaceRegion
|
||||||
|
#ifdef TRACE_BLIT
|
||||||
|
J2dTraceImpl(J2D_TRACE_VERBOSE, JNI_TRUE," [via pooled texture]");
|
||||||
|
#endif //TRACE_BLIT
|
||||||
|
MTLBlitSwToTextureViaPooledTexture(mtlc, &srcInfo, dstOps, &rfi, false, 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
|
||||||
|
J2dTraceLn(J2D_TRACE_ERROR, "MTLBlitLoops_SurfaceToSwBlit -- :TODO");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MTLBlitLoops_CopyArea(JNIEnv *env,
|
||||||
|
MTLContext *mtlc, BMTLSDOps *dstOps,
|
||||||
|
jint x, jint y, jint width, jint height,
|
||||||
|
jint dx, jint dy)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
J2dTraceImpl(J2D_TRACE_VERBOSE, JNI_TRUE, "MTLBlitLoops_CopyArea: bdst=%p [tex=%p] %dx%d | src (%d, %d), %dx%d -> dst (%d, %d)",
|
||||||
|
dstOps, dstOps->pTexture, ((id<MTLTexture>)dstOps->pTexture).width, ((id<MTLTexture>)dstOps->pTexture).height, x, y, width, height, dx, dy);
|
||||||
|
#endif //DEBUG
|
||||||
|
id <MTLBlitCommandEncoder> blitEncoder = [mtlc.encoderManager createBlitEncoder];
|
||||||
|
[blitEncoder
|
||||||
|
copyFromTexture:dstOps->pTexture
|
||||||
|
sourceSlice:0 sourceLevel:0 sourceOrigin:MTLOriginMake(x, y, 0) sourceSize:MTLSizeMake(width, height, 1)
|
||||||
|
toTexture:dstOps->pTexture destinationSlice:0 destinationLevel:0 destinationOrigin:MTLOriginMake(x + dx, y + dy, 0)];
|
||||||
|
[blitEncoder endEncoding];
|
||||||
|
}
|
||||||
|
|
||||||
|
#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,377 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLBufImgOps_CreateConvolveProgram -- :TODO");
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MTLBufImgOps_EnableConvolveOp(MTLContext *mtlc, jlong pSrcOps,
|
||||||
|
jboolean edgeZeroFill,
|
||||||
|
jint kernelWidth, jint kernelHeight,
|
||||||
|
unsigned char *kernel)
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
J2dTraceLn(J2D_TRACE_ERROR, "MTLBufImgOps_EnableConvolveOp -- :TODO");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MTLBufImgOps_DisableConvolveOp(MTLContext *mtlc)
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
J2dTraceLn(J2D_TRACE_ERROR, "MTLBufImgOps_DisableConvolveOp -- :TODO");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************** 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
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLBufImgOps_CreateRescaleProgram -- :TODO");
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MTLBufImgOps_EnableRescaleOp(MTLContext *mtlc, jlong pSrcOps,
|
||||||
|
jboolean nonPremult,
|
||||||
|
unsigned char *scaleFactors,
|
||||||
|
unsigned char *offsets)
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
J2dTraceLn(J2D_TRACE_ERROR, "MTLBufImgOps_EnableRescaleOp -- :TODO");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MTLBufImgOps_DisableRescaleOp(MTLContext *mtlc)
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
J2dTraceLn(J2D_TRACE_ERROR, "MTLBufImgOps_DisableRescaleOp -- :TODO");
|
||||||
|
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
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLBufImgOps_CreateLookupProgram -- :TODO");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MTLBufImgOps_EnableLookupOp(MTLContext *mtlc, jlong pSrcOps,
|
||||||
|
jboolean nonPremult, jboolean shortData,
|
||||||
|
jint numBands, jint bandLength, jint offset,
|
||||||
|
void *tableValues)
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
J2dTraceLn(J2D_TRACE_ERROR, "MTLBufImgOps_EnableLookupOp -- :TODO");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MTLBufImgOps_DisableLookupOp(MTLContext *mtlc)
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
J2dTraceLn(J2D_TRACE_ERROR, "MTLBufImgOps_DisableLookupOp -- :TODO");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* !HEADLESS */
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
#import <limits.h>
|
||||||
|
#ifndef MTLClip_h_Included
|
||||||
|
#define MTLClip_h_Included
|
||||||
|
|
||||||
|
#import <Metal/Metal.h>
|
||||||
|
|
||||||
|
#include <jni.h>
|
||||||
|
|
||||||
|
#include "MTLSurfaceDataBase.h"
|
||||||
|
|
||||||
|
enum Clip {
|
||||||
|
NO_CLIP,
|
||||||
|
RECT_CLIP,
|
||||||
|
SHAPE_CLIP
|
||||||
|
};
|
||||||
|
|
||||||
|
@class MTLContext;
|
||||||
|
@class MTLPipelineStatesStorage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The MTLClip class represents clip mode (rect or stencil)
|
||||||
|
* */
|
||||||
|
|
||||||
|
@interface MTLClip : NSObject
|
||||||
|
@property (readonly) id<MTLTexture> stencilTextureRef;
|
||||||
|
@property (readonly) jboolean stencilMaskGenerationInProgress;
|
||||||
|
|
||||||
|
- (id)init;
|
||||||
|
- (BOOL)isEqual:(MTLClip *)other; // used to compare requested with cached
|
||||||
|
- (void)copyFrom:(MTLClip *)other; // used to save cached
|
||||||
|
|
||||||
|
- (BOOL)isShape;
|
||||||
|
- (BOOL)isRect;
|
||||||
|
|
||||||
|
// returns null when clipType != RECT_CLIP
|
||||||
|
- (const MTLScissorRect *) getRect;
|
||||||
|
|
||||||
|
- (void)reset;
|
||||||
|
- (void)setClipRectX1:(jint)x1 Y1:(jint)y1 X2:(jint)x2 Y2:(jint)y2;
|
||||||
|
- (void)beginShapeClip:(BMTLSDOps *)dstOps context:(MTLContext *)mtlc;
|
||||||
|
- (void)endShapeClip:(BMTLSDOps *)dstOps context:(MTLContext *)mtlc;
|
||||||
|
|
||||||
|
- (void)setScissorOrStencil:(id<MTLRenderCommandEncoder>)encoder
|
||||||
|
destWidth:(NSUInteger)dw
|
||||||
|
destHeight:(NSUInteger)dh
|
||||||
|
device:(id<MTLDevice>)device;
|
||||||
|
|
||||||
|
- (void)setMaskGenerationPipelineState:(id<MTLRenderCommandEncoder>)encoder
|
||||||
|
destWidth:(NSUInteger)dw
|
||||||
|
destHeight:(NSUInteger)dh
|
||||||
|
pipelineStateStorage:(MTLPipelineStatesStorage *)pipelineStateStorage;
|
||||||
|
|
||||||
|
- (NSString *)getDescription __unused; // creates autorelease string
|
||||||
|
@end
|
||||||
|
|
||||||
|
#endif // MTLClip_h_Included
|
||||||
@@ -0,0 +1,313 @@
|
|||||||
|
#include "MTLClip.h"
|
||||||
|
#import <iso646.h>
|
||||||
|
|
||||||
|
#include "MTLContext.h"
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
static MTLRenderPipelineDescriptor * templateStencilPipelineDesc = nil;
|
||||||
|
|
||||||
|
static void initTemplatePipelineDescriptors() {
|
||||||
|
if (templateStencilPipelineDesc != nil)
|
||||||
|
return;
|
||||||
|
|
||||||
|
MTLVertexDescriptor *vertDesc = [[MTLVertexDescriptor new] autorelease];
|
||||||
|
vertDesc.attributes[VertexAttributePosition].format = MTLVertexFormatFloat2;
|
||||||
|
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;
|
||||||
|
|
||||||
|
templateStencilPipelineDesc = [[MTLRenderPipelineDescriptor new] autorelease];
|
||||||
|
templateStencilPipelineDesc.sampleCount = 1;
|
||||||
|
templateStencilPipelineDesc.vertexDescriptor = vertDesc;
|
||||||
|
templateStencilPipelineDesc.colorAttachments[0].pixelFormat = MTLPixelFormatR8Uint; // A byte buffer format
|
||||||
|
templateStencilPipelineDesc.label = @"template_stencil";
|
||||||
|
}
|
||||||
|
|
||||||
|
static id<MTLDepthStencilState> getStencilState(id<MTLDevice> device) {
|
||||||
|
static id<MTLDepthStencilState> stencilState = nil;
|
||||||
|
if (stencilState == nil) {
|
||||||
|
MTLDepthStencilDescriptor* stencilDescriptor;
|
||||||
|
stencilDescriptor = [[MTLDepthStencilDescriptor new] autorelease];
|
||||||
|
stencilDescriptor.frontFaceStencil.stencilCompareFunction = MTLCompareFunctionEqual;
|
||||||
|
stencilDescriptor.frontFaceStencil.stencilFailureOperation = MTLStencilOperationKeep;
|
||||||
|
|
||||||
|
// TODO : backFaceStencil can be set to nil if all primitives are drawn as front-facing primitives
|
||||||
|
// currently, fill parallelogram uses back-facing primitive drawing - that needs to be changed.
|
||||||
|
// Once that part is changed, set backFaceStencil to nil
|
||||||
|
//stencilDescriptor.backFaceStencil = nil;
|
||||||
|
|
||||||
|
stencilDescriptor.backFaceStencil.stencilCompareFunction = MTLCompareFunctionEqual;
|
||||||
|
stencilDescriptor.backFaceStencil.stencilFailureOperation = MTLStencilOperationKeep;
|
||||||
|
|
||||||
|
stencilState = [device newDepthStencilStateWithDescriptor:stencilDescriptor];
|
||||||
|
}
|
||||||
|
|
||||||
|
return stencilState;
|
||||||
|
}
|
||||||
|
|
||||||
|
@implementation MTLClip {
|
||||||
|
jint _clipType;
|
||||||
|
MTLScissorRect _clipRect;
|
||||||
|
|
||||||
|
jboolean _stencilMaskGenerationInProgress;
|
||||||
|
id<MTLTexture> _stencilTextureRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)init {
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
_clipType = NO_CLIP;
|
||||||
|
_stencilMaskGenerationInProgress = JNI_FALSE;
|
||||||
|
_stencilTextureRef = nil;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isEqual:(MTLClip *)other {
|
||||||
|
if (self == other)
|
||||||
|
return YES;
|
||||||
|
if (_stencilMaskGenerationInProgress == JNI_TRUE)
|
||||||
|
return other->_stencilMaskGenerationInProgress == JNI_TRUE;
|
||||||
|
if (_clipType != other->_clipType)
|
||||||
|
return NO;
|
||||||
|
if (_clipType == NO_CLIP)
|
||||||
|
return YES;
|
||||||
|
if (_clipType == RECT_CLIP) {
|
||||||
|
return _clipRect.x == other->_clipRect.x && _clipRect.y == other->_clipRect.y
|
||||||
|
&& _clipRect.width == other->_clipRect.width && _clipRect.height == other->_clipRect.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: can compare stencil-data pointers here
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isShape {
|
||||||
|
return _clipType == SHAPE_CLIP;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isRect __unused {
|
||||||
|
return _clipType == RECT_CLIP;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (const MTLScissorRect * _Nullable) getRect {
|
||||||
|
return _clipType == RECT_CLIP ? &_clipRect : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)copyFrom:(MTLClip *)other {
|
||||||
|
_clipType = other->_clipType;
|
||||||
|
_stencilMaskGenerationInProgress = other->_stencilMaskGenerationInProgress;
|
||||||
|
_stencilTextureRef = other->_stencilTextureRef;
|
||||||
|
if (other->_clipType == RECT_CLIP) {
|
||||||
|
_clipRect = other->_clipRect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)reset {
|
||||||
|
_clipType = NO_CLIP;
|
||||||
|
_stencilTextureRef = nil;
|
||||||
|
_stencilMaskGenerationInProgress = JNI_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setClipRectX1:(jint)x1 Y1:(jint)y1 X2:(jint)x2 Y2:(jint)y2 {
|
||||||
|
if (_clipType == SHAPE_CLIP) {
|
||||||
|
_stencilTextureRef = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x1 >= x2 || y1 >= y2) {
|
||||||
|
J2dTraceLn4(J2D_TRACE_ERROR, "MTLClip.setClipRect: invalid rect: x1=%d y1=%d x2=%d y2=%d", x1, y1, x2, y2);
|
||||||
|
_clipType = NO_CLIP;
|
||||||
|
}
|
||||||
|
|
||||||
|
const jint width = x2 - x1;
|
||||||
|
const jint height = y2 - y1;
|
||||||
|
|
||||||
|
J2dTraceLn4(J2D_TRACE_INFO, "MTLClip.setClipRect: x=%d y=%d w=%d h=%d", x1, y1, width, height);
|
||||||
|
|
||||||
|
_clipRect.x = (NSUInteger)((x1 >= 0) ? x1 : 0);
|
||||||
|
_clipRect.y = (NSUInteger)((y1 >= 0) ? y1 : 0);
|
||||||
|
_clipRect.width = (NSUInteger)((width >= 0) ? width : 0);
|
||||||
|
_clipRect.height = (NSUInteger)((height >= 0) ? height : 0);
|
||||||
|
_clipType = RECT_CLIP;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)beginShapeClip:(BMTLSDOps *)dstOps context:(MTLContext *)mtlc {
|
||||||
|
_stencilMaskGenerationInProgress = JNI_TRUE;
|
||||||
|
|
||||||
|
if ((dstOps == NULL) || (dstOps->pStencilData == NULL) || (dstOps->pStencilTexture == NULL)) {
|
||||||
|
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLContext_beginShapeClip: stencil render target or stencil texture is NULL");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the stencil render buffer & stencil texture
|
||||||
|
@autoreleasepool {
|
||||||
|
if (dstOps->width <= 0 || dstOps->height <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSUInteger width = (NSUInteger)dstOps->width;
|
||||||
|
NSUInteger height = (NSUInteger)dstOps->height;
|
||||||
|
id <MTLBuffer> buff = [mtlc.device newBufferWithLength:width * height options:MTLResourceStorageModeShared];
|
||||||
|
memset(buff.contents, 0, width * height);
|
||||||
|
|
||||||
|
id<MTLCommandBuffer> commandBuf = [mtlc createBlitCommandBuffer];
|
||||||
|
id<MTLBlitCommandEncoder> blitEncoder = [commandBuf blitCommandEncoder];
|
||||||
|
|
||||||
|
[blitEncoder copyFromBuffer:buff
|
||||||
|
sourceOffset:0
|
||||||
|
sourceBytesPerRow:width
|
||||||
|
sourceBytesPerImage:width * height
|
||||||
|
sourceSize:MTLSizeMake(width, height, 1)
|
||||||
|
toTexture:dstOps->pStencilData
|
||||||
|
destinationSlice:0
|
||||||
|
destinationLevel:0
|
||||||
|
destinationOrigin:MTLOriginMake(0, 0, 0)];
|
||||||
|
|
||||||
|
[blitEncoder copyFromBuffer:buff
|
||||||
|
sourceOffset:0
|
||||||
|
sourceBytesPerRow:width
|
||||||
|
sourceBytesPerImage:width * height
|
||||||
|
sourceSize:MTLSizeMake(width, height, 1)
|
||||||
|
toTexture:dstOps->pStencilTexture
|
||||||
|
destinationSlice:0
|
||||||
|
destinationLevel:0
|
||||||
|
destinationOrigin:MTLOriginMake(0, 0, 0)];
|
||||||
|
[blitEncoder endEncoding];
|
||||||
|
|
||||||
|
[commandBuf commit];
|
||||||
|
[commandBuf waitUntilCompleted];
|
||||||
|
|
||||||
|
[buff release];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)endShapeClip:(BMTLSDOps *)dstOps context:(MTLContext *)mtlc {
|
||||||
|
|
||||||
|
if ((dstOps == NULL) || (dstOps->pStencilData == NULL) || (dstOps->pStencilTexture == NULL)) {
|
||||||
|
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLContext_endShapeClip: stencil render target or stencil texture is NULL");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Complete the rendering to the stencil buffer ------------
|
||||||
|
[mtlc.encoderManager endEncoder];
|
||||||
|
|
||||||
|
MTLCommandBufferWrapper* cbWrapper = [mtlc pullCommandBufferWrapper];
|
||||||
|
|
||||||
|
id<MTLCommandBuffer> commandBuffer = [cbWrapper getCommandBuffer];
|
||||||
|
[commandBuffer addCompletedHandler:^(id <MTLCommandBuffer> c) {
|
||||||
|
[cbWrapper release];
|
||||||
|
}];
|
||||||
|
|
||||||
|
[commandBuffer commit];
|
||||||
|
[commandBuffer waitUntilCompleted];
|
||||||
|
|
||||||
|
// Now the stencil data is ready, this needs to be used while rendering further
|
||||||
|
@autoreleasepool {
|
||||||
|
if (dstOps->width > 0 && dstOps->height > 0) {
|
||||||
|
NSUInteger width = (NSUInteger)dstOps->width;
|
||||||
|
NSUInteger height = (NSUInteger)dstOps->height;
|
||||||
|
|
||||||
|
id<MTLBuffer> buff =
|
||||||
|
[mtlc.device newBufferWithLength:width * height
|
||||||
|
options:MTLResourceStorageModeShared];
|
||||||
|
|
||||||
|
id<MTLCommandBuffer> cb = [mtlc createBlitCommandBuffer];
|
||||||
|
id<MTLBlitCommandEncoder> blitEncoder = [cb blitCommandEncoder];
|
||||||
|
[blitEncoder copyFromTexture:dstOps->pStencilData
|
||||||
|
sourceSlice:0
|
||||||
|
sourceLevel:0
|
||||||
|
sourceOrigin:MTLOriginMake(0, 0, 0)
|
||||||
|
sourceSize:MTLSizeMake(width, height, 1)
|
||||||
|
toBuffer:buff
|
||||||
|
destinationOffset:0
|
||||||
|
destinationBytesPerRow:width
|
||||||
|
destinationBytesPerImage:width * height];
|
||||||
|
|
||||||
|
[blitEncoder copyFromBuffer:buff
|
||||||
|
sourceOffset:0
|
||||||
|
sourceBytesPerRow:width
|
||||||
|
sourceBytesPerImage:width * height
|
||||||
|
sourceSize:MTLSizeMake(width, height, 1)
|
||||||
|
toTexture:dstOps->pStencilTexture
|
||||||
|
destinationSlice:0
|
||||||
|
destinationLevel:0
|
||||||
|
destinationOrigin:MTLOriginMake(0, 0, 0)];
|
||||||
|
|
||||||
|
[blitEncoder endEncoding];
|
||||||
|
|
||||||
|
[cb commit];
|
||||||
|
[cb waitUntilCompleted];
|
||||||
|
|
||||||
|
[buff release];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_stencilMaskGenerationInProgress = JNI_FALSE;
|
||||||
|
_stencilTextureRef = dstOps->pStencilTexture;
|
||||||
|
_clipType = SHAPE_CLIP;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setMaskGenerationPipelineState:(id<MTLRenderCommandEncoder>)encoder
|
||||||
|
destWidth:(NSUInteger)dw
|
||||||
|
destHeight:(NSUInteger)dh
|
||||||
|
pipelineStateStorage:(MTLPipelineStatesStorage *)pipelineStateStorage
|
||||||
|
{
|
||||||
|
initTemplatePipelineDescriptors();
|
||||||
|
|
||||||
|
// A PipelineState for rendering to a byte-buffered texture that will be used as a stencil
|
||||||
|
id <MTLRenderPipelineState> pipelineState = [pipelineStateStorage getPipelineState:templateStencilPipelineDesc
|
||||||
|
vertexShaderId:@"vert_stencil"
|
||||||
|
fragmentShaderId:@"frag_stencil"];
|
||||||
|
[encoder setRenderPipelineState:pipelineState];
|
||||||
|
|
||||||
|
struct FrameUniforms uf; // color is ignored while writing to stencil buffer
|
||||||
|
memset(&uf, 0, sizeof(uf));
|
||||||
|
[encoder setVertexBytes:&uf length:sizeof(uf) atIndex:FrameUniformBuffer];
|
||||||
|
|
||||||
|
_clipRect.x = 0;
|
||||||
|
_clipRect.y = 0;
|
||||||
|
_clipRect.width = dw;
|
||||||
|
_clipRect.height = dh;
|
||||||
|
|
||||||
|
[encoder setScissorRect:_clipRect]; // just for insurance (to reset possible clip from previous drawing)
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setScissorOrStencil:(id<MTLRenderCommandEncoder>)encoder
|
||||||
|
destWidth:(NSUInteger)dw
|
||||||
|
destHeight:(NSUInteger)dh
|
||||||
|
device:(id<MTLDevice>)device
|
||||||
|
{
|
||||||
|
if (_clipType == NO_CLIP || _clipType == SHAPE_CLIP) {
|
||||||
|
_clipRect.x = 0;
|
||||||
|
_clipRect.y = 0;
|
||||||
|
_clipRect.width = dw;
|
||||||
|
_clipRect.height = dh;
|
||||||
|
}
|
||||||
|
|
||||||
|
[encoder setScissorRect:_clipRect];
|
||||||
|
if (_clipType == NO_CLIP || _clipType == RECT_CLIP) {
|
||||||
|
// NOTE: It seems that we can use the same encoder (with disabled stencil test) when mode changes from SHAPE to RECT.
|
||||||
|
// But [encoder setDepthStencilState:nil] causes crash, so we have to recreate encoder in such case.
|
||||||
|
// So we can omit [encoder setDepthStencilState:nil] here.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_clipType == SHAPE_CLIP) {
|
||||||
|
// Enable stencil test
|
||||||
|
[encoder setDepthStencilState:getStencilState(device)];
|
||||||
|
[encoder setStencilReferenceValue:0xFF];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)getDescription __unused {
|
||||||
|
if (_clipType == NO_CLIP) {
|
||||||
|
return @"NO_CLIP";
|
||||||
|
}
|
||||||
|
if (_clipType == RECT_CLIP) {
|
||||||
|
return [NSString stringWithFormat:@"RECT_CLIP [%lu,%lu - %lux%lu]", _clipRect.x, _clipRect.y, _clipRect.width, _clipRect.height];
|
||||||
|
}
|
||||||
|
return [NSString stringWithFormat:@"SHAPE_CLIP"];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
#ifndef MTLComposite_h_Included
|
||||||
|
#define MTLComposite_h_Included
|
||||||
|
|
||||||
|
#import <Metal/Metal.h>
|
||||||
|
|
||||||
|
#include <jni.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The MTLComposite class represents composite mode
|
||||||
|
* */
|
||||||
|
|
||||||
|
@interface MTLComposite : NSObject
|
||||||
|
- (id)init;
|
||||||
|
- (BOOL)isEqual:(MTLComposite *)other; // used to compare requested with cached
|
||||||
|
- (void)copyFrom:(MTLComposite *)other; // used to save cached
|
||||||
|
|
||||||
|
- (void)setRule:(jint)rule; // sets extraAlpha=1
|
||||||
|
- (void)setRule:(jint)rule extraAlpha:(jfloat)extraAlpha;
|
||||||
|
- (void)reset;
|
||||||
|
|
||||||
|
- (void)setXORComposite:(jint)color;
|
||||||
|
- (void)setAlphaComposite:(jint)rule;
|
||||||
|
|
||||||
|
|
||||||
|
- (jint)getCompositeState;
|
||||||
|
- (jint)getRule;
|
||||||
|
- (jint)getXorColor;
|
||||||
|
|
||||||
|
- (jboolean)isBlendingDisabled:(jboolean) isSrcOpaque;
|
||||||
|
- (NSString *)getDescription; // creates autorelease string
|
||||||
|
@end
|
||||||
|
|
||||||
|
#endif // MTLComposite_h_Included
|
||||||
@@ -0,0 +1,175 @@
|
|||||||
|
#include "MTLComposite.h"
|
||||||
|
#include "sun_java2d_SunGraphics2D.h"
|
||||||
|
#include "java_awt_AlphaComposite.h"
|
||||||
|
|
||||||
|
@implementation MTLComposite {
|
||||||
|
jint _compState;
|
||||||
|
jint _compositeRule;
|
||||||
|
jint _xorPixel;
|
||||||
|
jfloat _extraAlpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)init {
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
_compositeRule = -1;
|
||||||
|
_compState = -1;
|
||||||
|
_xorPixel = 0;
|
||||||
|
_extraAlpha = 1;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isEqual:(MTLComposite *)other {
|
||||||
|
if (self == other)
|
||||||
|
return YES;
|
||||||
|
|
||||||
|
if (_compState == other->_compState) {
|
||||||
|
if (_compState == sun_java2d_SunGraphics2D_COMP_XOR) {
|
||||||
|
return _xorPixel == other->_xorPixel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_compState == sun_java2d_SunGraphics2D_COMP_ALPHA) {
|
||||||
|
return _extraAlpha == other->_extraAlpha
|
||||||
|
&& _compositeRule == other->_compositeRule;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)copyFrom:(MTLComposite *)other {
|
||||||
|
_extraAlpha = other->_extraAlpha;
|
||||||
|
_compositeRule = other->_compositeRule;
|
||||||
|
_compState = other->_compState;
|
||||||
|
_xorPixel = other->_xorPixel;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setRule:(jint)rule {
|
||||||
|
_extraAlpha = 1.f;
|
||||||
|
_compositeRule = rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setRule:(jint)rule extraAlpha:(jfloat)extraAlpha {
|
||||||
|
_compState = sun_java2d_SunGraphics2D_COMP_ALPHA;
|
||||||
|
_extraAlpha = extraAlpha;
|
||||||
|
_compositeRule = rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)reset {
|
||||||
|
_compState = sun_java2d_SunGraphics2D_COMP_ISCOPY;
|
||||||
|
_compositeRule = java_awt_AlphaComposite_SRC;
|
||||||
|
_extraAlpha = 1.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (jint)getRule {
|
||||||
|
return _compositeRule;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)getDescription {
|
||||||
|
const char * result = "";
|
||||||
|
switch (_compositeRule) {
|
||||||
|
case java_awt_AlphaComposite_CLEAR:
|
||||||
|
{
|
||||||
|
result = "CLEAR";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case java_awt_AlphaComposite_SRC:
|
||||||
|
{
|
||||||
|
result = "SRC";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case java_awt_AlphaComposite_DST:
|
||||||
|
{
|
||||||
|
result = "DST";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case java_awt_AlphaComposite_SRC_OVER:
|
||||||
|
{
|
||||||
|
result = "SRC_OVER";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case java_awt_AlphaComposite_DST_OVER:
|
||||||
|
{
|
||||||
|
result = "DST_OVER";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case java_awt_AlphaComposite_SRC_IN:
|
||||||
|
{
|
||||||
|
result = "SRC_IN";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case java_awt_AlphaComposite_DST_IN:
|
||||||
|
{
|
||||||
|
result = "DST_IN";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case java_awt_AlphaComposite_SRC_OUT:
|
||||||
|
{
|
||||||
|
result = "SRC_OUT";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case java_awt_AlphaComposite_DST_OUT:
|
||||||
|
{
|
||||||
|
result = "DST_OUT";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case java_awt_AlphaComposite_SRC_ATOP:
|
||||||
|
{
|
||||||
|
result = "SRC_ATOP";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case java_awt_AlphaComposite_DST_ATOP:
|
||||||
|
{
|
||||||
|
result = "DST_ATOP";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case java_awt_AlphaComposite_XOR:
|
||||||
|
{
|
||||||
|
result = "XOR";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
result = "UNKNOWN";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const double epsilon = 0.001f;
|
||||||
|
if (fabs(_extraAlpha - 1.f) > epsilon) {
|
||||||
|
return [NSString stringWithFormat:@"%s [%1.2f]", result, _extraAlpha];
|
||||||
|
}
|
||||||
|
return [NSString stringWithFormat:@"%s", result];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (jboolean)isBlendingDisabled:(jboolean)isSrcOpaque {
|
||||||
|
if (_compositeRule == java_awt_AlphaComposite_SRC) {
|
||||||
|
const jfloat epsilon = 0.001f;
|
||||||
|
return fabs(_extraAlpha - 1.0f) < epsilon;
|
||||||
|
}
|
||||||
|
if (_compositeRule != java_awt_AlphaComposite_SRC_OVER) {
|
||||||
|
// J2dRlsTraceLn1(J2D_TRACE_VERBOSE, "\tuse blending for rule %d", alphaCompositeRule);
|
||||||
|
return JNI_FALSE;
|
||||||
|
}
|
||||||
|
return isSrcOpaque;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setAlphaComposite:(jint)rule {
|
||||||
|
_compState = sun_java2d_SunGraphics2D_COMP_ALPHA;
|
||||||
|
[self setRule:rule];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (jint)getCompositeState {
|
||||||
|
return _compState;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
-(void)setXORComposite:(jint)color {
|
||||||
|
_compState = sun_java2d_SunGraphics2D_COMP_XOR;
|
||||||
|
_xorPixel = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(jint)getXorColor {
|
||||||
|
return _xorPixel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,261 @@
|
|||||||
|
/*
|
||||||
|
* 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 "sun_java2d_pipe_BufferedContext.h"
|
||||||
|
#include "sun_java2d_metal_MTLContext.h"
|
||||||
|
#include "sun_java2d_metal_MTLContext_MTLContextCaps.h"
|
||||||
|
|
||||||
|
#import <Metal/Metal.h>
|
||||||
|
|
||||||
|
#include "MTLTexturePool.h"
|
||||||
|
#include "MTLPipelineStatesStorage.h"
|
||||||
|
#include "MTLTransform.h"
|
||||||
|
#include "MTLComposite.h"
|
||||||
|
#include "MTLPaints.h"
|
||||||
|
#include "MTLClip.h"
|
||||||
|
#include "EncoderManager.h"
|
||||||
|
|
||||||
|
#define MTLC_BLIT_TILE_SIZE 128
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The MTLCommandBufferWrapper class contains command buffer and
|
||||||
|
* associated resources that will be released in completion handler
|
||||||
|
* */
|
||||||
|
@interface MTLCommandBufferWrapper : NSObject
|
||||||
|
- (id<MTLCommandBuffer>) getCommandBuffer;
|
||||||
|
- (void) onComplete; // invoked from completion handler in some pooled thread
|
||||||
|
- (void) registerPooledTexture:(MTLPooledTextureHandle *)handle;
|
||||||
|
@end
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The MTLContext class contains cached state relevant to the native
|
||||||
|
* MTL context stored within the native ctxInfo field. Each Java-level
|
||||||
|
* MTLContext object is associated with a native-level MTLContext class.
|
||||||
|
* */
|
||||||
|
@interface MTLContext : NSObject
|
||||||
|
@property (readonly) MTLComposite * composite;
|
||||||
|
@property (readonly) MTLPaint * paint;
|
||||||
|
@property (readonly) MTLTransform * transform;
|
||||||
|
@property (readonly) MTLClip * clip;
|
||||||
|
|
||||||
|
@property jint textureFunction;
|
||||||
|
@property jboolean vertexCacheEnabled;
|
||||||
|
@property jboolean aaEnabled;
|
||||||
|
|
||||||
|
@property (readonly, strong) id<MTLDevice> device;
|
||||||
|
@property (strong) id<MTLLibrary> library;
|
||||||
|
@property (strong) id<MTLCommandQueue> commandQueue;
|
||||||
|
@property (strong) id<MTLBuffer> vertexBuffer;
|
||||||
|
|
||||||
|
@property (readonly) EncoderManager * encoderManager;
|
||||||
|
|
||||||
|
@property (strong)MTLPipelineStatesStorage* pipelineStateStorage;
|
||||||
|
@property (strong)MTLTexturePool* texturePool;
|
||||||
|
|
||||||
|
- (MTLCommandBufferWrapper *) getCommandBufferWrapper; // creates command buffer wrapper (when doesn't exist)
|
||||||
|
- (MTLCommandBufferWrapper *) pullCommandBufferWrapper; // returns current buffer wrapper with loosing object ownership
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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*) setSurfacesEnv:(JNIEnv*)env src:(jlong)pSrc dst:(jlong)pDst;
|
||||||
|
|
||||||
|
- (id)initWithDevice:(id<MTLDevice>)d shadersLib:(NSString*)shadersLib;
|
||||||
|
- (void)dealloc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the current clip state (disables both scissor and depth tests).
|
||||||
|
*/
|
||||||
|
- (void)resetClip;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the Metal scissor bounds to the provided rectangular clip bounds.
|
||||||
|
*/
|
||||||
|
- (void)setClipRectX1:(jint)x1 Y1:(jint)y1 X2:(jint)x2 Y2:(jint)y2;
|
||||||
|
|
||||||
|
- (const MTLScissorRect *)clipRect;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up a complex (shape) clip using the Metal stencil buffer. This
|
||||||
|
* method prepares the stencil buffer so that the clip Region spans can
|
||||||
|
* be "rendered" into it. The stencil buffer is first cleared, then the
|
||||||
|
* stencil 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 0xFF value is placed into that location in the stencil
|
||||||
|
* buffer. With stencil test enabled, pixels will only be rendered into the
|
||||||
|
* color buffer if the corresponding value at that (x,y) location in the
|
||||||
|
* stencil buffer is equal to 0xFF.
|
||||||
|
*/
|
||||||
|
- (void)beginShapeClip:(BMTLSDOps *)dstOps;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finishes setting up the shape clip by resetting the stencil func
|
||||||
|
* so that future rendering operations will once again be encoded for the
|
||||||
|
* color buffer (while respecting the clip set up in the stencil buffer).
|
||||||
|
*/
|
||||||
|
- (void)endShapeClip:(BMTLSDOps *)dstOps;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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)setExtraAlpha:(jfloat)ea;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets all OpenGL compositing state (disables blending and logic
|
||||||
|
* operations).
|
||||||
|
*/
|
||||||
|
- (void)resetComposite;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the OpenGL blending state. XOR mode is disabled and the
|
||||||
|
* appropriate blend functions are setup based on the AlphaComposite rule
|
||||||
|
* constant.
|
||||||
|
*/
|
||||||
|
- (void)setAlphaCompositeRule:(jint)rule extraAlpha:(jfloat)extraAlpha
|
||||||
|
flags:(jint)flags;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns autorelease string with composite description (for debugging only)
|
||||||
|
*/
|
||||||
|
- (NSString*)getCompositeDescription;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns autorelease string with paint description (for debugging only)
|
||||||
|
*/
|
||||||
|
- (NSString*)getPaintDescription;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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)setXorComposite:(jint)xorPixel;
|
||||||
|
- (jboolean)isBlendingDisabled:(jboolean) isSrcOpaque;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the OpenGL transform state back to the identity matrix.
|
||||||
|
*/
|
||||||
|
- (void)resetTransform;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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)setTransformM00:(jdouble) m00 M10:(jdouble) m10
|
||||||
|
M01:(jdouble) m01 M11:(jdouble) m11
|
||||||
|
M02:(jdouble) m02 M12:(jdouble) m12;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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)initBlitTileTexture;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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)createBlitTextureFormat:(jint)internalFormat pixelFormat:(jint)pixelFormat
|
||||||
|
width:(jint)width height:(jint)height;
|
||||||
|
|
||||||
|
- (void)destroyContextResources;
|
||||||
|
|
||||||
|
- (void)resetPaint;
|
||||||
|
- (void)setColorPaint:(int)pixel;
|
||||||
|
- (void)setGradientPaintUseMask:(jboolean)useMask
|
||||||
|
cyclic:(jboolean)cyclic
|
||||||
|
p0:(jdouble)p0
|
||||||
|
p1:(jdouble)p1
|
||||||
|
p3:(jdouble)p3
|
||||||
|
pixel1:(jint)pixel1
|
||||||
|
pixel2:(jint) pixel2;
|
||||||
|
- (void)setLinearGradientPaint:(jboolean)useMask
|
||||||
|
linear:(jboolean)linear
|
||||||
|
cycleMethod:(jboolean)cycleMethod
|
||||||
|
numStops:(jint)numStops
|
||||||
|
p0:(jfloat)p0
|
||||||
|
p1:(jfloat)p1
|
||||||
|
p3:(jfloat)p3
|
||||||
|
fractions:(void *)fractions
|
||||||
|
pixels:(void *)pixels;
|
||||||
|
- (void)setRadialGradientPaint:(jboolean)useMask
|
||||||
|
linear:(jboolean)linear
|
||||||
|
cycleMethod:(jboolean)cycleMethod
|
||||||
|
numStops:(jint)numStops
|
||||||
|
m00:(jfloat)m00
|
||||||
|
m01:(jfloat)m01
|
||||||
|
m02:(jfloat)m02
|
||||||
|
m10:(jfloat)m10
|
||||||
|
m11:(jfloat)m11
|
||||||
|
m12:(jfloat)m12
|
||||||
|
focusX:(jfloat)focusX
|
||||||
|
fractions:(void *)fractions
|
||||||
|
pixels:(void *)pixels;
|
||||||
|
- (void)setTexturePaint:(jboolean)useMask
|
||||||
|
pSrcOps:(jlong)pSrcOps
|
||||||
|
filter:(jboolean)filter
|
||||||
|
xp0:(jdouble)xp0
|
||||||
|
xp1:(jdouble)xp1
|
||||||
|
xp3:(jdouble)xp3
|
||||||
|
yp0:(jdouble)yp0
|
||||||
|
yp1:(jdouble)yp1
|
||||||
|
yp3:(jdouble)yp3;
|
||||||
|
|
||||||
|
- (id<MTLCommandBuffer>)createBlitCommandBuffer;
|
||||||
|
@end
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
|
||||||
|
#endif /* MTLContext_h_Included */
|
||||||
@@ -0,0 +1,430 @@
|
|||||||
|
/*
|
||||||
|
* 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_SunGraphics2D.h"
|
||||||
|
|
||||||
|
#include "jlong.h"
|
||||||
|
#import "MTLContext.h"
|
||||||
|
#include "MTLRenderQueue.h"
|
||||||
|
|
||||||
|
|
||||||
|
extern jboolean MTLSD_InitMTLWindow(JNIEnv *env, MTLSDOps *mtlsdo);
|
||||||
|
|
||||||
|
static struct TxtVertex verts[PGRAM_VERTEX_COUNT] = {
|
||||||
|
{{-1.0, 1.0}, {0.0, 0.0}},
|
||||||
|
{{1.0, 1.0}, {1.0, 0.0}},
|
||||||
|
{{1.0, -1.0}, {1.0, 1.0}},
|
||||||
|
{{1.0, -1.0}, {1.0, 1.0}},
|
||||||
|
{{-1.0, -1.0}, {0.0, 1.0}},
|
||||||
|
{{-1.0, 1.0}, {0.0, 0.0}}
|
||||||
|
};
|
||||||
|
|
||||||
|
@implementation MTLCommandBufferWrapper {
|
||||||
|
id<MTLCommandBuffer> _commandBuffer;
|
||||||
|
NSMutableArray * _pooledTextures;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id) initWithCommandBuffer:(id<MTLCommandBuffer>)cmdBuf {
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
_commandBuffer = [cmdBuf retain];
|
||||||
|
_pooledTextures = [[NSMutableArray alloc] init];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id<MTLCommandBuffer>) getCommandBuffer {
|
||||||
|
return _commandBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) onComplete { // invoked from completion handler in some pooled thread
|
||||||
|
for (int c = 0; c < [_pooledTextures count]; ++c)
|
||||||
|
[[_pooledTextures objectAtIndex:c] releaseTexture];
|
||||||
|
[_pooledTextures removeAllObjects];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) registerPooledTexture:(MTLPooledTextureHandle *)handle {
|
||||||
|
[_pooledTextures addObject:handle];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) dealloc {
|
||||||
|
[self onComplete];
|
||||||
|
|
||||||
|
[self->_pooledTextures release];
|
||||||
|
[self->_commandBuffer release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MTLContext {
|
||||||
|
MTLCommandBufferWrapper * _commandBufferWrapper;
|
||||||
|
|
||||||
|
MTLComposite * _composite;
|
||||||
|
MTLPaint * _paint;
|
||||||
|
MTLTransform * _transform;
|
||||||
|
MTLClip * _clip;
|
||||||
|
|
||||||
|
EncoderManager * _encoderManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@synthesize textureFunction,
|
||||||
|
vertexCacheEnabled, aaEnabled, device, library, pipelineStateStorage,
|
||||||
|
commandQueue, vertexBuffer,
|
||||||
|
texturePool;
|
||||||
|
|
||||||
|
- (id)initWithDevice:(id<MTLDevice>)d shadersLib:(NSString*)shadersLib {
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
// Initialization code here.
|
||||||
|
device = d;
|
||||||
|
|
||||||
|
texturePool = [[MTLTexturePool alloc] initWithDevice:device];
|
||||||
|
pipelineStateStorage = [[MTLPipelineStatesStorage alloc] initWithDevice:device shaderLibPath:shadersLib];
|
||||||
|
|
||||||
|
vertexBuffer = [device newBufferWithBytes:verts
|
||||||
|
length:sizeof(verts)
|
||||||
|
options:MTLResourceCPUCacheModeDefaultCache];
|
||||||
|
|
||||||
|
NSError *error = nil;
|
||||||
|
|
||||||
|
library = [device newLibraryWithFile:shadersLib error:&error];
|
||||||
|
if (!library) {
|
||||||
|
NSLog(@"Failed to load library. error %@", error);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
_encoderManager = [[EncoderManager alloc] init];
|
||||||
|
[_encoderManager setContext:self];
|
||||||
|
_composite = [[MTLComposite alloc] init];
|
||||||
|
_paint = [[MTLPaint alloc] init];
|
||||||
|
_transform = [[MTLTransform alloc] init];
|
||||||
|
_clip = [[MTLClip alloc] init];
|
||||||
|
|
||||||
|
_commandBufferWrapper = nil;
|
||||||
|
|
||||||
|
// Create command queue
|
||||||
|
commandQueue = [device newCommandQueue];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)dealloc {
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLContext.dealloc");
|
||||||
|
|
||||||
|
self.texturePool = nil;
|
||||||
|
self.library = nil;
|
||||||
|
self.vertexBuffer = nil;
|
||||||
|
self.commandQueue = nil;
|
||||||
|
self.pipelineStateStorage = nil;
|
||||||
|
[_encoderManager release];
|
||||||
|
[_composite release];
|
||||||
|
[_paint release];
|
||||||
|
[_transform release];
|
||||||
|
[_clip release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (MTLCommandBufferWrapper *) getCommandBufferWrapper {
|
||||||
|
if (_commandBufferWrapper == nil) {
|
||||||
|
J2dTraceLn(J2D_TRACE_VERBOSE, "MTLContext : commandBuffer is NULL");
|
||||||
|
// NOTE: Command queues are thread-safe and allow multiple outstanding command buffers to be encoded simultaneously.
|
||||||
|
_commandBufferWrapper = [[MTLCommandBufferWrapper alloc] initWithCommandBuffer:[self.commandQueue commandBuffer]];// released in [layer blitTexture]
|
||||||
|
}
|
||||||
|
return _commandBufferWrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (MTLCommandBufferWrapper *) pullCommandBufferWrapper {
|
||||||
|
MTLCommandBufferWrapper * result = _commandBufferWrapper;
|
||||||
|
_commandBufferWrapper = nil;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (MTLContext*) setSurfacesEnv:(JNIEnv*)env src:(jlong)pSrc dst:(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)resetClip {
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLContext.resetClip");
|
||||||
|
[_clip reset];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setClipRectX1:(jint)x1 Y1:(jint)y1 X2:(jint)x2 Y2:(jint)y2 {
|
||||||
|
[_clip setClipRectX1:x1 Y1:y1 X2:x2 Y2:y2];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)beginShapeClip:(BMTLSDOps *)dstOps {
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLContext.beginShapeClip");
|
||||||
|
[_clip beginShapeClip:dstOps context:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)endShapeClip:(BMTLSDOps *)dstOps {
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLContext.endShapeClip");
|
||||||
|
[_clip endShapeClip:dstOps context:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)resetComposite {
|
||||||
|
J2dTraceLn(J2D_TRACE_VERBOSE, "MTLContext_ResetComposite");
|
||||||
|
[_composite reset];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setAlphaCompositeRule:(jint)rule extraAlpha:(jfloat)extraAlpha
|
||||||
|
flags:(jint)flags {
|
||||||
|
J2dTraceLn3(J2D_TRACE_INFO, "MTLContext_SetAlphaComposite: rule=%d, extraAlpha=%1.2f, flags=%d", rule, extraAlpha, flags);
|
||||||
|
|
||||||
|
[_composite setRule:rule extraAlpha:extraAlpha];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString*)getCompositeDescription {
|
||||||
|
return [_composite getDescription];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString*)getPaintDescription {
|
||||||
|
return [_paint getDescription];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setXorComposite:(jint)xp {
|
||||||
|
J2dTraceLn1(J2D_TRACE_INFO, "MTLContext.setXorComposite: xorPixel=%08x", xp);
|
||||||
|
|
||||||
|
[_composite setXORComposite:xp];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (jboolean)isBlendingDisabled:(jboolean) isSrcOpaque {
|
||||||
|
return [_composite isBlendingDisabled:isSrcOpaque];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (void)resetTransform {
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLContext_ResetTransform");
|
||||||
|
[_transform resetTransform];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setTransformM00:(jdouble) m00 M10:(jdouble) m10
|
||||||
|
M01:(jdouble) m01 M11:(jdouble) m11
|
||||||
|
M02:(jdouble) m02 M12:(jdouble) m12 {
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLContext_SetTransform");
|
||||||
|
[_transform setTransformM00:m00 M10:m10 M01:m01 M11:m11 M02:m02 M12:m12];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (jboolean)initBlitTileTexture {
|
||||||
|
//TODO
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLContext_InitBlitTileTexture -- :TODO");
|
||||||
|
|
||||||
|
return JNI_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (jint)createBlitTextureFormat:(jint)internalFormat pixelFormat:(jint)pixelFormat
|
||||||
|
width:(jint)width height:(jint)height {
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLContext_InitBlitTileTexture -- :TODO");
|
||||||
|
|
||||||
|
//TODO
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)resetPaint {
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLContext.resetPaint");
|
||||||
|
[_paint reset];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setColorPaint:(int)pixel {
|
||||||
|
J2dTraceLn5(J2D_TRACE_INFO, "MTLContext.setColorPaint: pixel=%08x [r=%d g=%d b=%d a=%d]", pixel, (pixel >> 16) & (0xFF), (pixel >> 8) & 0xFF, (pixel) & 0xFF, (pixel >> 24) & 0xFF);
|
||||||
|
[_paint setColor:pixel];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setGradientPaintUseMask:(jboolean)useMask
|
||||||
|
cyclic:(jboolean)cyclic
|
||||||
|
p0:(jdouble)p0
|
||||||
|
p1:(jdouble)p1
|
||||||
|
p3:(jdouble)p3
|
||||||
|
pixel1:(jint)pixel1
|
||||||
|
pixel2:(jint) pixel2
|
||||||
|
{
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLContext.setGradientPaintUseMask");
|
||||||
|
[_paint setGradientUseMask:useMask
|
||||||
|
cyclic:cyclic
|
||||||
|
p0:p0
|
||||||
|
p1:p1
|
||||||
|
p3:p3
|
||||||
|
pixel1:pixel1
|
||||||
|
pixel2:pixel2];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setLinearGradientPaint:(jboolean)useMask
|
||||||
|
linear:(jboolean)linear
|
||||||
|
cycleMethod:(jboolean)cycleMethod
|
||||||
|
numStops:(jint)numStops
|
||||||
|
p0:(jfloat)p0
|
||||||
|
p1:(jfloat)p1
|
||||||
|
p3:(jfloat)p3
|
||||||
|
fractions:(void *)fractions
|
||||||
|
pixels:(void *)pixels
|
||||||
|
{
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLContext.setLinearGradientPaint");
|
||||||
|
[_paint setLinearGradient:useMask
|
||||||
|
linear:linear
|
||||||
|
cycleMethod:cycleMethod
|
||||||
|
numStops:numStops
|
||||||
|
p0:p0
|
||||||
|
p1:p1
|
||||||
|
p3:p3
|
||||||
|
fractions:fractions
|
||||||
|
pixels:pixels];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setRadialGradientPaint:(jboolean)useMask
|
||||||
|
linear:(jboolean)linear
|
||||||
|
cycleMethod:(jboolean)cycleMethod
|
||||||
|
numStops:(jint)numStops
|
||||||
|
m00:(jfloat)m00
|
||||||
|
m01:(jfloat)m01
|
||||||
|
m02:(jfloat)m02
|
||||||
|
m10:(jfloat)m10
|
||||||
|
m11:(jfloat)m11
|
||||||
|
m12:(jfloat)m12
|
||||||
|
focusX:(jfloat)focusX
|
||||||
|
fractions:(void *)fractions
|
||||||
|
pixels:(void *)pixels
|
||||||
|
{
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLContext.setRadialGradientPaint");
|
||||||
|
[_paint setRadialGradient:useMask
|
||||||
|
linear:linear
|
||||||
|
cycleMethod:cycleMethod
|
||||||
|
numStops:numStops
|
||||||
|
m00:m00
|
||||||
|
m01:m01
|
||||||
|
m02:m02
|
||||||
|
m10:m10
|
||||||
|
m11:m11
|
||||||
|
m12:m12
|
||||||
|
focusX:focusX
|
||||||
|
fractions:fractions
|
||||||
|
pixels:pixels];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setTexturePaint:(jboolean)useMask
|
||||||
|
pSrcOps:(jlong)pSrcOps
|
||||||
|
filter:(jboolean)filter
|
||||||
|
xp0:(jdouble)xp0
|
||||||
|
xp1:(jdouble)xp1
|
||||||
|
xp3:(jdouble)xp3
|
||||||
|
yp0:(jdouble)yp0
|
||||||
|
yp1:(jdouble)yp1
|
||||||
|
yp3:(jdouble)yp3
|
||||||
|
{
|
||||||
|
BMTLSDOps *srcOps = (BMTLSDOps *)jlong_to_ptr(pSrcOps);
|
||||||
|
|
||||||
|
if (srcOps == NULL || srcOps->pTexture == NULL) {
|
||||||
|
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLContext_setTexturePaint: texture paint - texture is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
J2dTraceLn1(J2D_TRACE_INFO, "MTLContext.setTexturePaint [tex=%p]", srcOps->pTexture);
|
||||||
|
|
||||||
|
|
||||||
|
[_paint setTexture:useMask
|
||||||
|
textureID:srcOps->pTexture
|
||||||
|
filter:filter
|
||||||
|
xp0:xp0
|
||||||
|
xp1:xp1
|
||||||
|
xp3:xp3
|
||||||
|
yp0:yp0
|
||||||
|
yp1:yp1
|
||||||
|
yp3:yp3];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id<MTLCommandBuffer>)createBlitCommandBuffer {
|
||||||
|
return [self.commandQueue commandBuffer];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
#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,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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HEADLESS
|
||||||
|
|
||||||
|
#include "MTLFuncs.h"
|
||||||
|
|
||||||
|
|
||||||
|
jboolean
|
||||||
|
MTLFuncs_OpenLibrary()
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
|
||||||
|
J2dRlsTraceLn(J2D_TRACE_INFO, "MTLFuncs_OpenLibrary");
|
||||||
|
|
||||||
|
|
||||||
|
return JNI_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MTLFuncs_CloseLibrary()
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
J2dRlsTraceLn(J2D_TRACE_INFO, "MTLFuncs_CloseLibrary");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
jboolean
|
||||||
|
MTLFuncs_InitPlatformFuncs()
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
J2dRlsTraceLn(J2D_TRACE_INFO, "MTLFuncs_InitPlatformFuncs");
|
||||||
|
|
||||||
|
return JNI_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
jboolean
|
||||||
|
MTLFuncs_InitBaseFuncs()
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
J2dRlsTraceLn(J2D_TRACE_INFO, "MTLFuncs_InitBaseFuncs");
|
||||||
|
|
||||||
|
|
||||||
|
return JNI_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
jboolean
|
||||||
|
MTLFuncs_InitExtFuncs()
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
J2dRlsTraceLn(J2D_TRACE_INFO, "MTLFuncs_InitExtFuncs");
|
||||||
|
|
||||||
|
return JNI_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* !HEADLESS */
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020, 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 MTLGlyphCache_h_Included
|
||||||
|
#define MTLGlyphCache_h_Included
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "jni.h"
|
||||||
|
#include "fontscalerdefs.h"
|
||||||
|
#import <Metal/Metal.h>
|
||||||
|
|
||||||
|
typedef void (MTLFlushFunc)();
|
||||||
|
|
||||||
|
typedef struct _MTLCacheCellInfo MTLCacheCellInfo;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
CacheCellInfo *head;
|
||||||
|
CacheCellInfo *tail;
|
||||||
|
id<MTLTexture> texture;
|
||||||
|
jint width;
|
||||||
|
jint height;
|
||||||
|
jint cellWidth;
|
||||||
|
jint cellHeight;
|
||||||
|
MTLFlushFunc *Flush;
|
||||||
|
} MTLGlyphCacheInfo;
|
||||||
|
|
||||||
|
struct _MTLCacheCellInfo {
|
||||||
|
MTLGlyphCacheInfo *cacheInfo;
|
||||||
|
struct GlyphInfo *glyphInfo;
|
||||||
|
// next cell info in the cache's list
|
||||||
|
MTLCacheCellInfo *next;
|
||||||
|
// REMIND: find better name?
|
||||||
|
// next cell info in the glyph's cell list (next Glyph Cache Info)
|
||||||
|
MTLCacheCellInfo *nextGCI;
|
||||||
|
jint timesRendered;
|
||||||
|
jint x;
|
||||||
|
jint y;
|
||||||
|
// number of pixels from the left or right edge not considered touched
|
||||||
|
// by the glyph
|
||||||
|
jint leftOff;
|
||||||
|
jint rightOff;
|
||||||
|
jfloat tx1;
|
||||||
|
jfloat ty1;
|
||||||
|
jfloat tx2;
|
||||||
|
jfloat ty2;
|
||||||
|
};
|
||||||
|
|
||||||
|
MTLGlyphCacheInfo *
|
||||||
|
MTLGlyphCache_Init(jint width, jint height,
|
||||||
|
jint cellWidth, jint cellHeight,
|
||||||
|
MTLFlushFunc *func);
|
||||||
|
MTLCacheCellInfo *
|
||||||
|
MTLGlyphCache_AddGlyph(MTLGlyphCacheInfo *cache, struct GlyphInfo *glyph);
|
||||||
|
bool
|
||||||
|
MTLGlyphCache_IsCacheFull(MTLGlyphCacheInfo *cache, GlyphInfo *glyph);
|
||||||
|
void
|
||||||
|
MTLGlyphCache_Invalidate(MTLGlyphCacheInfo *cache);
|
||||||
|
void
|
||||||
|
MTLGlyphCache_AddCellInfo(struct GlyphInfo *glyph, MTLCacheCellInfo *cellInfo);
|
||||||
|
void
|
||||||
|
MTLGlyphCache_RemoveCellInfo(struct GlyphInfo *glyph, MTLCacheCellInfo *cellInfo);
|
||||||
|
MTLCacheCellInfo *
|
||||||
|
MTLGlyphCache_GetCellInfoForCache(struct GlyphInfo *glyph,
|
||||||
|
MTLGlyphCacheInfo *cache);
|
||||||
|
JNIEXPORT void
|
||||||
|
MTLGlyphCache_RemoveAllCellInfos(struct GlyphInfo *glyph);
|
||||||
|
void
|
||||||
|
MTLGlyphCache_Free(MTLGlyphCacheInfo *cache);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* MTLGlyphCache_h_Included */
|
||||||
@@ -0,0 +1,365 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "jni.h"
|
||||||
|
#include "MTLGlyphCache.h"
|
||||||
|
#include "Trace.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the cache is full, we will try to reuse the cache cells that have
|
||||||
|
* been used relatively less than the others (and we will save the cells that
|
||||||
|
* have been rendered more than the threshold defined here).
|
||||||
|
*/
|
||||||
|
#define TIMES_RENDERED_THRESHOLD 5
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new GlyphCacheInfo structure, fills in the initial values, and
|
||||||
|
* then returns a pointer to the GlyphCacheInfo record.
|
||||||
|
*
|
||||||
|
* Note that this method only sets up a data structure describing a
|
||||||
|
* rectangular region of accelerated memory, containing "virtual" cells of
|
||||||
|
* the requested size. The cell information is added lazily to the linked
|
||||||
|
* list describing the cache as new glyphs are added. Platform specific
|
||||||
|
* glyph caching code is responsible for actually creating the accelerated
|
||||||
|
* memory surface that will contain the individual glyph images.
|
||||||
|
*
|
||||||
|
* Each glyph contains a reference to a list of cell infos - one per glyph
|
||||||
|
* cache. There may be multiple glyph caches (for example, one per graphics
|
||||||
|
* adapter), so if the glyph is cached on two devices its cell list will
|
||||||
|
* consists of two elements corresponding to different glyph caches.
|
||||||
|
*
|
||||||
|
* The platform-specific glyph caching code is supposed to use
|
||||||
|
* GetCellInfoForCache method for retrieving cache infos from the glyph's list.
|
||||||
|
*
|
||||||
|
* Note that if it is guaranteed that there will be only one global glyph
|
||||||
|
* cache then it one does not have to use AccelGlyphCache_GetCellInfoForCache
|
||||||
|
* for retrieving cell info for the glyph, but instead just use the struct's
|
||||||
|
* field directly.
|
||||||
|
*/
|
||||||
|
MTLGlyphCacheInfo *
|
||||||
|
MTLGlyphCache_Init(jint width, jint height,
|
||||||
|
jint cellWidth, jint cellHeight,
|
||||||
|
MTLFlushFunc *func)
|
||||||
|
{
|
||||||
|
MTLGlyphCacheInfo *gcinfo;
|
||||||
|
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLGlyphCache_Init");
|
||||||
|
|
||||||
|
gcinfo = (MTLGlyphCacheInfo *)malloc(sizeof(MTLGlyphCacheInfo));
|
||||||
|
if (gcinfo == NULL) {
|
||||||
|
J2dRlsTraceLn(J2D_TRACE_ERROR,
|
||||||
|
"MTLGlyphCache_Init: could not allocate MTLGlyphCacheInfo");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
gcinfo->head = NULL;
|
||||||
|
gcinfo->tail = NULL;
|
||||||
|
gcinfo->width = width;
|
||||||
|
gcinfo->height = height;
|
||||||
|
gcinfo->cellWidth = cellWidth;
|
||||||
|
gcinfo->cellHeight = cellHeight;
|
||||||
|
gcinfo->Flush = func;
|
||||||
|
|
||||||
|
return gcinfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to add the provided glyph to the specified cache. If the
|
||||||
|
* operation is successful, a pointer to the newly occupied cache cell is
|
||||||
|
* stored in the glyph's cellInfo field; otherwise, its cellInfo field is
|
||||||
|
* set to NULL, indicating that the glyph's original bits should be rendered
|
||||||
|
* instead. If the cache is full, the least-recently-used glyph is
|
||||||
|
* invalidated and its cache cell is reassigned to the new glyph being added.
|
||||||
|
*
|
||||||
|
* Note that this method only ensures that a rectangular region in the
|
||||||
|
* "virtual" glyph cache is available for the glyph image. Platform specific
|
||||||
|
* glyph caching code is responsible for actually caching the glyph image
|
||||||
|
* in the associated accelerated memory surface.
|
||||||
|
*
|
||||||
|
* Returns created cell info if it was successfully created and added to the
|
||||||
|
* cache and glyph's cell lists, NULL otherwise.
|
||||||
|
*/
|
||||||
|
MTLCacheCellInfo *
|
||||||
|
MTLGlyphCache_AddGlyph(MTLGlyphCacheInfo *cache, GlyphInfo *glyph)
|
||||||
|
{
|
||||||
|
MTLCacheCellInfo *cellinfo = NULL;
|
||||||
|
jint w = glyph->width;
|
||||||
|
jint h = glyph->height;
|
||||||
|
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLGlyphCache_AddGlyph");
|
||||||
|
|
||||||
|
if ((glyph->width > cache->cellWidth) ||
|
||||||
|
(glyph->height > cache->cellHeight))
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
jint x, y;
|
||||||
|
|
||||||
|
if (cache->head == NULL) {
|
||||||
|
x = 0;
|
||||||
|
y = 0;
|
||||||
|
} else {
|
||||||
|
x = cache->tail->x + cache->cellWidth;
|
||||||
|
y = cache->tail->y;
|
||||||
|
if ((x + cache->cellWidth) > cache->width) {
|
||||||
|
x = 0;
|
||||||
|
y += cache->cellHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// create new CacheCellInfo
|
||||||
|
cellinfo = (MTLCacheCellInfo *)malloc(sizeof(MTLCacheCellInfo));
|
||||||
|
if (cellinfo == NULL) {
|
||||||
|
J2dTraceLn(J2D_TRACE_ERROR, "could not allocate CellInfo");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cellinfo->cacheInfo = cache;
|
||||||
|
cellinfo->glyphInfo = glyph;
|
||||||
|
cellinfo->timesRendered = 0;
|
||||||
|
cellinfo->x = x;
|
||||||
|
cellinfo->y = y;
|
||||||
|
cellinfo->leftOff = 0;
|
||||||
|
cellinfo->rightOff = 0;
|
||||||
|
cellinfo->tx1 = (jfloat)cellinfo->x / cache->width;
|
||||||
|
cellinfo->ty1 = (jfloat)cellinfo->y / cache->height;
|
||||||
|
cellinfo->tx2 = cellinfo->tx1 + ((jfloat)w / cache->width);
|
||||||
|
cellinfo->ty2 = cellinfo->ty1 + ((jfloat)h / cache->height);
|
||||||
|
|
||||||
|
if (cache->head == NULL) {
|
||||||
|
// initialize the head cell
|
||||||
|
cache->head = cellinfo;
|
||||||
|
} else {
|
||||||
|
// update existing tail cell
|
||||||
|
cache->tail->next = cellinfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the new cell to the end of the list
|
||||||
|
cache->tail = cellinfo;
|
||||||
|
cellinfo->next = NULL;
|
||||||
|
cellinfo->nextGCI = NULL;
|
||||||
|
|
||||||
|
// add cache cell to the glyph's cells list
|
||||||
|
MTLGlyphCache_AddCellInfo(glyph, cellinfo);
|
||||||
|
return cellinfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
MTLGlyphCache_IsCacheFull(MTLGlyphCacheInfo *cache, GlyphInfo *glyph)
|
||||||
|
{
|
||||||
|
jint w = glyph->width;
|
||||||
|
jint h = glyph->height;
|
||||||
|
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLGlyphCache_IsCacheFull");
|
||||||
|
|
||||||
|
jint x, y;
|
||||||
|
|
||||||
|
if (cache->head == NULL) {
|
||||||
|
return JNI_FALSE;
|
||||||
|
} else {
|
||||||
|
x = cache->tail->x + cache->cellWidth;
|
||||||
|
y = cache->tail->y;
|
||||||
|
if ((x + cache->cellWidth) > cache->width) {
|
||||||
|
x = 0;
|
||||||
|
y += cache->cellHeight;
|
||||||
|
if ((y + cache->cellHeight) > cache->height) {
|
||||||
|
return JNI_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return JNI_FALSE;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Invalidates all cells in the cache. Note that this method does not
|
||||||
|
* attempt to compact the cache in any way; it just invalidates any cells
|
||||||
|
* that already exist.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
MTLGlyphCache_Invalidate(MTLGlyphCacheInfo *cache)
|
||||||
|
{
|
||||||
|
MTLCacheCellInfo *cellinfo;
|
||||||
|
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLGlyphCache_Invalidate");
|
||||||
|
|
||||||
|
if (cache == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// flush any pending vertices that may be depending on the current
|
||||||
|
// glyph cache layout
|
||||||
|
if (cache->Flush != NULL) {
|
||||||
|
cache->Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
cellinfo = cache->head;
|
||||||
|
while (cellinfo != NULL) {
|
||||||
|
if (cellinfo->glyphInfo != NULL) {
|
||||||
|
// if the cell is occupied, notify the base glyph that its
|
||||||
|
// cached version for this cache is about to be invalidated
|
||||||
|
MTLGlyphCache_RemoveCellInfo(cellinfo->glyphInfo, cellinfo);
|
||||||
|
}
|
||||||
|
cellinfo = cellinfo->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invalidates and frees all cells and the cache itself. The "cache" pointer
|
||||||
|
* becomes invalid after this function returns.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
MTLGlyphCache_Free(MTLGlyphCacheInfo *cache)
|
||||||
|
{
|
||||||
|
MTLCacheCellInfo *cellinfo;
|
||||||
|
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLGlyphCache_Free");
|
||||||
|
|
||||||
|
if (cache == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// flush any pending vertices that may be depending on the current
|
||||||
|
// glyph cache
|
||||||
|
if (cache->Flush != NULL) {
|
||||||
|
cache->Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
while (cache->head != NULL) {
|
||||||
|
cellinfo = cache->head;
|
||||||
|
if (cellinfo->glyphInfo != NULL) {
|
||||||
|
// if the cell is occupied, notify the base glyph that its
|
||||||
|
// cached version for this cache is about to be invalidated
|
||||||
|
MTLGlyphCache_RemoveCellInfo(cellinfo->glyphInfo, cellinfo);
|
||||||
|
}
|
||||||
|
cache->head = cellinfo->next;
|
||||||
|
free(cellinfo);
|
||||||
|
}
|
||||||
|
free(cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add cell info to the head of the glyph's list of cached cells.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
MTLGlyphCache_AddCellInfo(GlyphInfo *glyph, MTLCacheCellInfo *cellInfo)
|
||||||
|
{
|
||||||
|
// assert (glyph != NULL && cellInfo != NULL)
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLGlyphCache_AddCellInfo");
|
||||||
|
J2dTraceLn2(J2D_TRACE_VERBOSE, " glyph 0x%x: adding cell 0x%x to the list",
|
||||||
|
glyph, cellInfo);
|
||||||
|
|
||||||
|
cellInfo->glyphInfo = glyph;
|
||||||
|
cellInfo->nextGCI = glyph->cellInfo;
|
||||||
|
glyph->cellInfo = cellInfo;
|
||||||
|
glyph->managed = MANAGED_GLYPH;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes cell info from the glyph's list of cached cells.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
MTLGlyphCache_RemoveCellInfo(GlyphInfo *glyph, MTLCacheCellInfo *cellInfo)
|
||||||
|
{
|
||||||
|
MTLCacheCellInfo *currCellInfo = glyph->cellInfo;
|
||||||
|
MTLCacheCellInfo *prevInfo = NULL;
|
||||||
|
// assert (glyph!= NULL && glyph->cellInfo != NULL && cellInfo != NULL)
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLGlyphCache_RemoveCellInfo");
|
||||||
|
do {
|
||||||
|
if (currCellInfo == cellInfo) {
|
||||||
|
J2dTraceLn2(J2D_TRACE_VERBOSE,
|
||||||
|
" glyph 0x%x: removing cell 0x%x from glyph's list",
|
||||||
|
glyph, currCellInfo);
|
||||||
|
if (prevInfo == NULL) { // it's the head, chop-chop
|
||||||
|
glyph->cellInfo = currCellInfo->nextGCI;
|
||||||
|
} else {
|
||||||
|
prevInfo->nextGCI = currCellInfo->nextGCI;
|
||||||
|
}
|
||||||
|
currCellInfo->glyphInfo = NULL;
|
||||||
|
currCellInfo->nextGCI = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
prevInfo = currCellInfo;
|
||||||
|
currCellInfo = currCellInfo->nextGCI;
|
||||||
|
} while (currCellInfo != NULL);
|
||||||
|
J2dTraceLn2(J2D_TRACE_WARNING, "MTLGlyphCache_RemoveCellInfo: "\
|
||||||
|
"no cell 0x%x in glyph 0x%x's cell list",
|
||||||
|
cellInfo, glyph);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes cell info from the glyph's list of cached cells.
|
||||||
|
*/
|
||||||
|
JNIEXPORT void
|
||||||
|
MTLGlyphCache_RemoveAllCellInfos(GlyphInfo *glyph)
|
||||||
|
{
|
||||||
|
MTLCacheCellInfo *currCell, *prevCell;
|
||||||
|
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLGlyphCache_RemoveAllCellInfos");
|
||||||
|
|
||||||
|
if (glyph == NULL || glyph->cellInfo == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// invalidate all of this glyph's accelerated cache cells
|
||||||
|
currCell = glyph->cellInfo;
|
||||||
|
do {
|
||||||
|
currCell->glyphInfo = NULL;
|
||||||
|
prevCell = currCell;
|
||||||
|
currCell = currCell->nextGCI;
|
||||||
|
prevCell->nextGCI = NULL;
|
||||||
|
} while (currCell != NULL);
|
||||||
|
|
||||||
|
glyph->cellInfo = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns cell info associated with particular cache from the glyph's list of
|
||||||
|
* cached cells.
|
||||||
|
*/
|
||||||
|
MTLCacheCellInfo *
|
||||||
|
MTLGlyphCache_GetCellInfoForCache(GlyphInfo *glyph, MTLGlyphCacheInfo *cache)
|
||||||
|
{
|
||||||
|
// assert (glyph != NULL && cache != NULL)
|
||||||
|
J2dTraceLn(J2D_TRACE_VERBOSE2, "MTLGlyphCache_GetCellInfoForCache");
|
||||||
|
|
||||||
|
if (glyph->cellInfo != NULL) {
|
||||||
|
MTLCacheCellInfo *cellInfo = glyph->cellInfo;
|
||||||
|
do {
|
||||||
|
if (cellInfo->cacheInfo == cache) {
|
||||||
|
J2dTraceLn3(J2D_TRACE_VERBOSE2,
|
||||||
|
" glyph 0x%x: found cell 0x%x for cache 0x%x",
|
||||||
|
glyph, cellInfo, cache);
|
||||||
|
return cellInfo;
|
||||||
|
}
|
||||||
|
cellInfo = cellInfo->nextGCI;
|
||||||
|
} while (cellInfo != NULL);
|
||||||
|
}
|
||||||
|
J2dTraceLn2(J2D_TRACE_VERBOSE2, " glyph 0x%x: no cell for cache 0x%x",
|
||||||
|
glyph, cache);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* 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>
|
||||||
|
|
||||||
|
|
||||||
|
@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,228 @@
|
|||||||
|
/*
|
||||||
|
* 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 "awt.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) {
|
||||||
|
[mtlinfo->context release];
|
||||||
|
mtlinfo->context = nil;
|
||||||
|
}
|
||||||
|
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");
|
||||||
|
|
||||||
|
FILE *f = popen("system_profiler SPDisplaysDataType", "r");
|
||||||
|
bool metalSupport = FALSE;
|
||||||
|
while (getc(f) != EOF)
|
||||||
|
{
|
||||||
|
char str[60];
|
||||||
|
|
||||||
|
if (fgets(str, 60, f) != NULL) {
|
||||||
|
// Check for string
|
||||||
|
// "Metal: Supported, feature set macOS GPUFamily1 v4"
|
||||||
|
if (strstr(str, "Metal") != NULL) {
|
||||||
|
puts(str);
|
||||||
|
metalSupport = JNI_TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pclose(f);
|
||||||
|
if (!metalSupport) {
|
||||||
|
fprintf(stderr, "Metal support not present\n");
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Metal support is present\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@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 alloc] initWithDevice:CGDirectDisplayCopyCurrentMetalDevice(displayID)
|
||||||
|
shadersLib:mtlShadersLib];
|
||||||
|
if (mtlc == 0L) {
|
||||||
|
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLGC_InitMTLContext: could not allocate memory for mtlc");
|
||||||
|
[argValue addObject: [NSNumber numberWithLong: 0L]];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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");
|
||||||
|
|
||||||
|
// From "Metal Feature Set Tables"
|
||||||
|
// There are 2 GPU families for mac - MTLGPUFamilyMac1 and MTLGPUFamilyMac2
|
||||||
|
// Both of them support "Maximum 2D texture width and height" of 16384 pixels
|
||||||
|
// Note : there is no API to get this value, hence hardcoding by reading from the table
|
||||||
|
__block int max = 16384;
|
||||||
|
|
||||||
|
return (jint)max;
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* 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 <QuartzCore/CAMetalLayer.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;
|
||||||
|
int nextDrawableCount;
|
||||||
|
int topInset;
|
||||||
|
int leftInset;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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;
|
||||||
|
@property (readwrite, assign) int nextDrawableCount;
|
||||||
|
@property (readwrite, assign) int topInset;
|
||||||
|
@property (readwrite, assign) int leftInset;
|
||||||
|
|
||||||
|
- (id) initWithJavaLayer:(JNFWeakJObjectWrapper *)layer;
|
||||||
|
|
||||||
|
- (void) blitTexture;
|
||||||
|
- (void) fillParallelogramCtxX:(jfloat)x
|
||||||
|
Y:(jfloat)y
|
||||||
|
DX1:(jfloat)dx1
|
||||||
|
DY1:(jfloat)dy1
|
||||||
|
DX2:(jfloat)dx2
|
||||||
|
DY2:(jfloat)dy2;
|
||||||
|
- (void) blitCallback;
|
||||||
|
- (void) display;
|
||||||
|
@end
|
||||||
|
|
||||||
|
#endif /* CGLLayer_h_Included */
|
||||||
@@ -0,0 +1,238 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
@synthesize nextDrawableCount;
|
||||||
|
@synthesize topInset;
|
||||||
|
@synthesize leftInset;
|
||||||
|
|
||||||
|
- (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];
|
||||||
|
self.topInset = 0;
|
||||||
|
self.leftInset = 0;
|
||||||
|
self.framebufferOnly = NO;
|
||||||
|
self.nextDrawableCount = 0;
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) blitTexture {
|
||||||
|
if (self.ctx == NULL || self.javaLayer == NULL || self.buffer == nil || self.ctx.device == nil) {
|
||||||
|
J2dTraceLn4(J2D_TRACE_VERBOSE, "MTLLayer.blitTexture: uninitialized (mtlc=%p, javaLayer=%p, buffer=%p, devide=%p)", self.ctx, self.javaLayer, self.buffer, ctx.device);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.nextDrawableCount != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
@autoreleasepool {
|
||||||
|
if ((self.buffer.width == 0) || (self.buffer.height == 0)) {
|
||||||
|
J2dTraceLn(J2D_TRACE_VERBOSE, "MTLLayer.blitTexture: cannot create drawable of size 0");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
id<MTLCommandBuffer> commandBuf = [self.ctx createBlitCommandBuffer];
|
||||||
|
if (commandBuf == nil) {
|
||||||
|
J2dTraceLn(J2D_TRACE_VERBOSE, "MTLLayer.blitTexture: nothing to do (commandBuf is null)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
id<CAMetalDrawable> mtlDrawable = [self nextDrawable];
|
||||||
|
if (mtlDrawable == nil) {
|
||||||
|
J2dTraceLn(J2D_TRACE_VERBOSE, "MTLLayer.blitTexture: nextDrawable is null)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.nextDrawableCount++;
|
||||||
|
J2dTraceLn6(J2D_TRACE_VERBOSE, "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((jint)(self.leftInset*self.contentsScale), (jint)(self.topInset*self.contentsScale), 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> commandBuf) {
|
||||||
|
self.nextDrawableCount--;
|
||||||
|
}];
|
||||||
|
|
||||||
|
[commandBuf commit];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) dealloc {
|
||||||
|
self.javaLayer = nil;
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) blitCallback {
|
||||||
|
|
||||||
|
JNIEnv *env = [ThreadUtilities getJNIEnv];
|
||||||
|
static JNF_CLASS_CACHE(jc_JavaLayer, "sun/java2d/metal/MTLLayer");
|
||||||
|
static JNF_MEMBER_CACHE(jm_drawInMTLContext, jc_JavaLayer, "drawInMTLContext", "()V");
|
||||||
|
|
||||||
|
jobject javaLayerLocalRef = [self.javaLayer jObjectWithEnv:env];
|
||||||
|
if ((*env)->IsSameObject(env, javaLayerLocalRef, NULL)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNFCallVoidMethod(env, javaLayerLocalRef, jm_drawInMTLContext);
|
||||||
|
(*env)->DeleteLocalRef(env, javaLayerLocalRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) display {
|
||||||
|
AWT_ASSERT_APPKIT_THREAD;
|
||||||
|
J2dTraceLn(J2D_TRACE_VERBOSE, "MTLLayer_display() called");
|
||||||
|
[self blitCallback];
|
||||||
|
[super display];
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: sun_java2d_metal_MTLLayer
|
||||||
|
* 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.device;
|
||||||
|
layer.pixelFormat = MTLPixelFormatBGRA8Unorm;
|
||||||
|
layer.drawableSize =
|
||||||
|
CGSizeMake(layer.buffer.width,
|
||||||
|
layer.buffer.height);
|
||||||
|
} 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_sun_java2d_metal_MTLLayer_nativeSetInsets
|
||||||
|
(JNIEnv *env, jclass cls, jlong layerPtr, jint top, jint left)
|
||||||
|
{
|
||||||
|
MTLLayer *layer = jlong_to_ptr(layerPtr);
|
||||||
|
layer.topInset = top;
|
||||||
|
layer.leftInset = left;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_sun_java2d_metal_MTLLayer_blitTexture
|
||||||
|
(JNIEnv *env, jclass cls, jlong layerPtr)
|
||||||
|
{
|
||||||
|
J2dTraceLn(J2D_TRACE_VERBOSE, "MTLLayer_blitTexture");
|
||||||
|
MTLLayer *layer = jlong_to_ptr(layerPtr);
|
||||||
|
MTLContext * ctx = layer.ctx;
|
||||||
|
if (layer == NULL || ctx == NULL) {
|
||||||
|
J2dTraceLn(J2D_TRACE_VERBOSE, "MTLLayer_blit : Layer or Context is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[layer blitTexture];
|
||||||
|
}
|
||||||
@@ -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, BMTLSDOps * dstOps,
|
||||||
|
jint dstx, jint dsty,
|
||||||
|
jint width, jint height,
|
||||||
|
void *pPixels);
|
||||||
|
|
||||||
|
#endif /* MTLMaskBlit_h_Included */
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* 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, BMTLSDOps * dstOps,
|
||||||
|
jint dstx, jint dsty,
|
||||||
|
jint width, jint height,
|
||||||
|
void *pPixels)
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
J2dTraceLn(J2D_TRACE_ERROR, "MTLMaskBlit_MaskBlit -- :TODO");
|
||||||
|
|
||||||
|
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, BMTLSDOps * dstOps,
|
||||||
|
jint x, jint y, jint w, jint h,
|
||||||
|
jint maskoff, jint maskscan, jint masklen,
|
||||||
|
unsigned char *pMask);
|
||||||
|
|
||||||
|
#endif /* MTLMaskFill_h_Included */
|
||||||
@@ -0,0 +1,153 @@
|
|||||||
|
/*
|
||||||
|
* 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, BMTLSDOps * dstOps,
|
||||||
|
jint x, jint y, jint w, jint h,
|
||||||
|
jint maskoff, jint maskscan, jint masklen,
|
||||||
|
unsigned char *pMask)
|
||||||
|
{
|
||||||
|
J2dTraceLn5(J2D_TRACE_INFO, "MTLMaskFill_MaskFill (x=%d y=%d w=%d h=%d pMask=%p)", x, y, w, h, dstOps->pTexture);
|
||||||
|
|
||||||
|
MTLVertexCache_EnableMaskCache(mtlc, dstOps);
|
||||||
|
jint tw, th, x0;
|
||||||
|
jint sx1, sy1, sx2, sy2;
|
||||||
|
jint sx, sy, sw, sh;
|
||||||
|
|
||||||
|
x0 = x;
|
||||||
|
tw = MTLVC_MASK_CACHE_TILE_WIDTH;
|
||||||
|
th = MTLVC_MASK_CACHE_TILE_HEIGHT;
|
||||||
|
sx1 = maskoff % maskscan;
|
||||||
|
sy1 = maskoff / maskscan;
|
||||||
|
sx2 = sx1 + w;
|
||||||
|
sy2 = sy1 + h;
|
||||||
|
|
||||||
|
|
||||||
|
for (sy = sy1; sy < sy2; sy += th, y += th) {
|
||||||
|
x = x0;
|
||||||
|
sh = ((sy + th) > sy2) ? (sy2 - sy) : th;
|
||||||
|
|
||||||
|
for (sx = sx1; sx < sx2; sx += tw, x += tw) {
|
||||||
|
sw = ((sx + tw) > sx2) ? (sx2 - sx) : tw;
|
||||||
|
MTLVertexCache_AddMaskQuad(mtlc,
|
||||||
|
sx, sy, x, y, sw, sh,
|
||||||
|
MTLVC_MASK_CACHE_TILE_WIDTH, pMask, dstOps,
|
||||||
|
MTLVC_MASK_CACHE_TILE_WIDTH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MTLVertexCache_FlushVertexCache(mtlc);
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
BMTLSDOps *dstOps = MTLRenderQueue_GetCurrentDestination();
|
||||||
|
unsigned char *mask;
|
||||||
|
|
||||||
|
J2dTraceLn(J2D_TRACE_ERROR, "MTLMaskFill_maskFill");
|
||||||
|
|
||||||
|
if (maskArray != NULL) {
|
||||||
|
mask = (unsigned char *)
|
||||||
|
(*env)->GetPrimitiveArrayCritical(env, maskArray, NULL);
|
||||||
|
} else {
|
||||||
|
mask = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
MTLMaskFill_MaskFill(mtlc, dstOps,
|
||||||
|
x, y, w, h,
|
||||||
|
maskoff, maskscan, masklen, mask);
|
||||||
|
|
||||||
|
if (mask != NULL) {
|
||||||
|
(*env)->ReleasePrimitiveArrayCritical(env, maskArray, mask, JNI_ABORT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* !HEADLESS */
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
#import <Metal/Metal.h>
|
||||||
|
|
||||||
|
#include "MTLSurfaceDataBase.h"
|
||||||
|
|
||||||
|
#define sun_java2d_SunGraphics2D_PAINT_UNDEFINED -1
|
||||||
|
|
||||||
|
@class MTLComposite;
|
||||||
|
@class MTLClip;
|
||||||
|
@class MTLPipelineStatesStorage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The MTLPaint class represents paint mode (color, gradient, e.t.c.)
|
||||||
|
* */
|
||||||
|
|
||||||
|
@interface MTLPaint : NSObject
|
||||||
|
- (id)init;
|
||||||
|
- (BOOL)isEqual:(MTLPaint *)other; // used to compare requested with cached
|
||||||
|
- (void)copyFrom:(MTLPaint *)other; // used to save cached
|
||||||
|
- (NSString *)getDescription;
|
||||||
|
- (jint)getColor;
|
||||||
|
- (void)reset;
|
||||||
|
|
||||||
|
- (void)setColor:(jint)pixelColor;
|
||||||
|
- (void)setGradientUseMask:(jboolean)useMask
|
||||||
|
cyclic:(jboolean)cyclic
|
||||||
|
p0:(jdouble)p0
|
||||||
|
p1:(jdouble)p1
|
||||||
|
p3:(jdouble)p3
|
||||||
|
pixel1:(jint)pixel1
|
||||||
|
pixel2:(jint)pixel2;
|
||||||
|
|
||||||
|
- (void)setLinearGradient:(jboolean)useMask
|
||||||
|
linear:(jboolean)linear
|
||||||
|
cycleMethod:(jboolean)cycleMethod
|
||||||
|
numStops:(jint)numStops
|
||||||
|
p0:(jfloat)p0
|
||||||
|
p1:(jfloat)p1
|
||||||
|
p3:(jfloat)p3
|
||||||
|
fractions:(void *)fractions
|
||||||
|
pixels:(void *)pixels;
|
||||||
|
|
||||||
|
- (void)setRadialGradient:(jboolean)useMask
|
||||||
|
linear:(jboolean)linear
|
||||||
|
cycleMethod:(jboolean)cycleMethod
|
||||||
|
numStops:(jint)numStops
|
||||||
|
m00:(jfloat)m00
|
||||||
|
m01:(jfloat)m01
|
||||||
|
m02:(jfloat)m02
|
||||||
|
m10:(jfloat)m10
|
||||||
|
m11:(jfloat)m11
|
||||||
|
m12:(jfloat)m12
|
||||||
|
focusX:(jfloat)focusX
|
||||||
|
fractions:(void *)fractions
|
||||||
|
pixels:(void *)pixels;
|
||||||
|
|
||||||
|
- (void)setTexture:(jboolean)useMask
|
||||||
|
textureID:(id<MTLTexture>)textureID
|
||||||
|
filter:(jboolean)filter
|
||||||
|
xp0:(jdouble)xp0
|
||||||
|
xp1:(jdouble)xp1
|
||||||
|
xp3:(jdouble)xp3
|
||||||
|
yp0:(jdouble)yp0
|
||||||
|
yp1:(jdouble)yp1
|
||||||
|
yp3:(jdouble)yp3;
|
||||||
|
|
||||||
|
// For the current paint mode and passed composite (and flags):
|
||||||
|
// 1. Selects vertex+fragment shader (and corresponding pipelineDesc) and set pipelineState
|
||||||
|
// 2. Prepares corresponding buffers of vertex and fragment shaders
|
||||||
|
- (void)setPipelineState:(id<MTLRenderCommandEncoder>)encoder
|
||||||
|
composite:(MTLComposite *)composite
|
||||||
|
isStencilUsed:(jboolean)isStencilUsed
|
||||||
|
isTexture:(jboolean)isTexture
|
||||||
|
srcFlags:(const SurfaceRasterFlags *)srcFlags
|
||||||
|
dstFlags:(const SurfaceRasterFlags *)dstFlags
|
||||||
|
pipelineStateStorage:(MTLPipelineStatesStorage *)pipelineStateStorage;
|
||||||
|
|
||||||
|
- (void)setXorModePipelineState:(id<MTLRenderCommandEncoder>)encoder
|
||||||
|
composite:(MTLComposite *)composite
|
||||||
|
isStencilUsed:(jboolean)isStencilUsed
|
||||||
|
isTexture:(jboolean)isTexture
|
||||||
|
srcFlags:(const SurfaceRasterFlags *)srcFlags
|
||||||
|
dstFlags:(const SurfaceRasterFlags *)dstFlags
|
||||||
|
pipelineStateStorage:(MTLPipelineStatesStorage *)pipelineStateStorage;
|
||||||
|
@end
|
||||||
|
|
||||||
|
#endif /* MTLPaints_h_Included */
|
||||||
@@ -0,0 +1,860 @@
|
|||||||
|
/*
|
||||||
|
* 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 "MTLPaints.h"
|
||||||
|
|
||||||
|
#include "MTLClip.h"
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#include "sun_java2d_SunGraphics2D.h"
|
||||||
|
#include "sun_java2d_pipe_BufferedPaints.h"
|
||||||
|
|
||||||
|
#define RGBA_TO_V4(c) \
|
||||||
|
{ \
|
||||||
|
(((c) >> 16) & (0xFF))/255.0f, \
|
||||||
|
(((c) >> 8) & 0xFF)/255.0f, \
|
||||||
|
((c) & 0xFF)/255.0f, \
|
||||||
|
(((c) >> 24) & 0xFF)/255.0f \
|
||||||
|
}
|
||||||
|
|
||||||
|
static MTLRenderPipelineDescriptor * templateRenderPipelineDesc = nil;
|
||||||
|
static MTLRenderPipelineDescriptor * templateTexturePipelineDesc = nil;
|
||||||
|
static MTLRenderPipelineDescriptor * templateAATexturePipelineDesc = nil;
|
||||||
|
|
||||||
|
static void initTemplatePipelineDescriptors() {
|
||||||
|
if (templateRenderPipelineDesc != nil && templateTexturePipelineDesc != nil)
|
||||||
|
return;
|
||||||
|
|
||||||
|
MTLVertexDescriptor *vertDesc = [[MTLVertexDescriptor new] autorelease];
|
||||||
|
vertDesc.attributes[VertexAttributePosition].format = MTLVertexFormatFloat2;
|
||||||
|
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;
|
||||||
|
|
||||||
|
templateRenderPipelineDesc = [[MTLRenderPipelineDescriptor new] autorelease];
|
||||||
|
templateRenderPipelineDesc.sampleCount = 1;
|
||||||
|
templateRenderPipelineDesc.vertexDescriptor = vertDesc;
|
||||||
|
templateRenderPipelineDesc.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;
|
||||||
|
templateRenderPipelineDesc.label = @"template_render";
|
||||||
|
|
||||||
|
templateTexturePipelineDesc = [[templateRenderPipelineDesc copy] autorelease];
|
||||||
|
templateTexturePipelineDesc.vertexDescriptor.attributes[VertexAttributeTexPos].format = MTLVertexFormatFloat2;
|
||||||
|
templateTexturePipelineDesc.vertexDescriptor.attributes[VertexAttributeTexPos].offset = 2*sizeof(float);
|
||||||
|
templateTexturePipelineDesc.vertexDescriptor.attributes[VertexAttributeTexPos].bufferIndex = MeshVertexBuffer;
|
||||||
|
templateTexturePipelineDesc.vertexDescriptor.layouts[MeshVertexBuffer].stride = sizeof(struct TxtVertex);
|
||||||
|
templateTexturePipelineDesc.vertexDescriptor.layouts[MeshVertexBuffer].stepRate = 1;
|
||||||
|
templateTexturePipelineDesc.vertexDescriptor.layouts[MeshVertexBuffer].stepFunction = MTLVertexStepFunctionPerVertex;
|
||||||
|
templateTexturePipelineDesc.label = @"template_texture";
|
||||||
|
|
||||||
|
templateAATexturePipelineDesc = [[templateTexturePipelineDesc copy] autorelease];
|
||||||
|
templateAATexturePipelineDesc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorOne;
|
||||||
|
templateAATexturePipelineDesc.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorOne;
|
||||||
|
templateAATexturePipelineDesc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
|
||||||
|
templateAATexturePipelineDesc.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
|
||||||
|
templateAATexturePipelineDesc.label = @"template_aa_texture";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@implementation MTLPaint {
|
||||||
|
// TODO: remove paintState, split into heirarchy of Paint-objects (i.e. PaintColor, PaintGrad, e.t.c)
|
||||||
|
jint _paintState;
|
||||||
|
|
||||||
|
// color-mode
|
||||||
|
jint _color;
|
||||||
|
|
||||||
|
// lin-grad-mode
|
||||||
|
jdouble _p0;
|
||||||
|
jdouble _p1;
|
||||||
|
jdouble _p3;
|
||||||
|
jboolean _cyclic;
|
||||||
|
jint _pixel1;
|
||||||
|
jint _pixel2;
|
||||||
|
jboolean _useMask;
|
||||||
|
|
||||||
|
// texture paint
|
||||||
|
id<MTLTexture> _paintTexture;
|
||||||
|
struct AnchorData _anchor;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)init {
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
_paintState = sun_java2d_SunGraphics2D_PAINT_UNDEFINED;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isEqual:(MTLPaint *)other {
|
||||||
|
if (self == other)
|
||||||
|
return YES;
|
||||||
|
if (_paintState == sun_java2d_SunGraphics2D_PAINT_UNDEFINED)
|
||||||
|
return _paintState == other->_paintState;
|
||||||
|
if (_paintState != other->_paintState)
|
||||||
|
return NO;
|
||||||
|
if (_paintState == sun_java2d_SunGraphics2D_PAINT_GRADIENT) {
|
||||||
|
return _p0 == other->_p0
|
||||||
|
&& _p1 == other->_p1
|
||||||
|
&& _p3 == other->_p3
|
||||||
|
&& _pixel1 == other->_pixel1
|
||||||
|
&& _pixel2 == other->_pixel2;
|
||||||
|
}
|
||||||
|
if (_paintState == sun_java2d_SunGraphics2D_PAINT_ALPHACOLOR) {
|
||||||
|
return _color == other->_color;
|
||||||
|
}
|
||||||
|
if (_paintState == sun_java2d_SunGraphics2D_PAINT_TEXTURE) {
|
||||||
|
return _paintTexture == other->_paintTexture
|
||||||
|
&& _anchor.xParams[0] == other->_anchor.xParams[0]
|
||||||
|
&& _anchor.xParams[1] == other->_anchor.xParams[1]
|
||||||
|
&& _anchor.xParams[2] == other->_anchor.xParams[2]
|
||||||
|
&& _anchor.yParams[0] == other->_anchor.yParams[0]
|
||||||
|
&& _anchor.yParams[1] == other->_anchor.yParams[1]
|
||||||
|
&& _anchor.yParams[2] == other->_anchor.yParams[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
J2dTraceLn1(J2D_TRACE_ERROR, "Unimplemented paint mode %d", _paintState);
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)copyFrom:(MTLPaint *)other {
|
||||||
|
_paintState = other->_paintState;
|
||||||
|
if (other->_paintState == sun_java2d_SunGraphics2D_PAINT_UNDEFINED)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (other->_paintState == sun_java2d_SunGraphics2D_PAINT_GRADIENT) {
|
||||||
|
_p0 = other->_p0;
|
||||||
|
_p1 = other->_p1;
|
||||||
|
_p3 = other->_p3;
|
||||||
|
_pixel1 = other->_pixel1;
|
||||||
|
_pixel2 = other->_pixel2;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_paintState == sun_java2d_SunGraphics2D_PAINT_ALPHACOLOR) {
|
||||||
|
_color = other->_color;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_paintState == sun_java2d_SunGraphics2D_PAINT_TEXTURE) {
|
||||||
|
_color = other->_color;
|
||||||
|
_paintTexture = other->_paintTexture;
|
||||||
|
_anchor = other->_anchor;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
J2dTraceLn1(J2D_TRACE_ERROR, "Unsupported paint mode %d", _paintState);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)getDescription {
|
||||||
|
if (_paintState == sun_java2d_SunGraphics2D_PAINT_ALPHACOLOR) {
|
||||||
|
return [NSString stringWithFormat:@"[r=%d g=%d b=%d a=%d]", (_color >> 16) & (0xFF), (_color >> 8) & 0xFF, (_color) & 0xFF, (_color >> 24) & 0xFF];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_paintState == sun_java2d_SunGraphics2D_PAINT_GRADIENT) {
|
||||||
|
return [NSString stringWithFormat:@"gradient"];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_paintState == sun_java2d_SunGraphics2D_PAINT_TEXTURE) {
|
||||||
|
return [NSString stringWithFormat:@"texture_paint"];
|
||||||
|
}
|
||||||
|
|
||||||
|
return @"unknown-paint";
|
||||||
|
}
|
||||||
|
|
||||||
|
- (jint)getColor {
|
||||||
|
return _color;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)reset {
|
||||||
|
_paintState = sun_java2d_SunGraphics2D_PAINT_UNDEFINED;
|
||||||
|
_paintTexture = nil;
|
||||||
|
_anchor.xParams[0] = _anchor.xParams[1] = _anchor.xParams[2] = 0.0f;
|
||||||
|
_anchor.yParams[0] = _anchor.yParams[1] = _anchor.yParams[2] = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setColor:(jint)pixelColor {
|
||||||
|
_paintState = sun_java2d_SunGraphics2D_PAINT_ALPHACOLOR;
|
||||||
|
_color = pixelColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setGradientUseMask:(jboolean)useMask
|
||||||
|
cyclic:(jboolean)cyclic
|
||||||
|
p0:(jdouble)p0
|
||||||
|
p1:(jdouble)p1
|
||||||
|
p3:(jdouble)p3
|
||||||
|
pixel1:(jint)pixel1
|
||||||
|
pixel2:(jint)pixel2
|
||||||
|
{
|
||||||
|
//TODO Resolve gradient distribution problem
|
||||||
|
//TODO Implement useMask
|
||||||
|
//TODO Implement cyclic
|
||||||
|
//fprintf(stderr,
|
||||||
|
// "MTLPaints_SetGradientPaint useMask=%d cyclic=%d "
|
||||||
|
// "p0=%f p1=%f p3=%f pix1=%d pix2=%d\n", useMask, cyclic,
|
||||||
|
// p0, p1, p3, pixel1, pixel2);
|
||||||
|
|
||||||
|
_paintState = sun_java2d_SunGraphics2D_PAINT_GRADIENT;
|
||||||
|
_useMask = useMask;
|
||||||
|
_pixel1 = pixel1;
|
||||||
|
_pixel2 = pixel2;
|
||||||
|
_p0 = p0;
|
||||||
|
_p1 = p1;
|
||||||
|
_p3 = p3;
|
||||||
|
_cyclic = cyclic;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setLinearGradient:(jboolean)useMask
|
||||||
|
linear:(jboolean)linear
|
||||||
|
cycleMethod:(jboolean)cycleMethod
|
||||||
|
numStops:(jint)numStops
|
||||||
|
p0:(jfloat)p0
|
||||||
|
p1:(jfloat)p1
|
||||||
|
p3:(jfloat)p3
|
||||||
|
fractions:(void *)fractions
|
||||||
|
pixels:(void *)pixels
|
||||||
|
{
|
||||||
|
J2dTraceLn(J2D_TRACE_ERROR, "setLinearGradient: UNIMPLEMENTED");
|
||||||
|
[self setColor:0];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setRadialGradient:(jboolean)useMask
|
||||||
|
linear:(jboolean)linear
|
||||||
|
cycleMethod:(jboolean)cycleMethod
|
||||||
|
numStops:(jint)numStops
|
||||||
|
m00:(jfloat)m00
|
||||||
|
m01:(jfloat)m01
|
||||||
|
m02:(jfloat)m02
|
||||||
|
m10:(jfloat)m10
|
||||||
|
m11:(jfloat)m11
|
||||||
|
m12:(jfloat)m12
|
||||||
|
focusX:(jfloat)focusX
|
||||||
|
fractions:(void *)fractions
|
||||||
|
pixels:(void *)pixels
|
||||||
|
{
|
||||||
|
J2dTraceLn(J2D_TRACE_ERROR, "setRadialGradient: UNIMPLEMENTED");
|
||||||
|
[self setColor:0];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setTexture:(jboolean)useMask
|
||||||
|
textureID:(id<MTLTexture>)textureID
|
||||||
|
filter:(jboolean)filter
|
||||||
|
xp0:(jdouble)xp0
|
||||||
|
xp1:(jdouble)xp1
|
||||||
|
xp3:(jdouble)xp3
|
||||||
|
yp0:(jdouble)yp0
|
||||||
|
yp1:(jdouble)yp1
|
||||||
|
yp3:(jdouble)yp3
|
||||||
|
{
|
||||||
|
_paintState = sun_java2d_SunGraphics2D_PAINT_TEXTURE;
|
||||||
|
_paintTexture = textureID;
|
||||||
|
|
||||||
|
_anchor.xParams[0] = xp0;
|
||||||
|
_anchor.xParams[1] = xp1;
|
||||||
|
_anchor.xParams[2] = xp3;
|
||||||
|
|
||||||
|
_anchor.yParams[0] = yp0;
|
||||||
|
_anchor.yParams[1] = yp1;
|
||||||
|
_anchor.yParams[2] = yp3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For the current paint mode:
|
||||||
|
// 1. Selects vertex+fragment shaders (and corresponding pipelineDesc) and set pipelineState
|
||||||
|
// 2. Set vertex and fragment buffers
|
||||||
|
- (void)setPipelineState:(id<MTLRenderCommandEncoder>)encoder
|
||||||
|
composite:(MTLComposite *)composite
|
||||||
|
isStencilUsed:(jboolean)isStencilUsed
|
||||||
|
isTexture:(jboolean)isTexture
|
||||||
|
isAA:(jboolean)isAA
|
||||||
|
srcFlags:(const SurfaceRasterFlags *)srcFlags
|
||||||
|
dstFlags:(const SurfaceRasterFlags *)dstFlags
|
||||||
|
pipelineStateStorage:(MTLPipelineStatesStorage *)pipelineStateStorage
|
||||||
|
{
|
||||||
|
initTemplatePipelineDescriptors();
|
||||||
|
|
||||||
|
const bool stencil = isStencilUsed == JNI_TRUE;
|
||||||
|
|
||||||
|
id<MTLRenderPipelineState> pipelineState = nil;
|
||||||
|
if (isTexture) {
|
||||||
|
|
||||||
|
if (_paintState == sun_java2d_SunGraphics2D_PAINT_TEXTURE) {
|
||||||
|
pipelineState = [pipelineStateStorage getPipelineState:templateTexturePipelineDesc
|
||||||
|
vertexShaderId:@"vert_txt_tp"
|
||||||
|
fragmentShaderId:@"frag_txt_tp"
|
||||||
|
compositeRule:[composite getRule]
|
||||||
|
isAA:JNI_FALSE
|
||||||
|
srcFlags:srcFlags
|
||||||
|
dstFlags:dstFlags
|
||||||
|
stencilNeeded:stencil];
|
||||||
|
[encoder setVertexBytes:&_anchor length:sizeof(_anchor) atIndex:FrameUniformBuffer];
|
||||||
|
[encoder setFragmentTexture:_paintTexture atIndex: 1];
|
||||||
|
|
||||||
|
struct TxtFrameUniforms uf = {RGBA_TO_V4(0), 0, srcFlags->isOpaque,
|
||||||
|
dstFlags->isOpaque};
|
||||||
|
[encoder setFragmentBytes:&uf length:sizeof(uf)
|
||||||
|
atIndex:FrameUniformBuffer];
|
||||||
|
|
||||||
|
} else if (_paintState == sun_java2d_SunGraphics2D_PAINT_GRADIENT) {
|
||||||
|
pipelineState = [pipelineStateStorage getPipelineState:templateTexturePipelineDesc
|
||||||
|
vertexShaderId:@"vert_txt_grad"
|
||||||
|
fragmentShaderId:@"frag_txt_grad"
|
||||||
|
compositeRule:[composite getRule]
|
||||||
|
isAA:JNI_FALSE
|
||||||
|
srcFlags:srcFlags
|
||||||
|
dstFlags:dstFlags
|
||||||
|
stencilNeeded:stencil];
|
||||||
|
struct GradFrameUniforms uf = {
|
||||||
|
{_p0, _p1, _p3},
|
||||||
|
RGBA_TO_V4(_pixel1),
|
||||||
|
RGBA_TO_V4(_pixel2)};
|
||||||
|
[encoder setFragmentBytes: &uf length:sizeof(uf) atIndex:0];
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (isAA) {
|
||||||
|
pipelineState = [pipelineStateStorage
|
||||||
|
getPipelineState:templateAATexturePipelineDesc
|
||||||
|
vertexShaderId:@"vert_txt"
|
||||||
|
fragmentShaderId:@"aa_frag_txt"
|
||||||
|
compositeRule:[composite getRule]
|
||||||
|
isAA:JNI_FALSE
|
||||||
|
srcFlags:srcFlags
|
||||||
|
dstFlags:dstFlags
|
||||||
|
stencilNeeded:stencil];
|
||||||
|
|
||||||
|
} else {
|
||||||
|
pipelineState =
|
||||||
|
[pipelineStateStorage getPipelineState:templateTexturePipelineDesc
|
||||||
|
vertexShaderId:@"vert_txt"
|
||||||
|
fragmentShaderId:@"frag_txt"
|
||||||
|
compositeRule:[composite getRule]
|
||||||
|
isAA:JNI_FALSE
|
||||||
|
srcFlags:srcFlags
|
||||||
|
dstFlags:dstFlags
|
||||||
|
stencilNeeded:stencil];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_paintState == sun_java2d_SunGraphics2D_PAINT_ALPHACOLOR) {
|
||||||
|
struct TxtFrameUniforms uf = {RGBA_TO_V4(_color), 1, srcFlags->isOpaque, dstFlags->isOpaque };
|
||||||
|
[encoder setFragmentBytes:&uf length:sizeof(uf) atIndex:FrameUniformBuffer];
|
||||||
|
} else {
|
||||||
|
struct TxtFrameUniforms uf = {RGBA_TO_V4(0), 0, srcFlags->isOpaque, dstFlags->isOpaque };
|
||||||
|
[encoder setFragmentBytes:&uf length:sizeof(uf) atIndex:FrameUniformBuffer];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (_paintState == sun_java2d_SunGraphics2D_PAINT_ALPHACOLOR) {
|
||||||
|
pipelineState = [pipelineStateStorage getPipelineState:templateRenderPipelineDesc
|
||||||
|
vertexShaderId:@"vert_col"
|
||||||
|
fragmentShaderId:@"frag_col"
|
||||||
|
compositeRule:[composite getRule]
|
||||||
|
isAA:isAA
|
||||||
|
srcFlags:srcFlags
|
||||||
|
dstFlags:dstFlags
|
||||||
|
stencilNeeded:stencil];
|
||||||
|
|
||||||
|
struct FrameUniforms uf = {RGBA_TO_V4(_color)};
|
||||||
|
[encoder setVertexBytes:&uf length:sizeof(uf) atIndex:FrameUniformBuffer];
|
||||||
|
} else if (_paintState == sun_java2d_SunGraphics2D_PAINT_GRADIENT) {
|
||||||
|
pipelineState = [pipelineStateStorage getPipelineState:templateRenderPipelineDesc
|
||||||
|
vertexShaderId:@"vert_grad"
|
||||||
|
fragmentShaderId:@"frag_grad"
|
||||||
|
compositeRule:[composite getRule]
|
||||||
|
isAA:isAA
|
||||||
|
srcFlags:srcFlags
|
||||||
|
dstFlags:dstFlags
|
||||||
|
stencilNeeded:stencil];
|
||||||
|
|
||||||
|
struct GradFrameUniforms uf = {
|
||||||
|
{_p0, _p1, _p3},
|
||||||
|
RGBA_TO_V4(_pixel1),
|
||||||
|
RGBA_TO_V4(_pixel2)};
|
||||||
|
[encoder setFragmentBytes: &uf length:sizeof(uf) atIndex:0];
|
||||||
|
} else if (_paintState == sun_java2d_SunGraphics2D_PAINT_TEXTURE) {
|
||||||
|
pipelineState = [pipelineStateStorage getPipelineState:templateRenderPipelineDesc
|
||||||
|
vertexShaderId:@"vert_tp"
|
||||||
|
fragmentShaderId:@"frag_tp"
|
||||||
|
compositeRule:[composite getRule]
|
||||||
|
isAA:isAA
|
||||||
|
srcFlags:srcFlags
|
||||||
|
dstFlags:dstFlags
|
||||||
|
stencilNeeded:stencil];
|
||||||
|
|
||||||
|
[encoder setVertexBytes:&_anchor length:sizeof(_anchor) atIndex:FrameUniformBuffer];
|
||||||
|
[encoder setFragmentTexture:_paintTexture atIndex: 0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[encoder setRenderPipelineState:pipelineState];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// For the current paint mode: and for XOR composite - a separate method is added as fragment shader differ in some cases
|
||||||
|
// 1. Selects vertex+fragment shaders (and corresponding pipelineDesc) and set pipelineState
|
||||||
|
// 2. Set vertex and fragment buffers
|
||||||
|
- (void)setXorModePipelineState:(id<MTLRenderCommandEncoder>)encoder
|
||||||
|
composite:(MTLComposite *)composite
|
||||||
|
isStencilUsed:(jboolean)isStencilUsed
|
||||||
|
isTexture:(jboolean)isTexture
|
||||||
|
srcFlags:(const SurfaceRasterFlags *)srcFlags
|
||||||
|
dstFlags:(const SurfaceRasterFlags *)dstFlags
|
||||||
|
pipelineStateStorage:(MTLPipelineStatesStorage *)pipelineStateStorage {
|
||||||
|
initTemplatePipelineDescriptors();
|
||||||
|
|
||||||
|
const bool stencil = isStencilUsed == JNI_TRUE;
|
||||||
|
jint xorColor = (jint) [composite getXorColor];
|
||||||
|
|
||||||
|
id<MTLRenderPipelineState> pipelineState = nil;
|
||||||
|
if (isTexture) {
|
||||||
|
pipelineState = [pipelineStateStorage getXorModePipelineState:templateTexturePipelineDesc
|
||||||
|
vertexShaderId:@"vert_txt"
|
||||||
|
fragmentShaderId:@"frag_txt"
|
||||||
|
srcFlags:srcFlags
|
||||||
|
dstFlags:dstFlags
|
||||||
|
stencilNeeded:stencil];
|
||||||
|
|
||||||
|
if (_paintState == sun_java2d_SunGraphics2D_PAINT_ALPHACOLOR) {
|
||||||
|
struct TxtFrameUniforms uf = {RGBA_TO_V4(_color ^ xorColor), 1, srcFlags->isOpaque, dstFlags->isOpaque };
|
||||||
|
[encoder setFragmentBytes:&uf length:sizeof(uf) atIndex:FrameUniformBuffer];
|
||||||
|
} else {
|
||||||
|
struct TxtFrameUniforms uf = {RGBA_TO_V4(0 ^ xorColor), 0, srcFlags->isOpaque, dstFlags->isOpaque };
|
||||||
|
[encoder setFragmentBytes:&uf length:sizeof(uf) atIndex:FrameUniformBuffer];
|
||||||
|
}
|
||||||
|
[encoder setFragmentBytes:&xorColor length:sizeof(xorColor) atIndex: 0];
|
||||||
|
} else {
|
||||||
|
if (_paintState == sun_java2d_SunGraphics2D_PAINT_ALPHACOLOR) {
|
||||||
|
|
||||||
|
pipelineState = [pipelineStateStorage getXorModePipelineState:templateRenderPipelineDesc
|
||||||
|
vertexShaderId:@"vert_col"
|
||||||
|
fragmentShaderId:@"frag_col"
|
||||||
|
srcFlags:srcFlags
|
||||||
|
dstFlags:dstFlags
|
||||||
|
stencilNeeded:stencil];
|
||||||
|
|
||||||
|
// Calculate _color ^ xorColor for RGB components
|
||||||
|
// This color gets XORed with destination framebuffer pixel color
|
||||||
|
struct FrameUniforms uf = {RGBA_TO_V4(_color ^ xorColor)};
|
||||||
|
[encoder setVertexBytes:&uf length:sizeof(uf) atIndex:FrameUniformBuffer];
|
||||||
|
|
||||||
|
} else if (_paintState == sun_java2d_SunGraphics2D_PAINT_GRADIENT) {
|
||||||
|
|
||||||
|
pipelineState = [pipelineStateStorage getXorModePipelineState:templateRenderPipelineDesc
|
||||||
|
vertexShaderId:@"vert_grad"
|
||||||
|
fragmentShaderId:@"frag_grad"
|
||||||
|
srcFlags:srcFlags
|
||||||
|
dstFlags:dstFlags
|
||||||
|
stencilNeeded:stencil];
|
||||||
|
|
||||||
|
struct GradFrameUniforms uf = {
|
||||||
|
{_p0, _p1, _p3},
|
||||||
|
RGBA_TO_V4(_pixel1 ^ xorColor),
|
||||||
|
RGBA_TO_V4(_pixel2 ^ xorColor)};
|
||||||
|
[encoder setFragmentBytes: &uf length:sizeof(uf) atIndex:0];
|
||||||
|
} else if (_paintState == sun_java2d_SunGraphics2D_PAINT_TEXTURE) {
|
||||||
|
|
||||||
|
pipelineState = [pipelineStateStorage getXorModePipelineState:templateRenderPipelineDesc
|
||||||
|
vertexShaderId:@"vert_tp"
|
||||||
|
fragmentShaderId:@"frag_tp_xorMode"
|
||||||
|
srcFlags:srcFlags
|
||||||
|
dstFlags:dstFlags
|
||||||
|
stencilNeeded:stencil];
|
||||||
|
|
||||||
|
[encoder setVertexBytes:&_anchor length:sizeof(_anchor) atIndex:FrameUniformBuffer];
|
||||||
|
[encoder setFragmentTexture:_paintTexture atIndex: 0];
|
||||||
|
[encoder setFragmentBytes:&xorColor length:sizeof(xorColor) atIndex: 0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[encoder setRenderPipelineState:pipelineState];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
/************************* GradientPaint support ****************************/
|
||||||
|
|
||||||
|
static void
|
||||||
|
MTLPaints_InitGradientTexture()
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLPaints_InitGradientTexture -- :TODO");
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************** 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()
|
||||||
|
{
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLPaints_InitMultiGradientTexture -- :TODO");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compiles and links the MultipleGradientPaint shader program. If
|
||||||
|
* successful, this function returns a handle to the newly created
|
||||||
|
* shader program; otherwise returns 0.
|
||||||
|
*/
|
||||||
|
static void*
|
||||||
|
MTLPaints_CreateMultiGradProgram(jint flags,
|
||||||
|
char *paintVars, char *distCode)
|
||||||
|
{
|
||||||
|
|
||||||
|
//TODO
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLPaints_CreateMultiGradProgram -- :TODO");
|
||||||
|
|
||||||
|
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(void* multiGradProgram,
|
||||||
|
jint numStops,
|
||||||
|
void *pFractions, void *pPixels)
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLPaints_SetMultiGradientPaint -- :TODO");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************** 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 void* 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 void*
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************** 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 void* 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 void*
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* !HEADLESS */
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
#ifndef MTLPipelineStatesStorage_h_Included
|
||||||
|
#define MTLPipelineStatesStorage_h_Included
|
||||||
|
|
||||||
|
#import "MTLUtils.h"
|
||||||
|
#include "MTLSurfaceDataBase.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The MTLPipelineStatesStorage class used to obtain MTLRenderPipelineState
|
||||||
|
* */
|
||||||
|
|
||||||
|
|
||||||
|
@interface MTLPipelineStatesStorage : NSObject {
|
||||||
|
@private
|
||||||
|
|
||||||
|
id<MTLDevice> device;
|
||||||
|
id<MTLLibrary> library;
|
||||||
|
NSMutableDictionary<NSString*, id<MTLFunction>> * shaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
@property (readwrite, assign) id<MTLDevice> device;
|
||||||
|
@property (readwrite, retain) id<MTLLibrary> library;
|
||||||
|
@property (readwrite, retain) NSMutableDictionary<NSString*, id<MTLFunction>> * shaders;
|
||||||
|
@property (readwrite, retain) NSMutableDictionary<NSString*, NSMutableDictionary *> * states;
|
||||||
|
|
||||||
|
- (id) initWithDevice:(id<MTLDevice>)device shaderLibPath:(NSString *)shadersLib;
|
||||||
|
|
||||||
|
// returns pipelineState with disabled blending and stencil
|
||||||
|
- (id<MTLRenderPipelineState>) getPipelineState:(MTLRenderPipelineDescriptor *) pipelineDescriptor
|
||||||
|
vertexShaderId:(NSString *)vertexShaderId
|
||||||
|
fragmentShaderId:(NSString *)fragmentShaderId;
|
||||||
|
|
||||||
|
// returns pipelineState with composite for default SurfaceRasterFlags
|
||||||
|
- (id<MTLRenderPipelineState>) getPipelineState:(MTLRenderPipelineDescriptor *) pipelineDescriptor
|
||||||
|
vertexShaderId:(NSString *)vertexShaderId
|
||||||
|
fragmentShaderId:(NSString *)fragmentShaderId
|
||||||
|
compositeRule:(jint)compositeRule
|
||||||
|
stencilNeeded:(bool)stencilNeeded;
|
||||||
|
|
||||||
|
// base method to obtain MTLRenderPipelineState
|
||||||
|
- (id<MTLRenderPipelineState>) getPipelineState:(MTLRenderPipelineDescriptor *) pipelineDescriptor
|
||||||
|
vertexShaderId:(NSString *)vertexShaderId
|
||||||
|
fragmentShaderId:(NSString *)fragmentShaderId
|
||||||
|
compositeRule:(jint)compositeRule
|
||||||
|
srcFlags:(const SurfaceRasterFlags * )srcFlags
|
||||||
|
dstFlags:(const SurfaceRasterFlags * )dstFlags
|
||||||
|
stencilNeeded:(bool)stencilNeeded;
|
||||||
|
|
||||||
|
- (id<MTLRenderPipelineState>) getPipelineState:(MTLRenderPipelineDescriptor *) pipelineDescriptor
|
||||||
|
vertexShaderId:(NSString *)vertexShaderId
|
||||||
|
fragmentShaderId:(NSString *)fragmentShaderId
|
||||||
|
compositeRule:(jint)compositeRule
|
||||||
|
isAA:(jboolean)isAA
|
||||||
|
srcFlags:(const SurfaceRasterFlags *)srcFlags
|
||||||
|
dstFlags:(const SurfaceRasterFlags *)dstFlags
|
||||||
|
stencilNeeded:(bool)stencilNeeded;
|
||||||
|
|
||||||
|
- (id<MTLRenderPipelineState>) getXorModePipelineState:(MTLRenderPipelineDescriptor *) pipelineDescriptor
|
||||||
|
vertexShaderId:(NSString *)vertexShaderId
|
||||||
|
fragmentShaderId:(NSString *)fragmentShaderId
|
||||||
|
srcFlags:(const SurfaceRasterFlags * )srcFlags
|
||||||
|
dstFlags:(const SurfaceRasterFlags * )dstFlags
|
||||||
|
stencilNeeded:(bool)stencilNeeded;
|
||||||
|
- (id<MTLFunction>) getShader:(NSString *)name;
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
#endif // MTLPipelineStatesStorage_h_Included
|
||||||
@@ -0,0 +1,389 @@
|
|||||||
|
#import "MTLPipelineStatesStorage.h"
|
||||||
|
|
||||||
|
#include "GraphicsPrimitiveMgr.h"
|
||||||
|
|
||||||
|
// A special value for xor composite
|
||||||
|
const int XOR_COMPOSITE_RULE = 20;
|
||||||
|
|
||||||
|
extern const SurfaceRasterFlags defaultRasterFlags;
|
||||||
|
|
||||||
|
static void setBlendingFactors(
|
||||||
|
MTLRenderPipelineColorAttachmentDescriptor * cad,
|
||||||
|
int compositeRule,
|
||||||
|
const SurfaceRasterFlags * srcFlags, const SurfaceRasterFlags * dstFlags);
|
||||||
|
|
||||||
|
@implementation MTLPipelineStatesStorage
|
||||||
|
|
||||||
|
@synthesize device;
|
||||||
|
@synthesize library;
|
||||||
|
@synthesize shaders;
|
||||||
|
@synthesize states;
|
||||||
|
|
||||||
|
- (id) initWithDevice:(id<MTLDevice>)dev shaderLibPath:(NSString *)shadersLib {
|
||||||
|
self = [super init];
|
||||||
|
if (self == nil) return self;
|
||||||
|
|
||||||
|
self.device = dev;
|
||||||
|
|
||||||
|
NSError *error = nil;
|
||||||
|
self.library = [dev newLibraryWithFile:shadersLib error:&error];
|
||||||
|
if (!self.library) {
|
||||||
|
NSLog(@"Failed to load library. error %@", error);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
self.shaders = [NSMutableDictionary dictionaryWithCapacity:10];
|
||||||
|
self.states = [NSMutableDictionary dictionaryWithCapacity:10];
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSPointerArray * ) getSubStates:(NSString *)vertexShaderId fragmentShader:(NSString *)fragmentShaderId {
|
||||||
|
NSMutableDictionary * vSubStates = states[vertexShaderId];
|
||||||
|
if (vSubStates == nil) {
|
||||||
|
@autoreleasepool {
|
||||||
|
vSubStates = [NSMutableDictionary dictionary];
|
||||||
|
[states setObject:vSubStates forKey:vertexShaderId];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NSPointerArray * sSubStates = vSubStates[fragmentShaderId];
|
||||||
|
if (sSubStates == nil) {
|
||||||
|
@autoreleasepool {
|
||||||
|
sSubStates = [NSPointerArray strongObjectsPointerArray];
|
||||||
|
[vSubStates setObject:sSubStates forKey:fragmentShaderId];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sSubStates;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id<MTLRenderPipelineState>) getPipelineState:(MTLRenderPipelineDescriptor *) pipelineDescriptor
|
||||||
|
vertexShaderId:(NSString *)vertexShaderId
|
||||||
|
fragmentShaderId:(NSString *)fragmentShaderId
|
||||||
|
{
|
||||||
|
return [self getPipelineState:pipelineDescriptor
|
||||||
|
vertexShaderId:vertexShaderId
|
||||||
|
fragmentShaderId:fragmentShaderId
|
||||||
|
compositeRule:RULE_Src
|
||||||
|
srcFlags:NULL
|
||||||
|
dstFlags:NULL
|
||||||
|
stencilNeeded:NO];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id<MTLRenderPipelineState>) getPipelineState:(MTLRenderPipelineDescriptor *) pipelineDescriptor
|
||||||
|
vertexShaderId:(NSString *)vertexShaderId
|
||||||
|
fragmentShaderId:(NSString *)fragmentShaderId
|
||||||
|
compositeRule:(jint)compositeRule
|
||||||
|
stencilNeeded:(bool)stencilNeeded;
|
||||||
|
{
|
||||||
|
return [self getPipelineState:pipelineDescriptor
|
||||||
|
vertexShaderId:vertexShaderId
|
||||||
|
fragmentShaderId:fragmentShaderId
|
||||||
|
compositeRule:compositeRule
|
||||||
|
srcFlags:&defaultRasterFlags
|
||||||
|
dstFlags:&defaultRasterFlags
|
||||||
|
stencilNeeded:stencilNeeded];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id<MTLRenderPipelineState>) getPipelineState:(MTLRenderPipelineDescriptor *) pipelineDescriptor
|
||||||
|
vertexShaderId:(NSString *)vertexShaderId
|
||||||
|
fragmentShaderId:(NSString *)fragmentShaderId
|
||||||
|
compositeRule:(jint)compositeRule
|
||||||
|
srcFlags:(const SurfaceRasterFlags *)srcFlags
|
||||||
|
dstFlags:(const SurfaceRasterFlags *)dstFlags
|
||||||
|
stencilNeeded:(bool)stencilNeeded;
|
||||||
|
{
|
||||||
|
return [self getPipelineState:pipelineDescriptor
|
||||||
|
vertexShaderId:vertexShaderId
|
||||||
|
fragmentShaderId:fragmentShaderId
|
||||||
|
compositeRule:compositeRule
|
||||||
|
isAA:JNI_FALSE
|
||||||
|
srcFlags:srcFlags
|
||||||
|
dstFlags:dstFlags
|
||||||
|
stencilNeeded:stencilNeeded];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Base method to obtain MTLRenderPipelineState.
|
||||||
|
// NOTE: parameters compositeRule, srcFlags, dstFlags are used to set MTLRenderPipelineColorAttachmentDescriptor multipliers
|
||||||
|
- (id<MTLRenderPipelineState>) getPipelineState:(MTLRenderPipelineDescriptor *) pipelineDescriptor
|
||||||
|
vertexShaderId:(NSString *)vertexShaderId
|
||||||
|
fragmentShaderId:(NSString *)fragmentShaderId
|
||||||
|
compositeRule:(jint)compositeRule
|
||||||
|
isAA:(jboolean)isAA
|
||||||
|
srcFlags:(const SurfaceRasterFlags *)srcFlags
|
||||||
|
dstFlags:(const SurfaceRasterFlags *)dstFlags
|
||||||
|
stencilNeeded:(bool)stencilNeeded;
|
||||||
|
{
|
||||||
|
const jboolean useXorComposite = (compositeRule == XOR_COMPOSITE_RULE);
|
||||||
|
const jboolean useComposite = compositeRule >= 0
|
||||||
|
&& compositeRule < java_awt_AlphaComposite_MAX_RULE
|
||||||
|
&& srcFlags != NULL && dstFlags != NULL;
|
||||||
|
|
||||||
|
// Calculate index by flags and compositeRule
|
||||||
|
// TODO: reimplement, use map with convenient key (calculated by all arguments)
|
||||||
|
int subIndex = 0;
|
||||||
|
if (useXorComposite) {
|
||||||
|
// compositeRule value is already XOR_COMPOSITE_RULE
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (useComposite) {
|
||||||
|
if (!srcFlags->isPremultiplied)
|
||||||
|
subIndex |= 1;
|
||||||
|
if (srcFlags->isOpaque)
|
||||||
|
subIndex |= 1 << 1;
|
||||||
|
if (!dstFlags->isPremultiplied)
|
||||||
|
subIndex |= 1 << 2;
|
||||||
|
if (dstFlags->isOpaque)
|
||||||
|
subIndex |= 1 << 3;
|
||||||
|
} else
|
||||||
|
compositeRule = RULE_Src;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stencilNeeded) {
|
||||||
|
subIndex |= 1 << 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isAA) {
|
||||||
|
subIndex |= 1 << 5;
|
||||||
|
}
|
||||||
|
int index = compositeRule*64 + subIndex;
|
||||||
|
|
||||||
|
NSPointerArray * subStates = [self getSubStates:vertexShaderId fragmentShader:fragmentShaderId];
|
||||||
|
while (index >= [subStates count]) {
|
||||||
|
[subStates addPointer:NULL]; // obj-c collections haven't resize methods, so do that
|
||||||
|
}
|
||||||
|
|
||||||
|
id<MTLRenderPipelineState> result = [subStates pointerAtIndex:index];
|
||||||
|
if (result == nil) {
|
||||||
|
@autoreleasepool {
|
||||||
|
id <MTLFunction> vertexShader = [self getShader:vertexShaderId];
|
||||||
|
id <MTLFunction> fragmentShader = [self getShader:fragmentShaderId];
|
||||||
|
MTLRenderPipelineDescriptor *pipelineDesc = [[pipelineDescriptor copy] autorelease];
|
||||||
|
pipelineDesc.vertexFunction = vertexShader;
|
||||||
|
pipelineDesc.fragmentFunction = fragmentShader;
|
||||||
|
|
||||||
|
if (useXorComposite) {
|
||||||
|
pipelineDesc.colorAttachments[0].blendingEnabled = YES;
|
||||||
|
|
||||||
|
pipelineDesc.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd;
|
||||||
|
pipelineDesc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorOneMinusDestinationColor;
|
||||||
|
pipelineDesc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceColor;
|
||||||
|
|
||||||
|
} else if (useComposite) {
|
||||||
|
setBlendingFactors(
|
||||||
|
pipelineDesc.colorAttachments[0],
|
||||||
|
compositeRule,
|
||||||
|
srcFlags, dstFlags
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (stencilNeeded) {
|
||||||
|
pipelineDesc.stencilAttachmentPixelFormat = MTLPixelFormatStencil8;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isAA) {
|
||||||
|
pipelineDesc.sampleCount = MTLAASampleCount;
|
||||||
|
pipelineDesc.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd;
|
||||||
|
pipelineDesc.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd;
|
||||||
|
pipelineDesc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha;
|
||||||
|
pipelineDesc.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorSourceAlpha;
|
||||||
|
pipelineDesc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
|
||||||
|
pipelineDesc.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
|
||||||
|
pipelineDesc.colorAttachments[0].blendingEnabled = YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSError *error = nil;
|
||||||
|
result = [[self.device newRenderPipelineStateWithDescriptor:pipelineDesc error:&error] autorelease];
|
||||||
|
if (result == nil) {
|
||||||
|
NSLog(@"Failed to create pipeline state, error %@", error);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[subStates insertPointer:result atIndex:index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id<MTLFunction>) getShader:(NSString *)name {
|
||||||
|
id<MTLFunction> result = [self.shaders valueForKey:name];
|
||||||
|
if (result == nil) {
|
||||||
|
result = [[self.library newFunctionWithName:name] autorelease];
|
||||||
|
[self.shaders setValue:result forKey:name];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id<MTLRenderPipelineState>) getXorModePipelineState:(MTLRenderPipelineDescriptor *) pipelineDescriptor
|
||||||
|
vertexShaderId:(NSString *)vertexShaderId
|
||||||
|
fragmentShaderId:(NSString *)fragmentShaderId
|
||||||
|
srcFlags:(const SurfaceRasterFlags * )srcFlags
|
||||||
|
dstFlags:(const SurfaceRasterFlags * )dstFlags
|
||||||
|
stencilNeeded:(bool)stencilNeeded {
|
||||||
|
return [self getPipelineState:pipelineDescriptor
|
||||||
|
vertexShaderId:vertexShaderId
|
||||||
|
fragmentShaderId:fragmentShaderId
|
||||||
|
compositeRule:XOR_COMPOSITE_RULE
|
||||||
|
srcFlags:NULL
|
||||||
|
dstFlags:NULL
|
||||||
|
stencilNeeded:stencilNeeded];
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
static void setBlendingFactors(
|
||||||
|
MTLRenderPipelineColorAttachmentDescriptor * cad,
|
||||||
|
int compositeRule,
|
||||||
|
const SurfaceRasterFlags * srcFlags,
|
||||||
|
const SurfaceRasterFlags * dstFlags
|
||||||
|
) {
|
||||||
|
if (compositeRule == RULE_Src) {
|
||||||
|
J2dTraceLn(J2D_TRACE_VERBOSE, "set RULE_Src");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cad.blendingEnabled = YES;
|
||||||
|
|
||||||
|
// RGB = Source.rgb * SBFc + Dest.rgb * DBFc
|
||||||
|
// A = Source.a * SBFa + Dest.a * DBFa
|
||||||
|
//
|
||||||
|
// default mode == RULE_Src with constants:
|
||||||
|
// DBFa=0
|
||||||
|
// DBFc=0
|
||||||
|
// SBFa=1
|
||||||
|
// SBFc=1
|
||||||
|
//
|
||||||
|
// NOTE: constants MTLBlendFactorBlendAlpha, MTLBlendFactorOneMinusBlendAlpha refers to [encoder setBlendColorRed:green:blue:alpha:] (default value is zero)
|
||||||
|
//
|
||||||
|
// TODO: implement alpha-composite via shaders (will be much more simpler and can support all rules and modes)
|
||||||
|
|
||||||
|
switch (compositeRule) {
|
||||||
|
case RULE_SrcOver: {
|
||||||
|
// Ar = As + Ad*(1-As)
|
||||||
|
// Cr = Cs + Cd*(1-As)
|
||||||
|
if (srcFlags->isOpaque) {
|
||||||
|
J2dTraceLn(J2D_TRACE_VERBOSE, "rule=RULE_Src, but blending is disabled because src is opaque");
|
||||||
|
cad.blendingEnabled = NO;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (dstFlags->isOpaque) {
|
||||||
|
// Ar = 1, can be ignored, so
|
||||||
|
// Cr = Cs + Cd*(1-As)
|
||||||
|
// TODO: select any multiplier with best performance
|
||||||
|
// for example: cad.destinationAlphaBlendFactor = MTLBlendFactorZero;
|
||||||
|
} else {
|
||||||
|
cad.destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
|
||||||
|
}
|
||||||
|
if (!srcFlags->isPremultiplied) {
|
||||||
|
cad.sourceRGBBlendFactor = MTLBlendFactorSourceAlpha;
|
||||||
|
}
|
||||||
|
cad.destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
|
||||||
|
J2dTraceLn(J2D_TRACE_VERBOSE, "set RULE_SrcOver");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RULE_DstOver: {
|
||||||
|
// Ar = As*(1-Ad) + Ad
|
||||||
|
// Cr = Cs*(1-Ad) + Cd
|
||||||
|
if (srcFlags->isOpaque) {
|
||||||
|
J2dTraceLn(J2D_TRACE_ERROR, "Composite rule RULE_DstOver with opaque src isn't implemented (src alpha won't be ignored)");
|
||||||
|
}
|
||||||
|
if (dstFlags->isOpaque) {
|
||||||
|
J2dTraceLn(J2D_TRACE_ERROR, "Composite rule RULE_DstOver with opaque dest hasn't any sense");
|
||||||
|
}
|
||||||
|
if (!srcFlags->isPremultiplied) {
|
||||||
|
J2dTrace(J2D_TRACE_ERROR, "Composite rule RULE_DstOver with non-premultiplied source isn't implemented (scr alpha will be ignored for rgb-component)");
|
||||||
|
}
|
||||||
|
cad.sourceAlphaBlendFactor = MTLBlendFactorOneMinusDestinationAlpha;
|
||||||
|
cad.sourceRGBBlendFactor = MTLBlendFactorOneMinusDestinationAlpha;
|
||||||
|
cad.destinationAlphaBlendFactor = MTLBlendFactorOne;
|
||||||
|
cad.destinationRGBBlendFactor = MTLBlendFactorOne;
|
||||||
|
J2dTraceLn(J2D_TRACE_VERBOSE, "set RULE_DstOver");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RULE_SrcIn: {
|
||||||
|
// Ar = As*Ad
|
||||||
|
// Cr = Cs*Ad
|
||||||
|
if (srcFlags->isOpaque) {
|
||||||
|
J2dTraceLn(J2D_TRACE_ERROR, "Composite rule RULE_SrcIn with opaque src isn't implemented (src alpha won't be ignored)");
|
||||||
|
}
|
||||||
|
if (dstFlags->isOpaque) {
|
||||||
|
J2dTraceLn(J2D_TRACE_VERBOSE, "rule=RULE_SrcIn, but blending is disabled because dest is opaque");
|
||||||
|
cad.blendingEnabled = NO;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!srcFlags->isPremultiplied) {
|
||||||
|
J2dTrace(J2D_TRACE_ERROR, "Composite rule RULE_SrcIn with non-premultiplied source isn't implemented (scr alpha will be ignored for rgb-component)");
|
||||||
|
}
|
||||||
|
cad.sourceAlphaBlendFactor = MTLBlendFactorDestinationAlpha;
|
||||||
|
cad.sourceRGBBlendFactor = MTLBlendFactorDestinationAlpha;
|
||||||
|
cad.destinationAlphaBlendFactor = MTLBlendFactorZero;
|
||||||
|
cad.destinationRGBBlendFactor = MTLBlendFactorZero;
|
||||||
|
J2dTraceLn(J2D_TRACE_VERBOSE, "set RULE_SrcIn");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RULE_DstIn: {
|
||||||
|
// Ar = Ad*As
|
||||||
|
// Cr = Cd*As
|
||||||
|
if (srcFlags->isOpaque) {
|
||||||
|
J2dTraceLn(J2D_TRACE_ERROR, "Composite rule RULE_DstIn with opaque src isn't implemented (src alpha won't be ignored)");
|
||||||
|
}
|
||||||
|
if (dstFlags->isOpaque) {
|
||||||
|
J2dTraceLn(J2D_TRACE_ERROR, "Composite rule RULE_DstIn with opaque dest isn't implemented (dest alpha won't be ignored)");
|
||||||
|
}
|
||||||
|
cad.sourceAlphaBlendFactor = MTLBlendFactorZero;
|
||||||
|
cad.sourceRGBBlendFactor = MTLBlendFactorZero;
|
||||||
|
cad.destinationAlphaBlendFactor = MTLBlendFactorSourceAlpha;
|
||||||
|
cad.destinationRGBBlendFactor = MTLBlendFactorSourceAlpha;
|
||||||
|
J2dTraceLn(J2D_TRACE_VERBOSE, "set RULE_DstIn");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RULE_SrcOut: {
|
||||||
|
// Ar = As*(1-Ad)
|
||||||
|
// Cr = Cs*(1-Ad)
|
||||||
|
if (!srcFlags->isPremultiplied) {
|
||||||
|
J2dTrace(J2D_TRACE_ERROR, "Composite rule SrcOut with non-premultiplied source isn't implemented (scr alpha will be ignored for rgb-component)");
|
||||||
|
}
|
||||||
|
cad.sourceAlphaBlendFactor = MTLBlendFactorOneMinusDestinationAlpha;
|
||||||
|
cad.sourceRGBBlendFactor = MTLBlendFactorOneMinusDestinationAlpha;
|
||||||
|
cad.destinationAlphaBlendFactor = MTLBlendFactorZero;
|
||||||
|
cad.destinationRGBBlendFactor = MTLBlendFactorZero;
|
||||||
|
J2dTraceLn(J2D_TRACE_VERBOSE, "set RULE_SrcOut");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RULE_DstOut: {
|
||||||
|
// Ar = Ad*(1-As)
|
||||||
|
// Cr = Cd*(1-As)
|
||||||
|
cad.sourceAlphaBlendFactor = MTLBlendFactorZero;
|
||||||
|
cad.sourceRGBBlendFactor = MTLBlendFactorZero;
|
||||||
|
cad.destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
|
||||||
|
cad.destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
|
||||||
|
J2dTraceLn(J2D_TRACE_VERBOSE, "set RULE_DstOut");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RULE_Xor: {
|
||||||
|
// Ar = As*(1-Ad) + Ad*(1-As)
|
||||||
|
// Cr = Cs*(1-Ad) + Cd*(1-As)
|
||||||
|
if (!srcFlags->isPremultiplied) {
|
||||||
|
J2dTrace(J2D_TRACE_ERROR, "Composite rule Xor with non-premultiplied source isn't implemented (scr alpha will be ignored for rgb-component)");
|
||||||
|
}
|
||||||
|
cad.sourceAlphaBlendFactor = MTLBlendFactorOneMinusDestinationAlpha;
|
||||||
|
cad.sourceRGBBlendFactor = MTLBlendFactorOneMinusDestinationAlpha;
|
||||||
|
cad.destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
|
||||||
|
cad.destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
|
||||||
|
J2dTraceLn(J2D_TRACE_VERBOSE, "set RULE_Xor");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RULE_Clear: {
|
||||||
|
// Ar = 0
|
||||||
|
// Cr = 0
|
||||||
|
cad.sourceAlphaBlendFactor = MTLBlendFactorZero;
|
||||||
|
cad.sourceRGBBlendFactor = MTLBlendFactorZero;
|
||||||
|
cad.destinationAlphaBlendFactor = MTLBlendFactorZero;
|
||||||
|
cad.destinationRGBBlendFactor = MTLBlendFactorZero;
|
||||||
|
J2dTraceLn(J2D_TRACE_VERBOSE, "set RULE_Clear");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
J2dTrace1(J2D_TRACE_ERROR, "Unimplemented composite rule %d (will be used Src)", compositeRule);
|
||||||
|
cad.blendingEnabled = NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* 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"
|
||||||
|
#include "MTLVertexCache.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)
|
||||||
|
|
||||||
|
// Operations for CheckPreviousOp
|
||||||
|
enum {
|
||||||
|
MTL_OP_INIT,
|
||||||
|
MTL_OP_AA,
|
||||||
|
MTL_OP_SET_COLOR,
|
||||||
|
MTL_OP_OTHER
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* These macros now simply delegate to the CheckPreviousOp() method.
|
||||||
|
*/
|
||||||
|
#define CHECK_PREVIOUS_OP(op) MTLRenderQueue_CheckPreviousOp(op)
|
||||||
|
#define RESET_PREVIOUS_OP() {mtlPreviousOp = MTL_OP_INIT;}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Increments a pointer (buf) by the given number of bytes.
|
||||||
|
*/
|
||||||
|
#define SKIP_BYTES(buf, numbytes) buf += (numbytes)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extracts a value at the given offset from the provided packed value.
|
||||||
|
*/
|
||||||
|
#define EXTRACT_VAL(packedval, offset, mask) \
|
||||||
|
(((packedval) >> (offset)) & (mask))
|
||||||
|
#define EXTRACT_BYTE(packedval, offset) \
|
||||||
|
(unsigned char)EXTRACT_VAL(packedval, offset, 0xff)
|
||||||
|
#define EXTRACT_BOOLEAN(packedval, offset) \
|
||||||
|
(jboolean)EXTRACT_VAL(packedval, offset, 0x1)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following macros allow the caller to return (or continue) if the
|
||||||
|
* provided value is NULL. (The strange else clause is included below to
|
||||||
|
* allow for a trailing ';' after RETURN/CONTINUE_IF_NULL() invocations.)
|
||||||
|
*/
|
||||||
|
#define ACT_IF_NULL(ACTION, value) \
|
||||||
|
if ((value) == NULL) { \
|
||||||
|
J2dTraceLn1(J2D_TRACE_ERROR, \
|
||||||
|
"%s is null", #value); \
|
||||||
|
ACTION; \
|
||||||
|
} else do { } while (0)
|
||||||
|
#define RETURN_IF_NULL(value) ACT_IF_NULL(return, value)
|
||||||
|
#define CONTINUE_IF_NULL(value) ACT_IF_NULL(continue, value)
|
||||||
|
|
||||||
|
MTLContext *MTLRenderQueue_GetCurrentContext();
|
||||||
|
BMTLSDOps *MTLRenderQueue_GetCurrentDestination();
|
||||||
|
|
||||||
|
extern jint mtlPreviousOp;
|
||||||
|
|
||||||
|
#endif /* MTLRenderQueue_h_Included */
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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, BMTLSDOps * dstOps,
|
||||||
|
jint x1, jint y1, jint x2, jint y2);
|
||||||
|
void MTLRenderer_DrawRect(MTLContext *mtlc, BMTLSDOps * dstOps,
|
||||||
|
jint x, jint y, jint w, jint h);
|
||||||
|
void MTLRenderer_DrawPoly(MTLContext *mtlc, BMTLSDOps * dstOps,
|
||||||
|
jint nPoints, jint isClosed,
|
||||||
|
jint transX, jint transY,
|
||||||
|
jint *xPoints, jint *yPoints);
|
||||||
|
void MTLRenderer_DrawScanlines(MTLContext *mtlc, BMTLSDOps * dstOps,
|
||||||
|
jint count, jint *scanlines);
|
||||||
|
void MTLRenderer_DrawParallelogram(MTLContext *mtlc, BMTLSDOps * dstOps,
|
||||||
|
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, BMTLSDOps * dstOps,
|
||||||
|
jint x, jint y, jint w, jint h);
|
||||||
|
void MTLRenderer_FillSpans(MTLContext *mtlc, BMTLSDOps * dstOps,
|
||||||
|
jint count, jint *spans);
|
||||||
|
void MTLRenderer_FillParallelogram(MTLContext *mtlc, BMTLSDOps * dstOps,
|
||||||
|
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();
|
||||||
|
|
||||||
|
#endif /* MTLRenderer_h_Included */
|
||||||
@@ -0,0 +1,736 @@
|
|||||||
|
/*
|
||||||
|
* 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>
|
||||||
|
|
||||||
|
#include "sun_java2d_metal_MTLRenderer.h"
|
||||||
|
|
||||||
|
#include "MTLRenderer.h"
|
||||||
|
#include "MTLRenderQueue.h"
|
||||||
|
#include "MTLSurfaceData.h"
|
||||||
|
#include "MTLUtils.h"
|
||||||
|
#import "MTLLayer.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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_DrawLine(MTLContext *mtlc, BMTLSDOps * dstOps, jint x1, jint y1, jint x2, jint y2) {
|
||||||
|
if (mtlc == NULL || dstOps == NULL || dstOps->pTexture == NULL) {
|
||||||
|
J2dTraceLn(J2D_TRACE_ERROR, "MTLRenderer_DrawLine: dest is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
J2dTraceLn5(J2D_TRACE_INFO, "MTLRenderer_DrawLine (x1=%1.2f y1=%1.2f x2=%1.2f y2=%1.2f), dst tex=%p", x1, y1, x2, y2, dstOps->pTexture);
|
||||||
|
|
||||||
|
id<MTLRenderCommandEncoder> mtlEncoder = [mtlc.encoderManager getRenderEncoder:dstOps];
|
||||||
|
if (mtlEncoder == nil)
|
||||||
|
return;
|
||||||
|
|
||||||
|
struct Vertex verts[2] = {
|
||||||
|
{{x1, y1}},
|
||||||
|
{{x2, y2}}
|
||||||
|
};
|
||||||
|
|
||||||
|
[mtlEncoder setVertexBytes:verts length:sizeof(verts) atIndex:MeshVertexBuffer];
|
||||||
|
[mtlEncoder drawPrimitives:MTLPrimitiveTypeLine vertexStart:0 vertexCount:2];
|
||||||
|
}
|
||||||
|
|
||||||
|
void MTLRenderer_DrawRect(MTLContext *mtlc, BMTLSDOps * dstOps, jint x, jint y, jint w, jint h) {
|
||||||
|
if (mtlc == NULL || dstOps == NULL || dstOps->pTexture == NULL) {
|
||||||
|
J2dTraceLn(J2D_TRACE_ERROR, "MTLRenderer_DrawRect: dest is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
id<MTLTexture> dest = dstOps->pTexture;
|
||||||
|
J2dTraceLn5(J2D_TRACE_INFO, "MTLRenderer_DrawRect (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 = [mtlc.encoderManager getRenderEncoder:dstOps];
|
||||||
|
if (mtlEncoder == nil)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const int verticesCount = 5;
|
||||||
|
struct Vertex vertices[5] = {
|
||||||
|
{{x, y}},
|
||||||
|
{{x + w, y}},
|
||||||
|
{{x + w, y + h}},
|
||||||
|
{{x, y + h}},
|
||||||
|
{{x, y}},
|
||||||
|
};
|
||||||
|
[mtlEncoder setVertexBytes:vertices length:sizeof(vertices) atIndex:MeshVertexBuffer];
|
||||||
|
[mtlEncoder drawPrimitives:MTLPrimitiveTypeLineStrip vertexStart:0 vertexCount:verticesCount];
|
||||||
|
}
|
||||||
|
|
||||||
|
const int POLYLINE_BUF_SIZE = 64;
|
||||||
|
|
||||||
|
NS_INLINE void fillVertex(struct Vertex * vertex, int x, int y) {
|
||||||
|
vertex->position[0] = x;
|
||||||
|
vertex->position[1] = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MTLRenderer_DrawPoly(MTLContext *mtlc, BMTLSDOps * dstOps,
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mtlc == NULL || dstOps == NULL || dstOps->pTexture == NULL) {
|
||||||
|
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLRenderer_DrawPoly: dest is 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;
|
||||||
|
|
||||||
|
// We intend to submit draw commands in batches of POLYLINE_BUF_SIZE vertices at a time
|
||||||
|
// Subsequent batches need to be connected - so end point in one batch is repeated as first point in subsequent batch
|
||||||
|
// This inflates the total number of points by a factor of number of batches of size POLYLINE_BUF_SIZE
|
||||||
|
nPoints += (nPoints/POLYLINE_BUF_SIZE);
|
||||||
|
|
||||||
|
jint prevX = *(xPoints++);
|
||||||
|
jint prevY = *(yPoints++);
|
||||||
|
const jint firstX = prevX;
|
||||||
|
const jint firstY = prevY;
|
||||||
|
while (nPoints > 0) {
|
||||||
|
const bool isLastChunk = nPoints <= POLYLINE_BUF_SIZE;
|
||||||
|
__block int chunkSize = isLastChunk ? nPoints : POLYLINE_BUF_SIZE;
|
||||||
|
|
||||||
|
fillVertex(pointsChunk.verts, prevX + transX, prevY + transY);
|
||||||
|
|
||||||
|
for (int i = 1; i < chunkSize; i++) {
|
||||||
|
prevX = *(xPoints++);
|
||||||
|
prevY = *(yPoints++);
|
||||||
|
fillVertex(pointsChunk.verts + i, prevX + transX, prevY + transY);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool drawCloseSegment = false;
|
||||||
|
if (isClosed && isLastChunk) {
|
||||||
|
if (chunkSize + 2 <= POLYLINE_BUF_SIZE) {
|
||||||
|
fillVertex(pointsChunk.verts + chunkSize, firstX + transX, firstY + transY);
|
||||||
|
++chunkSize;
|
||||||
|
} else
|
||||||
|
drawCloseSegment = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
nPoints -= chunkSize;
|
||||||
|
id<MTLRenderCommandEncoder> mtlEncoder = [mtlc.encoderManager getRenderEncoder:dstOps];
|
||||||
|
if (mtlEncoder == nil)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[mtlEncoder setVertexBytes:pointsChunk.verts length:sizeof(pointsChunk.verts) atIndex:MeshVertexBuffer];
|
||||||
|
[mtlEncoder drawPrimitives:MTLPrimitiveTypeLineStrip vertexStart:0 vertexCount:chunkSize];
|
||||||
|
|
||||||
|
if (drawCloseSegment) {
|
||||||
|
struct Vertex vertices[2] = {
|
||||||
|
{{prevX + transX, prevY + transY}},
|
||||||
|
{{firstX + transX, firstY + transY}},
|
||||||
|
};
|
||||||
|
|
||||||
|
[mtlEncoder setVertexBytes:vertices length:sizeof(vertices) atIndex:MeshVertexBuffer];
|
||||||
|
[mtlEncoder drawPrimitives:MTLPrimitiveTypeLine vertexStart:0 vertexCount:2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
J2dTraceLn(J2D_TRACE_ERROR, "MTLRenderer_drawPoly -- :TODO");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MTLRenderer_DrawScanlines(MTLContext *mtlc, BMTLSDOps * dstOps,
|
||||||
|
jint scanlineCount, jint *scanlines)
|
||||||
|
{
|
||||||
|
|
||||||
|
J2dTraceLn2(J2D_TRACE_INFO, "MTLRenderer_DrawScanlines (scanlineCount=%d), dst tex=%p", scanlineCount, dstOps->pTexture);
|
||||||
|
if (mtlc == NULL || dstOps == NULL || dstOps->pTexture == NULL) {
|
||||||
|
J2dTraceLn(J2D_TRACE_ERROR, "MTLRenderer_DrawScanlines: dest is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
id<MTLRenderCommandEncoder> mtlEncoder = [mtlc.encoderManager getRenderEncoder:dstOps];
|
||||||
|
|
||||||
|
if (mtlEncoder == nil) return;
|
||||||
|
|
||||||
|
struct Vertex verts[2*scanlineCount];
|
||||||
|
|
||||||
|
for (int j = 0, i = 0; j < scanlineCount; j++) {
|
||||||
|
// Translate each vertex by a fraction so
|
||||||
|
// that we hit pixel centers.
|
||||||
|
float x1 = ((float)*(scanlines++)) + 0.2f;
|
||||||
|
float x2 = ((float)*(scanlines++)) + 1.2f;
|
||||||
|
float y = ((float)*(scanlines++)) + 0.5f;
|
||||||
|
struct Vertex v1 = {{x1, y}};
|
||||||
|
struct Vertex v2 = {{x2, y}};
|
||||||
|
verts[i++] = v1;
|
||||||
|
verts[i++] = v2;
|
||||||
|
}
|
||||||
|
|
||||||
|
[mtlEncoder setVertexBytes:verts length:sizeof(verts) atIndex:MeshVertexBuffer];
|
||||||
|
[mtlEncoder drawPrimitives:MTLPrimitiveTypeLine vertexStart:0 vertexCount:2*scanlineCount];
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MTLRenderer_FillRect(MTLContext *mtlc, BMTLSDOps * dstOps, jint x, jint y, jint w, jint h)
|
||||||
|
{
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLRenderer_FillRect");
|
||||||
|
|
||||||
|
if (mtlc == NULL || dstOps == NULL || dstOps->pTexture == NULL) {
|
||||||
|
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLRenderer_FillRect: current dest is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Vertex verts[QUAD_VERTEX_COUNT] = {
|
||||||
|
{ {x, y}},
|
||||||
|
{ {x, y+h}},
|
||||||
|
{ {x+w, y}},
|
||||||
|
{ {x+w, y+h}
|
||||||
|
}};
|
||||||
|
|
||||||
|
|
||||||
|
id<MTLTexture> dest = dstOps->pTexture;
|
||||||
|
J2dTraceLn5(J2D_TRACE_INFO, "MTLRenderer_FillRect (x=%d y=%d w=%d h=%d), dst tex=%p", x, y, w, h, dest);
|
||||||
|
|
||||||
|
// Encode render command.
|
||||||
|
id<MTLRenderCommandEncoder> mtlEncoder = [mtlc.encoderManager getRenderEncoder:dstOps];
|
||||||
|
if (mtlEncoder == nil)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[mtlEncoder setVertexBytes:verts length:sizeof(verts) atIndex:MeshVertexBuffer];
|
||||||
|
[mtlEncoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount: QUAD_VERTEX_COUNT];
|
||||||
|
}
|
||||||
|
|
||||||
|
void MTLRenderer_FillSpans(MTLContext *mtlc, BMTLSDOps * dstOps, jint spanCount, jint *spans)
|
||||||
|
{
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLRenderer_FillSpans");
|
||||||
|
if (mtlc == NULL || dstOps == NULL || dstOps->pTexture == NULL) {
|
||||||
|
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLRenderer_FillSpans: dest is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// MTLRenderCommandEncoder setVertexBytes usage is recommended if the data is of 4KB.
|
||||||
|
|
||||||
|
// We use a buffer that closely matches the 4KB limit size
|
||||||
|
// This buffer is resued multiple times to encode draw calls of a triangle list
|
||||||
|
// NOTE : Due to nature of *spans data - it is not possible to use triangle strip.
|
||||||
|
// We use triangle list to draw spans
|
||||||
|
|
||||||
|
// Destination texture to which render commands are encoded
|
||||||
|
id<MTLTexture> dest = dstOps->pTexture;
|
||||||
|
bool isDestOpaque = dstOps->isOpaque;
|
||||||
|
if (mtlc.clip.stencilMaskGenerationInProgress == JNI_TRUE) {
|
||||||
|
dest = dstOps->pStencilData;
|
||||||
|
isDestOpaque = NO;
|
||||||
|
}
|
||||||
|
id<MTLRenderCommandEncoder> mtlEncoder = [mtlc.encoderManager getRenderEncoder:dest isDstOpaque:isDestOpaque];
|
||||||
|
if (mtlEncoder == nil) {
|
||||||
|
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLRenderer_FillSpans: mtlEncoder is nil");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is the max no of vertices (of struct Vertex - 8 bytes) we can accomodate in 4KB
|
||||||
|
const int TOTAL_VERTICES_IN_BLOCK = 510;
|
||||||
|
struct Vertex vertexList[TOTAL_VERTICES_IN_BLOCK]; // a total of 170 triangles ==> 85 spans
|
||||||
|
|
||||||
|
int counter = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < spanCount; i++) {
|
||||||
|
jfloat x1 = *(spans++);
|
||||||
|
jfloat y1 = *(spans++);
|
||||||
|
jfloat x2 = *(spans++);
|
||||||
|
jfloat y2 = *(spans++);
|
||||||
|
|
||||||
|
struct Vertex verts[6] = {
|
||||||
|
{{x1, y1}},
|
||||||
|
{{x1, y2}},
|
||||||
|
{{x2, y1}},
|
||||||
|
|
||||||
|
{{x1, y2}},
|
||||||
|
{{x2, y1}},
|
||||||
|
{{x2, y2}
|
||||||
|
}};
|
||||||
|
|
||||||
|
memcpy(&vertexList[counter], &verts, sizeof(verts));
|
||||||
|
counter += 6;
|
||||||
|
|
||||||
|
// If vertexList buffer full
|
||||||
|
if (counter % TOTAL_VERTICES_IN_BLOCK == 0) {
|
||||||
|
[mtlEncoder setVertexBytes:vertexList length:sizeof(vertexList) atIndex:MeshVertexBuffer];
|
||||||
|
[mtlEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:TOTAL_VERTICES_IN_BLOCK];
|
||||||
|
counter = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw triangles using remaining vertices if any
|
||||||
|
if (counter != 0) {
|
||||||
|
[mtlEncoder setVertexBytes:vertexList length:sizeof(vertexList) atIndex:MeshVertexBuffer];
|
||||||
|
[mtlEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:counter];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MTLRenderer_FillParallelogram(MTLContext *mtlc, BMTLSDOps * dstOps,
|
||||||
|
jfloat fx11, jfloat fy11,
|
||||||
|
jfloat dx21, jfloat dy21,
|
||||||
|
jfloat dx12, jfloat dy12)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (mtlc == NULL || dstOps == NULL || dstOps->pTexture == NULL) {
|
||||||
|
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLRenderer_FillParallelogram: current dest is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
id<MTLTexture> dest = dstOps->pTexture;
|
||||||
|
J2dTraceLn7(J2D_TRACE_INFO,
|
||||||
|
"MTLRenderer_FillParallelogram "
|
||||||
|
"(x=%6.2f y=%6.2f "
|
||||||
|
"dx1=%6.2f dy1=%6.2f "
|
||||||
|
"dx2=%6.2f dy2=%6.2f dst tex=%p)",
|
||||||
|
fx11, fy11,
|
||||||
|
dx21, dy21,
|
||||||
|
dx12, dy12, dest);
|
||||||
|
|
||||||
|
struct Vertex verts[QUAD_VERTEX_COUNT] = {
|
||||||
|
{ {fx11, fy11}},
|
||||||
|
{ {fx11+dx21, fy11+dy21}},
|
||||||
|
{ {fx11+dx12, fy11+dy12}},
|
||||||
|
{ {fx11 + dx21 + dx12, fy11+ dy21 + dy12}
|
||||||
|
}};
|
||||||
|
|
||||||
|
// Encode render command.
|
||||||
|
id<MTLRenderCommandEncoder> mtlEncoder = [mtlc.encoderManager getRenderEncoder:dstOps];
|
||||||
|
if (mtlEncoder == nil)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[mtlEncoder setVertexBytes:verts length:sizeof(verts) atIndex:MeshVertexBuffer];
|
||||||
|
[mtlEncoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount: QUAD_VERTEX_COUNT];
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MTLRenderer_DrawParallelogram(MTLContext *mtlc, BMTLSDOps * dstOps,
|
||||||
|
jfloat fx11, jfloat fy11,
|
||||||
|
jfloat dx21, jfloat dy21,
|
||||||
|
jfloat dx12, jfloat dy12,
|
||||||
|
jfloat lwr21, jfloat lwr12)
|
||||||
|
{
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
|
||||||
|
// Only need to generate 4 quads if the interior still
|
||||||
|
// has a hole in it (i.e. if the line width ratio was
|
||||||
|
// less than 1.0)
|
||||||
|
if (lwr21 < 1.0f && lwr12 < 1.0f) {
|
||||||
|
|
||||||
|
// Note: "TOP", "BOTTOM", "LEFT" and "RIGHT" here are
|
||||||
|
// relative to whether the dxNN variables are positive
|
||||||
|
// and negative. The math works fine regardless of
|
||||||
|
// their signs, but for conceptual simplicity the
|
||||||
|
// comments will refer to the sides as if the dxNN
|
||||||
|
// were all positive. "TOP" and "BOTTOM" segments
|
||||||
|
// are defined by the dxy21 deltas. "LEFT" and "RIGHT"
|
||||||
|
// segments are defined by the dxy12 deltas.
|
||||||
|
|
||||||
|
// Each segment includes its starting corner and comes
|
||||||
|
// to just short of the following corner. Thus, each
|
||||||
|
// corner is included just once and the only lengths
|
||||||
|
// needed are the original parallelogram delta lengths
|
||||||
|
// and the "line width deltas". The sides will cover
|
||||||
|
// the following relative territories:
|
||||||
|
//
|
||||||
|
// T T T T T R
|
||||||
|
// L R
|
||||||
|
// L R
|
||||||
|
// L R
|
||||||
|
// L R
|
||||||
|
// L B B B B B
|
||||||
|
|
||||||
|
// Every segment is drawn as a filled Parallelogram quad
|
||||||
|
// Each quad is encoded using two triangles
|
||||||
|
// For 4 segments - there are 8 triangles in total
|
||||||
|
// Each triangle has 3 vertices
|
||||||
|
const int TOTAL_VERTICES = 8 * 3;
|
||||||
|
struct Vertex vertexList[TOTAL_VERTICES];
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
// TOP segment, to left side of RIGHT edge
|
||||||
|
// "width" of original pgram, "height" of hor. line size
|
||||||
|
fx11 = ox11;
|
||||||
|
fy11 = oy11;
|
||||||
|
|
||||||
|
fillVertex(vertexList + (i++), fx11, fy11);
|
||||||
|
fillVertex(vertexList + (i++), fx11 + dx21, fy11 + dy21);
|
||||||
|
fillVertex(vertexList + (i++), fx11 + dx21 + ldx12, fy11 + dy21 + ldy12);
|
||||||
|
|
||||||
|
fillVertex(vertexList + (i++), fx11 + dx21 + ldx12, fy11 + dy21 + ldy12);
|
||||||
|
fillVertex(vertexList + (i++), fx11 + ldx12, fy11 + ldy12);
|
||||||
|
fillVertex(vertexList + (i++), fx11, fy11);
|
||||||
|
|
||||||
|
// RIGHT segment, to top of BOTTOM edge
|
||||||
|
// "width" of vert. line size , "height" of original pgram
|
||||||
|
fx11 = ox11 + dx21;
|
||||||
|
fy11 = oy11 + dy21;
|
||||||
|
fillVertex(vertexList + (i++), fx11, fy11);
|
||||||
|
fillVertex(vertexList + (i++), fx11 + ldx21, fy11 + ldy21);
|
||||||
|
fillVertex(vertexList + (i++), fx11 + ldx21 + dx12, fy11 + ldy21 + dy12);
|
||||||
|
|
||||||
|
fillVertex(vertexList + (i++), fx11 + ldx21 + dx12, fy11 + ldy21 + dy12);
|
||||||
|
fillVertex(vertexList + (i++), fx11 + dx12, fy11 + dy12);
|
||||||
|
fillVertex(vertexList + (i++), fx11, fy11);
|
||||||
|
|
||||||
|
// BOTTOM segment, from right side of LEFT edge
|
||||||
|
// "width" of original pgram, "height" of hor. line size
|
||||||
|
fx11 = ox11 + dx12 + ldx21;
|
||||||
|
fy11 = oy11 + dy12 + ldy21;
|
||||||
|
fillVertex(vertexList + (i++), fx11, fy11);
|
||||||
|
fillVertex(vertexList + (i++), fx11 + dx21, fy11 + dy21);
|
||||||
|
fillVertex(vertexList + (i++), fx11 + dx21 + ldx12, fy11 + dy21 + ldy12);
|
||||||
|
|
||||||
|
fillVertex(vertexList + (i++), fx11 + dx21 + ldx12, fy11 + dy21 + ldy12);
|
||||||
|
fillVertex(vertexList + (i++), fx11 + ldx12, fy11 + ldy12);
|
||||||
|
fillVertex(vertexList + (i++), fx11, fy11);
|
||||||
|
|
||||||
|
// LEFT segment, from bottom of TOP edge
|
||||||
|
// "width" of vert. line size , "height" of inner pgram
|
||||||
|
fx11 = ox11 + ldx12;
|
||||||
|
fy11 = oy11 + ldy12;
|
||||||
|
fillVertex(vertexList + (i++), fx11, fy11);
|
||||||
|
fillVertex(vertexList + (i++), fx11 + ldx21, fy11 + ldy21);
|
||||||
|
fillVertex(vertexList + (i++), fx11 + ldx21 + dx12, fy11 + ldy21 + dy12);
|
||||||
|
|
||||||
|
fillVertex(vertexList + (i++), fx11 + ldx21 + dx12, fy11 + ldy21 + dy12);
|
||||||
|
fillVertex(vertexList + (i++), fx11 + dx12, fy11 + dy12);
|
||||||
|
fillVertex(vertexList + (i++), fx11, fy11);
|
||||||
|
|
||||||
|
// Encode render command.
|
||||||
|
id<MTLRenderCommandEncoder> mtlEncoder = [mtlc.encoderManager getRenderEncoder:dstOps];
|
||||||
|
if (mtlEncoder == nil)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[mtlEncoder setVertexBytes:vertexList length:sizeof(vertexList) atIndex:MeshVertexBuffer];
|
||||||
|
[mtlEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:TOTAL_VERTICES];
|
||||||
|
} else {
|
||||||
|
// The line width ratios were large enough to consume
|
||||||
|
// the entire hole in the middle of the parallelogram
|
||||||
|
// so we can just issue one large quad for the outer
|
||||||
|
// parallelogram.
|
||||||
|
dx21 += ldx21;
|
||||||
|
dy21 += ldy21;
|
||||||
|
dx12 += ldx12;
|
||||||
|
dy12 += ldy12;
|
||||||
|
MTLRenderer_FillParallelogram(mtlc, dstOps, ox11, oy11, dx21, dy21, dx12, dy12);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
if (mtlc == NULL || dstOps == NULL || dstOps->pTexture == NULL) {
|
||||||
|
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLRenderer_FillParallelogram: current dest is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
J2dTraceLn7(J2D_TRACE_INFO,
|
||||||
|
"MTLRenderer_FillAAParallelogram "
|
||||||
|
"(x=%6.2f y=%6.2f "
|
||||||
|
"dx1=%6.2f dy1=%6.2f "
|
||||||
|
"dx2=%6.2f dy2=%6.2f dst tex=%p)",
|
||||||
|
fx11, fy11,
|
||||||
|
dx21, dy21,
|
||||||
|
dx12, dy12, dstOps->pTexture);
|
||||||
|
|
||||||
|
struct Vertex verts[QUAD_VERTEX_COUNT] = {
|
||||||
|
{ {fx11, fy11}},
|
||||||
|
{ {fx11+dx21, fy11+dy21}},
|
||||||
|
{ {fx11+dx12, fy11+dy12}},
|
||||||
|
{ {fx11 + dx21 + dx12, fy11+ dy21 + dy12}
|
||||||
|
}};
|
||||||
|
|
||||||
|
id<MTLTexture> dstTxt = dstOps->pTexture;
|
||||||
|
|
||||||
|
// Encode render command.
|
||||||
|
id<MTLRenderCommandEncoder> mtlEncoder =
|
||||||
|
[mtlc.encoderManager getAARenderEncoder:dstOps];
|
||||||
|
|
||||||
|
if (mtlEncoder == nil) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[mtlEncoder setVertexBytes:verts length:sizeof(verts) atIndex:MeshVertexBuffer];
|
||||||
|
[mtlEncoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount: QUAD_VERTEX_COUNT];
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
J2dTraceLn(J2D_TRACE_ERROR, "MTLRenderer_FillAAParallelogramInnerOuter -- :TODO");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MTLRenderer_DrawAAParallelogram(MTLContext *mtlc, BMTLSDOps *dstOps,
|
||||||
|
jfloat fx11, jfloat fy11,
|
||||||
|
jfloat dx21, jfloat dy21,
|
||||||
|
jfloat dx12, jfloat dy12,
|
||||||
|
jfloat lwr21, jfloat lwr12)
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
// 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_ERROR,
|
||||||
|
"MTLRenderer_DrawAAParallelogram -- :TODO"
|
||||||
|
"(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
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLRenderer_EnableAAParallelogramProgram -- :TODO");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MTLRenderer_DisableAAParallelogramProgram()
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLRenderer_DisableAAParallelogramProgram -- :TODO");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* !HEADLESS */
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
// debug-method
|
||||||
|
NSString * getSurfaceDescription(const BMTLSDOps * bmtlsdOps);
|
||||||
|
|
||||||
|
#endif /* MTLSurfaceData_h_Included */
|
||||||
@@ -0,0 +1,402 @@
|
|||||||
|
/*
|
||||||
|
* 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 *bmtlsdo);
|
||||||
|
extern jboolean MTLSD_InitMTLWindow(JNIEnv *env, BMTLSDOps *bmtlsdo);
|
||||||
|
extern void MTLSD_DestroyMTLSurface(JNIEnv *env, BMTLSDOps *bmtlsdo);
|
||||||
|
|
||||||
|
void MTLSD_SetNativeDimensions(JNIEnv *env, BMTLSDOps *bmtlsdo, jint w, jint h);
|
||||||
|
|
||||||
|
static jboolean MTLSurfaceData_initTexture(BMTLSDOps *bmtlsdo, jboolean isOpaque, jboolean rtt, jint width, jint height) {
|
||||||
|
@autoreleasepool {
|
||||||
|
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];
|
||||||
|
textureDescriptor.usage = MTLTextureUsageUnknown;
|
||||||
|
bmtlsdo->pTexture = [ctx.device newTextureWithDescriptor: textureDescriptor];
|
||||||
|
|
||||||
|
MTLTextureDescriptor *stencilDataDescriptor =
|
||||||
|
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatR8Uint width:width height:height mipmapped:NO];
|
||||||
|
stencilDataDescriptor.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead;
|
||||||
|
stencilDataDescriptor.storageMode = MTLStorageModePrivate;
|
||||||
|
bmtlsdo->pStencilData = [ctx.device newTextureWithDescriptor:stencilDataDescriptor];
|
||||||
|
|
||||||
|
MTLTextureDescriptor *stencilTextureDescriptor =
|
||||||
|
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatStencil8 width:width height:height mipmapped:NO];
|
||||||
|
stencilTextureDescriptor.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite;
|
||||||
|
stencilTextureDescriptor.storageMode = MTLStorageModePrivate;
|
||||||
|
bmtlsdo->pStencilTexture = [ctx.device newTextureWithDescriptor:stencilTextureDescriptor];
|
||||||
|
|
||||||
|
MTLTextureDescriptor *lcdTextureDescriptor =
|
||||||
|
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm width:width height:height mipmapped:NO];
|
||||||
|
|
||||||
|
bmtlsdo->textureLCD = [ctx.device newTextureWithDescriptor:lcdTextureDescriptor];
|
||||||
|
|
||||||
|
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 = rtt ? MTLSD_RT_TEXTURE : MTLSD_TEXTURE;
|
||||||
|
|
||||||
|
J2dTraceLn6(J2D_TRACE_VERBOSE, "MTLSurfaceData_initTexture: w=%d h=%d bp=%p [tex=%p] opaque=%d rtt=%d", width, height, bmtlsdo, bmtlsdo->pTexture, isOpaque, rtt);
|
||||||
|
return JNI_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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,
|
||||||
|
jint width, jint height
|
||||||
|
) {
|
||||||
|
if (!MTLSurfaceData_initTexture((BMTLSDOps *)pData, isOpaque, JNI_FALSE, width, height))
|
||||||
|
return JNI_FALSE;
|
||||||
|
MTLSD_SetNativeDimensions(env, (BMTLSDOps *)pData, width, height);
|
||||||
|
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,
|
||||||
|
jint width, jint height)
|
||||||
|
{
|
||||||
|
if (!MTLSurfaceData_initTexture((BMTLSDOps *)pData, isOpaque, JNI_TRUE, width, height))
|
||||||
|
return JNI_FALSE;
|
||||||
|
MTLSD_SetNativeDimensions(env, (BMTLSDOps *)pData, width, height);
|
||||||
|
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
|
||||||
|
MTLSDOps *mtlsdo = (MTLSDOps *)jlong_to_ptr(pData);
|
||||||
|
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLSurfaceData_initFlipBackbuffer -- :TODO");
|
||||||
|
return JNI_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jlong JNICALL
|
||||||
|
Java_sun_java2d_metal_MTLSurfaceData_getMTLTexturePointer(JNIEnv *env, jobject mtlsd, jlong pData) {
|
||||||
|
if (pData == 0)
|
||||||
|
return 0;
|
||||||
|
return ptr_to_jlong(((BMTLSDOps *)pData)->pTexture);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 *bmtlsdo)
|
||||||
|
{
|
||||||
|
J2dTraceLn3(J2D_TRACE_VERBOSE, "MTLSD_Delete: type=%d %p [tex=%p]", bmtlsdo->drawableType, bmtlsdo, bmtlsdo->pTexture);
|
||||||
|
if (bmtlsdo->drawableType == MTLSD_WINDOW) {
|
||||||
|
MTLSD_DestroyMTLSurface(env, bmtlsdo);
|
||||||
|
} else if (
|
||||||
|
bmtlsdo->drawableType == MTLSD_RT_TEXTURE
|
||||||
|
|| bmtlsdo->drawableType == MTLSD_TEXTURE
|
||||||
|
|| bmtlsdo->drawableType == MTLSD_FLIP_BACKBUFFER
|
||||||
|
) {
|
||||||
|
[(NSObject *)bmtlsdo->pTexture release];
|
||||||
|
bmtlsdo->pTexture = NULL;
|
||||||
|
bmtlsdo->drawableType = MTLSD_UNDEFINED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
BMTLSDOps *bmtlsdo = (BMTLSDOps *)ops;
|
||||||
|
jobject graphicsConfig = bmtlsdo->graphicsConfig;
|
||||||
|
|
||||||
|
JNU_CallStaticMethodByName(env, NULL, "sun/java2d/metal/MTLSurfaceData",
|
||||||
|
"dispose",
|
||||||
|
"(JLsun/java2d/metal/MTLGraphicsConfig;)V",
|
||||||
|
ptr_to_jlong(ops), graphicsConfig);
|
||||||
|
(*env)->DeleteGlobalRef(env, graphicsConfig);
|
||||||
|
bmtlsdo->graphicsConfig = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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, BMTLSDOps * bmtlsdo)
|
||||||
|
{
|
||||||
|
J2dTraceLn(J2D_TRACE_ERROR, "MTLSD_DestroyMTLSurface not implemented!");
|
||||||
|
JNF_COCOA_ENTER(env);
|
||||||
|
if (bmtlsdo->drawableType == MTLSD_WINDOW) {
|
||||||
|
// TODO: detach the NSView from the metal context
|
||||||
|
}
|
||||||
|
|
||||||
|
bmtlsdo->drawableType = MTLSD_UNDEFINED;
|
||||||
|
JNF_COCOA_EXIT(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function initializes a native window surface and caches the window
|
||||||
|
* bounds in the given BMTLSDOps. Returns JNI_TRUE if the operation was
|
||||||
|
* successful; JNI_FALSE otherwise.
|
||||||
|
*/
|
||||||
|
jboolean
|
||||||
|
MTLSD_InitMTLWindow(JNIEnv *env, BMTLSDOps *bmtlsdo)
|
||||||
|
{
|
||||||
|
if (bmtlsdo == NULL) {
|
||||||
|
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSD_InitMTLWindow: ops are null");
|
||||||
|
return JNI_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
MTLSDOps *mtlsdo = (MTLSDOps *)bmtlsdo->privOps;
|
||||||
|
if (mtlsdo == NULL) {
|
||||||
|
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSD_InitMTLWindow: priv ops are null");
|
||||||
|
return JNI_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
AWTView *v = mtlsdo->peerData;
|
||||||
|
if (v == NULL) {
|
||||||
|
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLSD_InitMTLWindow: view is invalid");
|
||||||
|
return JNI_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNF_COCOA_ENTER(env);
|
||||||
|
NSRect surfaceBounds = [v bounds];
|
||||||
|
bmtlsdo->drawableType = MTLSD_WINDOW;
|
||||||
|
bmtlsdo->isOpaque = JNI_TRUE;
|
||||||
|
bmtlsdo->width = surfaceBounds.size.width;
|
||||||
|
bmtlsdo->height = surfaceBounds.size.height;
|
||||||
|
JNF_COCOA_EXIT(env);
|
||||||
|
|
||||||
|
J2dTraceLn2(J2D_TRACE_VERBOSE, " created window: w=%d h=%d", bmtlsdo->width, bmtlsdo->height);
|
||||||
|
return JNI_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MTLSD_SwapBuffers(JNIEnv *env, jlong pPeerData)
|
||||||
|
{
|
||||||
|
J2dTraceLn(J2D_TRACE_ERROR, "OGLSD_SwapBuffers -- :TODO");
|
||||||
|
}
|
||||||
|
|
||||||
|
#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 mtlsd, jobject gc,
|
||||||
|
jlong pConfigInfo, jlong pPeerData, jlong layerPtr,
|
||||||
|
jint xoff, jint yoff, jboolean isOpaque)
|
||||||
|
{
|
||||||
|
BMTLSDOps *bmtlsdo = (BMTLSDOps *)SurfaceData_InitOps(env, mtlsd, 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);
|
||||||
|
|
||||||
|
gc = (*env)->NewGlobalRef(env, gc);
|
||||||
|
if (gc == NULL) {
|
||||||
|
JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mtlsdo == NULL) {
|
||||||
|
(*env)->DeleteGlobalRef(env, gc);
|
||||||
|
JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// later the graphicsConfig will be used for deallocation of mtlsdo
|
||||||
|
bmtlsdo->privOps = mtlsdo;
|
||||||
|
bmtlsdo->graphicsConfig = gc;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSString * getSurfaceDescription(const BMTLSDOps * bmtlsdOps) {
|
||||||
|
if (bmtlsdOps == NULL)
|
||||||
|
return @"NULL";
|
||||||
|
return [NSString stringWithFormat:@"%p [tex=%p, %dx%d, O=%d]", bmtlsdOps, bmtlsdOps->pTexture, bmtlsdOps->width, bmtlsdOps->height, bmtlsdOps->isOpaque];
|
||||||
|
}
|
||||||
@@ -0,0 +1,231 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
jobject graphicsConfig;
|
||||||
|
jint drawableType;
|
||||||
|
jint activeBuffer;
|
||||||
|
jboolean isOpaque;
|
||||||
|
jboolean needsInit;
|
||||||
|
jint xOffset;
|
||||||
|
jint yOffset;
|
||||||
|
jint width;
|
||||||
|
jint height;
|
||||||
|
void* pTexture;
|
||||||
|
void* pStencilData; // stencil data to be rendered to this buffer
|
||||||
|
void* pStencilTexture; // byte buffer stencil mask used in main rendering
|
||||||
|
void* textureLCD;
|
||||||
|
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
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The SurfaceRasterFlags structure contains information about raster (of some MTLTexture):
|
||||||
|
*
|
||||||
|
* jboolean isOpaque;
|
||||||
|
* If true, indicates that this pixel format hasn't alpha component (and values of this component can contain garbage).
|
||||||
|
*
|
||||||
|
* jboolean isPremultiplied;
|
||||||
|
* If true, indicates that this pixel format contains color components that have been pre-multiplied by their
|
||||||
|
* corresponding alpha component.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
jboolean isOpaque;
|
||||||
|
jboolean isPremultiplied;
|
||||||
|
} SurfaceRasterFlags;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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,58 @@
|
|||||||
|
/*
|
||||||
|
* 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, BMTLSDOps *dstOps);
|
||||||
|
void MTLTR_DisableGlyphVertexCache(MTLContext *mtlc);
|
||||||
|
id<MTLTexture> MTLTR_GetGlyphCacheTexture();
|
||||||
|
|
||||||
|
void MTLTR_DrawGlyphList(JNIEnv *env, MTLContext *mtlc, BMTLSDOps *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,994 @@
|
|||||||
|
/*
|
||||||
|
* 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 "MTLGlyphCache.h"
|
||||||
|
#include "MTLBlitLoops.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The following constants define the inner and outer bounds of the
|
||||||
|
* accelerated glyph cache.
|
||||||
|
*/
|
||||||
|
#define MTLTR_CACHE_WIDTH 512
|
||||||
|
#define MTLTR_CACHE_HEIGHT 512
|
||||||
|
#define MTLTR_CACHE_CELL_WIDTH 32
|
||||||
|
#define MTLTR_CACHE_CELL_HEIGHT 32
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 MTLGlyphCacheInfo *glyphCacheLCD = NULL;
|
||||||
|
static MTLGlyphCacheInfo *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 32
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 512
|
||||||
|
#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;
|
||||||
|
|
||||||
|
static struct TxtVertex txtVertices[6];
|
||||||
|
static jint vertexCacheIndex = 0;
|
||||||
|
|
||||||
|
#define LCD_ADD_VERTEX(TX, TY, DX, DY, DZ) \
|
||||||
|
do { \
|
||||||
|
struct TxtVertex *v = &txtVertices[vertexCacheIndex++]; \
|
||||||
|
v->txtpos[0] = TX; \
|
||||||
|
v->txtpos[1] = TY; \
|
||||||
|
v->position[0]= DX; \
|
||||||
|
v->position[1] = DY; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define LCD_ADD_TRIANGLES(TX1, TY1, TX2, TY2, DX1, DY1, DX2, DY2) \
|
||||||
|
do { \
|
||||||
|
LCD_ADD_VERTEX(TX1, TY1, DX1, DY1, 0); \
|
||||||
|
LCD_ADD_VERTEX(TX2, TY1, DX2, DY1, 0); \
|
||||||
|
LCD_ADD_VERTEX(TX2, TY2, DX2, DY2, 0); \
|
||||||
|
LCD_ADD_VERTEX(TX2, TY2, DX2, DY2, 0); \
|
||||||
|
LCD_ADD_VERTEX(TX1, TY2, DX1, DY2, 0); \
|
||||||
|
LCD_ADD_VERTEX(TX1, TY1, DX1, DY1, 0); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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(MTLContext *mtlc, jboolean lcdCache)
|
||||||
|
{
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLTR_InitGlyphCache");
|
||||||
|
MTLPixelFormat pixelFormat =
|
||||||
|
lcdCache ? MTLPixelFormatRGBA8Unorm : MTLPixelFormatA8Unorm;
|
||||||
|
|
||||||
|
MTLGlyphCacheInfo *gcinfo;
|
||||||
|
// init glyph cache data structure
|
||||||
|
gcinfo = MTLGlyphCache_Init(MTLTR_CACHE_WIDTH,
|
||||||
|
MTLTR_CACHE_HEIGHT,
|
||||||
|
MTLTR_CACHE_CELL_WIDTH,
|
||||||
|
MTLTR_CACHE_CELL_HEIGHT,
|
||||||
|
MTLVertexCache_FlushGlyphVertexCache);
|
||||||
|
|
||||||
|
if (gcinfo == NULL) {
|
||||||
|
J2dRlsTraceLn(J2D_TRACE_ERROR,
|
||||||
|
"MTLTR_InitGlyphCache: could not init MTL glyph cache");
|
||||||
|
return JNI_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
MTLTextureDescriptor *textureDescriptor =
|
||||||
|
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:pixelFormat
|
||||||
|
width:MTLTR_CACHE_WIDTH
|
||||||
|
height:MTLTR_CACHE_HEIGHT
|
||||||
|
mipmapped:NO];
|
||||||
|
|
||||||
|
gcinfo->texture = [mtlc.device newTextureWithDescriptor:textureDescriptor];
|
||||||
|
[textureDescriptor release];
|
||||||
|
|
||||||
|
if (lcdCache) {
|
||||||
|
glyphCacheLCD = gcinfo;
|
||||||
|
} else {
|
||||||
|
glyphCacheAA = gcinfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
return JNI_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
id<MTLTexture>
|
||||||
|
MTLTR_GetGlyphCacheTexture()
|
||||||
|
{
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLTR_GetGlyphCacheTexture");
|
||||||
|
if (glyphCacheAA != NULL) {
|
||||||
|
return glyphCacheAA->texture;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the given glyph to the glyph cache (texture and data structure)
|
||||||
|
* associated with the given MTLContext.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
MTLTR_AddToGlyphCache(GlyphInfo *glyph, MTLContext *mtlc,
|
||||||
|
MTLPixelFormat pixelFormat)
|
||||||
|
{
|
||||||
|
MTLCacheCellInfo *ccinfo;
|
||||||
|
MTLGlyphCacheInfo *gcinfo;
|
||||||
|
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLTR_AddToGlyphCache");
|
||||||
|
if (pixelFormat == MTLPixelFormatA8Unorm) {
|
||||||
|
gcinfo = glyphCacheAA;
|
||||||
|
} else {
|
||||||
|
gcinfo = glyphCacheLCD;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((gcinfo == NULL) || (glyph->image == NULL)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isCacheFull = MTLGlyphCache_IsCacheFull(gcinfo, glyph);
|
||||||
|
if (isCacheFull) {
|
||||||
|
MTLGlyphCache_Free(gcinfo);
|
||||||
|
if (pixelFormat == MTLPixelFormatA8Unorm) {
|
||||||
|
MTLTR_InitGlyphCache(mtlc, JNI_FALSE);
|
||||||
|
} else {
|
||||||
|
MTLTR_InitGlyphCache(mtlc, JNI_TRUE);
|
||||||
|
}
|
||||||
|
gcinfo = glyphCacheAA;
|
||||||
|
}
|
||||||
|
MTLGlyphCache_AddGlyph(gcinfo, glyph);
|
||||||
|
ccinfo = (MTLCacheCellInfo *) glyph->cellInfo;
|
||||||
|
|
||||||
|
if (ccinfo != NULL) {
|
||||||
|
// store glyph image in texture cell
|
||||||
|
MTLRegion region = {
|
||||||
|
{ccinfo->x, ccinfo->y, 0},
|
||||||
|
{glyph->width, glyph->height, 1}
|
||||||
|
};
|
||||||
|
NSUInteger bytesPerRow = 1 * glyph->width;
|
||||||
|
[gcinfo->texture replaceRegion:region
|
||||||
|
mipmapLevel:0
|
||||||
|
withBytes:glyph->image
|
||||||
|
bytesPerRow:bytesPerRow];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static MTLRenderPipelineDescriptor * templateRenderPipelineDesc = nil;
|
||||||
|
static MTLRenderPipelineDescriptor * templateLCDPipelineDesc = nil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables the LCD text shader and updates any related state, such as the
|
||||||
|
* gamma lookup table textures.
|
||||||
|
*/
|
||||||
|
static jboolean
|
||||||
|
MTLTR_EnableLCDGlyphModeState(id<MTLRenderCommandEncoder> encoder,
|
||||||
|
MTLContext *mtlc,
|
||||||
|
MTLSDOps *dstOps,
|
||||||
|
jint contrast)
|
||||||
|
{
|
||||||
|
// create the LCD text shader, if necessary
|
||||||
|
if (templateLCDPipelineDesc == nil) {
|
||||||
|
|
||||||
|
MTLVertexDescriptor *vertDesc = [[MTLVertexDescriptor new] autorelease];
|
||||||
|
vertDesc.attributes[VertexAttributePosition].format = MTLVertexFormatFloat2;
|
||||||
|
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;
|
||||||
|
|
||||||
|
templateLCDPipelineDesc = [[MTLRenderPipelineDescriptor new] autorelease];
|
||||||
|
templateLCDPipelineDesc.sampleCount = 1;
|
||||||
|
templateLCDPipelineDesc.vertexDescriptor = vertDesc;
|
||||||
|
templateLCDPipelineDesc.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;
|
||||||
|
templateLCDPipelineDesc.vertexDescriptor.attributes[VertexAttributeTexPos].format = MTLVertexFormatFloat2;
|
||||||
|
templateLCDPipelineDesc.vertexDescriptor.attributes[VertexAttributeTexPos].offset = 2*sizeof(float);
|
||||||
|
templateLCDPipelineDesc.vertexDescriptor.attributes[VertexAttributeTexPos].bufferIndex = MeshVertexBuffer;
|
||||||
|
templateLCDPipelineDesc.vertexDescriptor.layouts[MeshVertexBuffer].stride = sizeof(struct TxtVertex);
|
||||||
|
templateLCDPipelineDesc.vertexDescriptor.layouts[MeshVertexBuffer].stepRate = 1;
|
||||||
|
templateLCDPipelineDesc.vertexDescriptor.layouts[MeshVertexBuffer].stepFunction = MTLVertexStepFunctionPerVertex;
|
||||||
|
templateLCDPipelineDesc.label = @"template_lcd";
|
||||||
|
}
|
||||||
|
|
||||||
|
id<MTLRenderPipelineState> pipelineState =
|
||||||
|
[mtlc.pipelineStateStorage
|
||||||
|
getPipelineState:templateLCDPipelineDesc
|
||||||
|
vertexShaderId:@"vert_txt"
|
||||||
|
fragmentShaderId:@"lcd_color"
|
||||||
|
];
|
||||||
|
|
||||||
|
[encoder setRenderPipelineState:pipelineState];
|
||||||
|
|
||||||
|
double g = 0;
|
||||||
|
double ig = 0;
|
||||||
|
|
||||||
|
// update the current contrast setting, if necessary
|
||||||
|
if (lastLCDContrast != contrast) {
|
||||||
|
g = ((double)contrast) / 100.0;
|
||||||
|
ig = 1.0 / g;
|
||||||
|
lastLCDContrast = contrast;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update the current color settings
|
||||||
|
double gamma = ((double)contrast) / 100.0;
|
||||||
|
jfloat radj, gadj, badj;
|
||||||
|
jfloat clr[4];
|
||||||
|
jint col = [mtlc.paint getColor];
|
||||||
|
|
||||||
|
J2dTraceLn1(J2D_TRACE_INFO, "primary color %x", col);
|
||||||
|
|
||||||
|
clr[0] = ((col >> 16) & 0xFF)/255.0f;
|
||||||
|
clr[1] = ((col >> 8) & 0xFF)/255.0f;
|
||||||
|
clr[2] = ((col) & 0xFF)/255.0f;
|
||||||
|
|
||||||
|
// gamma adjust the primary color
|
||||||
|
radj = (float)pow(clr[0], gamma);
|
||||||
|
gadj = (float)pow(clr[1], gamma);
|
||||||
|
badj = (float)pow(clr[2], gamma);
|
||||||
|
|
||||||
|
struct LCDFrameUniforms uf = {
|
||||||
|
{radj, gadj, badj},
|
||||||
|
{g, g, g},
|
||||||
|
{ig, ig, ig}};
|
||||||
|
[encoder setFragmentBytes:&uf length:sizeof(uf) atIndex:FrameUniformBuffer];
|
||||||
|
|
||||||
|
return JNI_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MTLTR_EnableGlyphVertexCache(MTLContext *mtlc, BMTLSDOps *dstOps)
|
||||||
|
{
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLTR_EnableGlyphVertexCache");
|
||||||
|
|
||||||
|
if (!MTLVertexCache_InitVertexCache()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (glyphCacheAA == NULL) {
|
||||||
|
if (!MTLTR_InitGlyphCache(mtlc, JNI_FALSE)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MTLVertexCache_CreateSamplingEncoder(mtlc, dstOps);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MTLTR_DisableGlyphVertexCache(MTLContext *mtlc)
|
||||||
|
{
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLTR_DisableGlyphVertexCache");
|
||||||
|
MTLVertexCache_FlushGlyphVertexCache();
|
||||||
|
MTLVertexCache_RestoreColorState(mtlc);
|
||||||
|
MTLVertexCache_FreeVertexCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disables any pending state associated with the current "glyph mode".
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
MTLTR_DisableGlyphModeState()
|
||||||
|
{
|
||||||
|
// TODO : This is similar to OpenGL implementation
|
||||||
|
// When LCD implementation is done weshould make
|
||||||
|
// more changes.
|
||||||
|
J2dTraceLn1(J2D_TRACE_VERBOSE,
|
||||||
|
"MTLTR_DisableGlyphModeState: mode=%d", glyphMode);
|
||||||
|
switch (glyphMode) {
|
||||||
|
case MODE_NO_CACHE_LCD:
|
||||||
|
// TODO : Along with LCD implementation
|
||||||
|
// changes needs to be made
|
||||||
|
case MODE_USE_CACHE_LCD:
|
||||||
|
// TODO : Along with LCD implementation
|
||||||
|
// changes needs to be made
|
||||||
|
break;
|
||||||
|
case MODE_NO_CACHE_GRAY:
|
||||||
|
case MODE_USE_CACHE_GRAY:
|
||||||
|
case MODE_NOT_INITED:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static jboolean
|
||||||
|
MTLTR_DrawGrayscaleGlyphViaCache(MTLContext *mtlc,
|
||||||
|
GlyphInfo *ginfo, jint x, jint y, BMTLSDOps *dstOps)
|
||||||
|
{
|
||||||
|
MTLCacheCellInfo *cell;
|
||||||
|
jfloat x1, y1, x2, y2;
|
||||||
|
|
||||||
|
if (glyphMode != MODE_USE_CACHE_GRAY) {
|
||||||
|
if (glyphMode == MODE_NO_CACHE_GRAY) {
|
||||||
|
MTLVertexCache_DisableMaskCache(mtlc);
|
||||||
|
}
|
||||||
|
MTLTR_EnableGlyphVertexCache(mtlc, dstOps);
|
||||||
|
glyphMode = MODE_USE_CACHE_GRAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ginfo->cellInfo == NULL) {
|
||||||
|
// attempt to add glyph to accelerated glyph cache
|
||||||
|
MTLTR_AddToGlyphCache(ginfo, mtlc, MTLPixelFormatA8Unorm);
|
||||||
|
|
||||||
|
if (ginfo->cellInfo == NULL) {
|
||||||
|
// we'll just no-op in the rare case that the cell is NULL
|
||||||
|
return JNI_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cell = (MTLCacheCellInfo *) (ginfo->cellInfo);
|
||||||
|
cell->timesRendered++;
|
||||||
|
|
||||||
|
x1 = (jfloat)x;
|
||||||
|
y1 = (jfloat)y;
|
||||||
|
x2 = x1 + ginfo->width;
|
||||||
|
y2 = y1 + ginfo->height;
|
||||||
|
|
||||||
|
MTLVertexCache_AddGlyphQuad(mtlc,
|
||||||
|
cell->tx1, cell->ty1,
|
||||||
|
cell->tx2, cell->ty2,
|
||||||
|
x1, y1, x2, y2);
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
static jboolean
|
||||||
|
MTLTR_DrawLCDGlyphViaCache(MTLContext *mtlc, BMTLSDOps *dstOps,
|
||||||
|
GlyphInfo *ginfo, jint x, jint y,
|
||||||
|
jint glyphIndex, jint totalGlyphs,
|
||||||
|
jboolean rgbOrder, jint contrast,
|
||||||
|
id<MTLTexture> dstTexture)
|
||||||
|
{
|
||||||
|
CacheCellInfo *cell;
|
||||||
|
jfloat tx1, ty1, tx2, ty2;
|
||||||
|
jfloat dtx1=0, dty1=0, dtx2=0, dty2=0;
|
||||||
|
jint tw, th;
|
||||||
|
jint sx=0, sy=0, sw=0, sh=0, dxadj=0, dyadj=0;
|
||||||
|
jint x0;
|
||||||
|
jint w = ginfo->width;
|
||||||
|
jint h = ginfo->height;
|
||||||
|
id<MTLTexture> blitTexture = nil;
|
||||||
|
|
||||||
|
id<MTLRenderCommandEncoder> encoder = nil;
|
||||||
|
|
||||||
|
MTLTextureDescriptor *textureDescriptor =
|
||||||
|
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
|
||||||
|
width:w
|
||||||
|
height:h
|
||||||
|
mipmapped:NO];
|
||||||
|
|
||||||
|
blitTexture = [mtlc.device newTextureWithDescriptor:textureDescriptor];
|
||||||
|
[textureDescriptor release];
|
||||||
|
|
||||||
|
if (glyphMode != MODE_USE_CACHE_LCD) {
|
||||||
|
if (glyphMode == MODE_NO_CACHE_GRAY) {
|
||||||
|
MTLVertexCache_DisableMaskCache(mtlc);
|
||||||
|
} else if (glyphMode == MODE_USE_CACHE_GRAY) {
|
||||||
|
MTLTR_DisableGlyphVertexCache(mtlc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (glyphCacheLCD == NULL) {
|
||||||
|
if (!MTLTR_InitGlyphCache(mtlc, JNI_TRUE)) {
|
||||||
|
return JNI_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rgbOrder != lastRGBOrder) {
|
||||||
|
// need to invalidate the cache in this case; see comments
|
||||||
|
// for lastRGBOrder above
|
||||||
|
MTLGlyphCache_Invalidate(glyphCacheLCD);
|
||||||
|
lastRGBOrder = rgbOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
glyphMode = MODE_USE_CACHE_LCD;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ginfo->cellInfo == NULL) {
|
||||||
|
// attempt to add glyph to accelerated glyph cache
|
||||||
|
// TODO : Handle RGB order
|
||||||
|
MTLTR_AddToGlyphCache(ginfo, mtlc, MTLPixelFormatRGBA8Unorm);
|
||||||
|
|
||||||
|
if (ginfo->cellInfo == NULL) {
|
||||||
|
// we'll just no-op in the rare case that the cell is NULL
|
||||||
|
return JNI_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
encoder = [mtlc.encoderManager getTextureEncoder:dstOps->pTexture isSrcOpaque:YES isDstOpaque:YES];
|
||||||
|
if (!MTLTR_EnableLCDGlyphModeState(encoder, mtlc, dstOps,contrast))
|
||||||
|
{
|
||||||
|
return JNI_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned int imageBytes = w * h *4;
|
||||||
|
unsigned char imageData[imageBytes];
|
||||||
|
memset(&imageData, 0, sizeof(imageData));
|
||||||
|
|
||||||
|
for (int i = 0; i < h; i++) {
|
||||||
|
for (int j = 0; j < w; j++) {
|
||||||
|
imageData[(i * w * 4) + j * 4] = ginfo->image[(i * w * 3) + j * 3];
|
||||||
|
imageData[(i * w * 4) + j * 4 + 1] = ginfo->image[(i * w * 3) + j * 3 + 1];
|
||||||
|
imageData[(i * w * 4) + j * 4 + 2] = ginfo->image[(i * w * 3) + j * 3 + 2];
|
||||||
|
imageData[(i * w * 4) + j * 4 + 3] = 0xFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy LCD mask into glyph texture tile
|
||||||
|
MTLRegion region = MTLRegionMake2D(0, 0, w, h);
|
||||||
|
|
||||||
|
NSUInteger bytesPerRow = 4 * ginfo->width;
|
||||||
|
[blitTexture replaceRegion:region
|
||||||
|
mipmapLevel:0
|
||||||
|
withBytes:imageData
|
||||||
|
bytesPerRow:bytesPerRow];
|
||||||
|
|
||||||
|
J2dTraceLn7(J2D_TRACE_INFO, "sx = %d sy = %d x = %d y = %d sw = %d sh = %d w = %d", sx, sy, x, y, sw, sh, w);
|
||||||
|
|
||||||
|
x0 = x;
|
||||||
|
tx1 = 0.0f;
|
||||||
|
ty1 = 0.0f;
|
||||||
|
dtx1 = 0.0f;
|
||||||
|
dty2 = 0.0f;
|
||||||
|
tw = MTLTR_NOCACHE_TILE_SIZE;
|
||||||
|
th = MTLTR_NOCACHE_TILE_SIZE;
|
||||||
|
|
||||||
|
// update the lower-right glyph texture coordinates
|
||||||
|
tx2 = 1.0f;
|
||||||
|
ty2 = 1.0f;
|
||||||
|
|
||||||
|
J2dTraceLn5(J2D_TRACE_INFO, "xOffset %d yOffset %d, dxadj %d, dyadj %d dstOps->height %d", dstOps->xOffset, dstOps->yOffset, dxadj, dyadj, dstOps->height);
|
||||||
|
|
||||||
|
dtx1 = ((jfloat)dxadj) / dstOps->textureWidth;
|
||||||
|
dtx2 = ((float)dxadj + sw) / dstOps->textureWidth;
|
||||||
|
|
||||||
|
dty1 = ((jfloat)dyadj + sh) / dstOps->textureHeight;
|
||||||
|
dty2 = ((jfloat)dyadj) / dstOps->textureHeight;
|
||||||
|
|
||||||
|
J2dTraceLn4(J2D_TRACE_INFO, "tx1 %f, ty1 %f, tx2 %f, ty2 %f", tx1, ty1, tx2, ty2);
|
||||||
|
J2dTraceLn2(J2D_TRACE_INFO, "textureWidth %d textureHeight %d", dstOps->textureWidth, dstOps->textureHeight);
|
||||||
|
J2dTraceLn4(J2D_TRACE_INFO, "dtx1 %f, dty1 %f, dtx2 %f, dty2 %f", dtx1, dty1, dtx2, dty2);
|
||||||
|
|
||||||
|
LCD_ADD_TRIANGLES(tx1, ty1, tx2, ty2, x, y, x+w, y+h);
|
||||||
|
|
||||||
|
[encoder setVertexBytes:txtVertices length:sizeof(txtVertices) atIndex:MeshVertexBuffer];
|
||||||
|
[encoder setFragmentTexture:blitTexture atIndex:0];
|
||||||
|
[encoder setFragmentTexture:dstOps->pTexture atIndex:1];
|
||||||
|
|
||||||
|
[encoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:6];
|
||||||
|
|
||||||
|
vertexCacheIndex = 0;
|
||||||
|
[mtlc.encoderManager endEncoder];
|
||||||
|
|
||||||
|
[blitTexture release];
|
||||||
|
|
||||||
|
MTLCommandBufferWrapper* cbwrapper = [mtlc pullCommandBufferWrapper];
|
||||||
|
|
||||||
|
id<MTLCommandBuffer> commandbuf = [cbwrapper getCommandBuffer];
|
||||||
|
[commandbuf addCompletedHandler:^(id <MTLCommandBuffer> commandbuf) {
|
||||||
|
[cbwrapper release];
|
||||||
|
}];
|
||||||
|
|
||||||
|
[commandbuf commit];
|
||||||
|
[commandbuf waitUntilCompleted];
|
||||||
|
|
||||||
|
// TODO : Updating cache bounds and texture mapping.
|
||||||
|
return JNI_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static jboolean
|
||||||
|
MTLTR_DrawGrayscaleGlyphNoCache(MTLContext *mtlc,
|
||||||
|
GlyphInfo *ginfo, jint x, jint y, BMTLSDOps *dstOps)
|
||||||
|
{
|
||||||
|
jint tw, th;
|
||||||
|
jint sx, sy, sw, sh;
|
||||||
|
jint x0;
|
||||||
|
jint w = ginfo->width;
|
||||||
|
jint h = ginfo->height;
|
||||||
|
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLTR_DrawGrayscaleGlyphNoCache");
|
||||||
|
if (glyphMode != MODE_NO_CACHE_GRAY) {
|
||||||
|
if (glyphMode == MODE_USE_CACHE_GRAY) {
|
||||||
|
MTLTR_DisableGlyphVertexCache(mtlc);
|
||||||
|
}
|
||||||
|
MTLVertexCache_EnableMaskCache(mtlc, dstOps);
|
||||||
|
glyphMode = MODE_NO_CACHE_GRAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
x0 = x;
|
||||||
|
tw = MTLVC_MASK_CACHE_TILE_WIDTH;
|
||||||
|
th = MTLVC_MASK_CACHE_TILE_HEIGHT;
|
||||||
|
|
||||||
|
for (sy = 0; sy < h; sy += th, y += th) {
|
||||||
|
x = x0;
|
||||||
|
sh = ((sy + th) > h) ? (h - sy) : th;
|
||||||
|
|
||||||
|
for (sx = 0; sx < w; sx += tw, x += tw) {
|
||||||
|
sw = ((sx + tw) > w) ? (w - sx) : tw;
|
||||||
|
|
||||||
|
J2dTraceLn7(J2D_TRACE_INFO, "sx = %d sy = %d x = %d y = %d sw = %d sh = %d w = %d", sx, sy, x, y, sw, sh, w);
|
||||||
|
MTLVertexCache_AddMaskQuad(mtlc,
|
||||||
|
sx, sy, x, y, sw, sh,
|
||||||
|
w, ginfo->image,
|
||||||
|
dstOps,
|
||||||
|
ginfo->width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return JNI_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static jboolean
|
||||||
|
MTLTR_DrawLCDGlyphNoCache(MTLContext *mtlc, BMTLSDOps *dstOps,
|
||||||
|
GlyphInfo *ginfo, jint x, jint y,
|
||||||
|
jint rowBytesOffset,
|
||||||
|
jboolean rgbOrder, jint contrast,
|
||||||
|
id<MTLTexture> dstTexture)
|
||||||
|
{
|
||||||
|
jfloat tx1, ty1, tx2, ty2;
|
||||||
|
jfloat dtx1=0, dty1=0, dtx2=0, dty2=0;
|
||||||
|
jint tw, th;
|
||||||
|
jint sx=0, sy=0, sw=0, sh=0, dxadj=0, dyadj=0;
|
||||||
|
jint x0;
|
||||||
|
jint w = ginfo->width;
|
||||||
|
jint h = ginfo->height;
|
||||||
|
id<MTLTexture> blitTexture = nil;
|
||||||
|
|
||||||
|
J2dTraceLn2(J2D_TRACE_INFO, "MTLTR_DrawLCDGlyphNoCache x %d, y%d", x, y);
|
||||||
|
J2dTraceLn3(J2D_TRACE_INFO, "MTLTR_DrawLCDGlyphNoCache rowBytesOffset=%d, rgbOrder=%d, contrast=%d", rowBytesOffset, rgbOrder, contrast);
|
||||||
|
|
||||||
|
|
||||||
|
id<MTLRenderCommandEncoder> encoder = nil;
|
||||||
|
|
||||||
|
MTLTextureDescriptor *textureDescriptor =
|
||||||
|
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
|
||||||
|
width:w
|
||||||
|
height:h
|
||||||
|
mipmapped:NO];
|
||||||
|
|
||||||
|
blitTexture = [mtlc.device newTextureWithDescriptor:textureDescriptor];
|
||||||
|
[textureDescriptor release];
|
||||||
|
|
||||||
|
if (glyphMode != MODE_NO_CACHE_LCD) {
|
||||||
|
if (glyphMode == MODE_NO_CACHE_GRAY) {
|
||||||
|
MTLVertexCache_DisableMaskCache(mtlc);
|
||||||
|
} else if (glyphMode == MODE_USE_CACHE_GRAY) {
|
||||||
|
MTLTR_DisableGlyphVertexCache(mtlc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blitTexture == nil) {
|
||||||
|
J2dTraceLn(J2D_TRACE_ERROR, "can't obtain temporary texture object from pool");
|
||||||
|
return JNI_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
glyphMode = MODE_NO_CACHE_LCD;
|
||||||
|
}
|
||||||
|
encoder = [mtlc.encoderManager getTextureEncoder:dstOps->pTexture isSrcOpaque:YES isDstOpaque:YES];
|
||||||
|
if (!MTLTR_EnableLCDGlyphModeState(encoder, mtlc, dstOps,contrast))
|
||||||
|
{
|
||||||
|
return JNI_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
x0 = x;
|
||||||
|
tx1 = 0.0f;
|
||||||
|
ty1 = 0.0f;
|
||||||
|
dtx1 = 0.0f;
|
||||||
|
dty2 = 0.0f;
|
||||||
|
tw = MTLTR_NOCACHE_TILE_SIZE;
|
||||||
|
th = MTLTR_NOCACHE_TILE_SIZE;
|
||||||
|
|
||||||
|
unsigned int imageBytes = w * h *4;
|
||||||
|
unsigned char imageData[imageBytes];
|
||||||
|
memset(&imageData, 0, sizeof(imageData));
|
||||||
|
|
||||||
|
for (int i = 0; i < h; i++) {
|
||||||
|
for (int j = 0; j < w; j++) {
|
||||||
|
imageData[(i * w * 4) + j * 4] = ginfo->image[(i * w * 3) + j * 3];
|
||||||
|
imageData[(i * w * 4) + j * 4 + 1] = ginfo->image[(i * w * 3) + j * 3 + 1];
|
||||||
|
imageData[(i * w * 4) + j * 4 + 2] = ginfo->image[(i * w * 3) + j * 3 + 2];
|
||||||
|
imageData[(i * w * 4) + j * 4 + 3] = 0xFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy LCD mask into glyph texture tile
|
||||||
|
MTLRegion region = MTLRegionMake2D(0, 0, w, h);
|
||||||
|
|
||||||
|
NSUInteger bytesPerRow = 4 * ginfo->width;
|
||||||
|
[blitTexture replaceRegion:region
|
||||||
|
mipmapLevel:0
|
||||||
|
withBytes:imageData
|
||||||
|
bytesPerRow:bytesPerRow];
|
||||||
|
|
||||||
|
J2dTraceLn7(J2D_TRACE_INFO, "sx = %d sy = %d x = %d y = %d sw = %d sh = %d w = %d", sx, sy, x, y, sw, sh, w);
|
||||||
|
|
||||||
|
|
||||||
|
// update the lower-right glyph texture coordinates
|
||||||
|
tx2 = 1.0f;
|
||||||
|
ty2 = 1.0f;
|
||||||
|
|
||||||
|
J2dTraceLn5(J2D_TRACE_INFO, "xOffset %d yOffset %d, dxadj %d, dyadj %d dstOps->height %d", dstOps->xOffset, dstOps->yOffset, dxadj, dyadj, dstOps->height);
|
||||||
|
|
||||||
|
dtx1 = ((jfloat)dxadj) / dstOps->textureWidth;
|
||||||
|
dtx2 = ((float)dxadj + sw) / dstOps->textureWidth;
|
||||||
|
|
||||||
|
dty1 = ((jfloat)dyadj + sh) / dstOps->textureHeight;
|
||||||
|
dty2 = ((jfloat)dyadj) / dstOps->textureHeight;
|
||||||
|
|
||||||
|
J2dTraceLn4(J2D_TRACE_INFO, "tx1 %f, ty1 %f, tx2 %f, ty2 %f", tx1, ty1, tx2, ty2);
|
||||||
|
J2dTraceLn2(J2D_TRACE_INFO, "textureWidth %d textureHeight %d", dstOps->textureWidth, dstOps->textureHeight);
|
||||||
|
J2dTraceLn4(J2D_TRACE_INFO, "dtx1 %f, dty1 %f, dtx2 %f, dty2 %f", dtx1, dty1, dtx2, dty2);
|
||||||
|
|
||||||
|
LCD_ADD_TRIANGLES(tx1, ty1, tx2, ty2, x, y, x+w, y+h);
|
||||||
|
|
||||||
|
[encoder setVertexBytes:txtVertices length:sizeof(txtVertices) atIndex:MeshVertexBuffer];
|
||||||
|
[encoder setFragmentTexture:blitTexture atIndex:0];
|
||||||
|
[encoder setFragmentTexture:dstOps->pTexture atIndex:1];
|
||||||
|
|
||||||
|
[encoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:6];
|
||||||
|
|
||||||
|
vertexCacheIndex = 0;
|
||||||
|
[mtlc.encoderManager endEncoder];
|
||||||
|
[blitTexture release];
|
||||||
|
|
||||||
|
MTLCommandBufferWrapper* cbwrapper = [mtlc pullCommandBufferWrapper];
|
||||||
|
|
||||||
|
id<MTLCommandBuffer> commandbuf = [cbwrapper getCommandBuffer];
|
||||||
|
[commandbuf addCompletedHandler:^(id <MTLCommandBuffer> commandbuf) {
|
||||||
|
[cbwrapper release];
|
||||||
|
}];
|
||||||
|
|
||||||
|
[commandbuf commit];
|
||||||
|
[commandbuf waitUntilCompleted];
|
||||||
|
|
||||||
|
return JNI_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static jboolean
|
||||||
|
MTLTR_DrawColorGlyphNoCache(MTLContext *mtlc, GlyphInfo *ginfo, jint x, jint y)
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
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, BMTLSDOps *dstOps,
|
||||||
|
jint totalGlyphs, jboolean usePositions,
|
||||||
|
jboolean subPixPos, jboolean rgbOrder, jint lcdContrast,
|
||||||
|
jfloat glyphListOrigX, jfloat glyphListOrigY,
|
||||||
|
unsigned char *images, unsigned char *positions)
|
||||||
|
{
|
||||||
|
int glyphCounter;
|
||||||
|
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLTR_DrawGlyphList");
|
||||||
|
|
||||||
|
RETURN_IF_NULL(mtlc);
|
||||||
|
RETURN_IF_NULL(dstOps);
|
||||||
|
RETURN_IF_NULL(images);
|
||||||
|
if (usePositions) {
|
||||||
|
RETURN_IF_NULL(positions);
|
||||||
|
}
|
||||||
|
|
||||||
|
glyphMode = MODE_NOT_INITED;
|
||||||
|
isCachedDestValid = JNI_FALSE;
|
||||||
|
J2dTraceLn1(J2D_TRACE_INFO, "totalGlyphs = %d", totalGlyphs);
|
||||||
|
|
||||||
|
for (glyphCounter = 0; glyphCounter < totalGlyphs; glyphCounter++) {
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "Entered for loop for glyph list");
|
||||||
|
jint x, y;
|
||||||
|
jfloat glyphx, glyphy;
|
||||||
|
jboolean grayscale, ok;
|
||||||
|
GlyphInfo *ginfo = (GlyphInfo *)jlong_to_ptr(NEXT_LONG(images));
|
||||||
|
|
||||||
|
if (ginfo == NULL) {
|
||||||
|
// this shouldn't happen, but if it does we'll just break out...
|
||||||
|
J2dRlsTraceLn(J2D_TRACE_ERROR,
|
||||||
|
"MTLTR_DrawGlyphList: glyph info is null");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
grayscale = (ginfo->rowBytes == ginfo->width);
|
||||||
|
|
||||||
|
if (usePositions) {
|
||||||
|
jfloat posx = NEXT_FLOAT(positions);
|
||||||
|
jfloat posy = NEXT_FLOAT(positions);
|
||||||
|
glyphx = glyphListOrigX + posx + ginfo->topLeftX;
|
||||||
|
glyphy = glyphListOrigY + posy + ginfo->topLeftY;
|
||||||
|
FLOOR_ASSIGN(x, glyphx);
|
||||||
|
FLOOR_ASSIGN(y, glyphy);
|
||||||
|
} else {
|
||||||
|
glyphx = glyphListOrigX + ginfo->topLeftX;
|
||||||
|
glyphy = glyphListOrigY + ginfo->topLeftY;
|
||||||
|
FLOOR_ASSIGN(x, glyphx);
|
||||||
|
FLOOR_ASSIGN(y, glyphy);
|
||||||
|
glyphListOrigX += ginfo->advanceX;
|
||||||
|
glyphListOrigY += ginfo->advanceY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ginfo->image == NULL) {
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "Glyph image is null");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
J2dTraceLn2(J2D_TRACE_INFO, "Glyph width = %d height = %d", ginfo->width, ginfo->height);
|
||||||
|
J2dTraceLn1(J2D_TRACE_INFO, "rowBytes = %d", ginfo->rowBytes);
|
||||||
|
//TODO : Right now we have initial texture mapping logic
|
||||||
|
// as we implement LCD, cache usage add new selection condition.
|
||||||
|
if (grayscale) {
|
||||||
|
// grayscale or monochrome glyph data
|
||||||
|
if (ginfo->width <= MTLTR_CACHE_CELL_WIDTH &&
|
||||||
|
ginfo->height <= MTLTR_CACHE_CELL_HEIGHT)
|
||||||
|
{
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLTR_DrawGlyphList Grayscale cache");
|
||||||
|
ok = MTLTR_DrawGrayscaleGlyphViaCache(mtlc, ginfo, x, y, dstOps);
|
||||||
|
} else {
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLTR_DrawGlyphList Grayscale no cache");
|
||||||
|
ok = MTLTR_DrawGrayscaleGlyphNoCache(mtlc, ginfo, x, y, dstOps);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
void* dstTexture = dstOps->textureLCD;
|
||||||
|
|
||||||
|
// LCD-optimized glyph data
|
||||||
|
jint rowBytesOffset = 0;
|
||||||
|
|
||||||
|
if (subPixPos) {
|
||||||
|
jint frac = (jint)((glyphx - x) * 3);
|
||||||
|
if (frac != 0) {
|
||||||
|
rowBytesOffset = 3 - frac;
|
||||||
|
x += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Implement LCD text rendering
|
||||||
|
if (rowBytesOffset == 0 &&
|
||||||
|
ginfo->width <= MTLTR_CACHE_CELL_WIDTH &&
|
||||||
|
ginfo->height <= MTLTR_CACHE_CELL_HEIGHT)
|
||||||
|
{
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLTR_DrawGlyphList LCD cache -- :TODO");
|
||||||
|
ok = MTLTR_DrawLCDGlyphViaCache(mtlc, dstOps,
|
||||||
|
ginfo, x, y,
|
||||||
|
glyphCounter, totalGlyphs,
|
||||||
|
rgbOrder, lcdContrast,
|
||||||
|
dstTexture);
|
||||||
|
} else {
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLTR_DrawGlyphList LCD no cache");
|
||||||
|
ok = MTLTR_DrawLCDGlyphNoCache(mtlc, dstOps,
|
||||||
|
ginfo, x, y,
|
||||||
|
rowBytesOffset,
|
||||||
|
rgbOrder, lcdContrast,
|
||||||
|
dstTexture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* This state management needs to be extended for other glyphmodes
|
||||||
|
* when they are implemented.
|
||||||
|
*/
|
||||||
|
if (glyphMode != MODE_NO_CACHE_LCD) {
|
||||||
|
if (glyphMode == MODE_NO_CACHE_GRAY) {
|
||||||
|
MTLVertexCache_DisableMaskCache(mtlc);
|
||||||
|
} else {
|
||||||
|
MTLTR_DisableGlyphVertexCache(mtlc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
unsigned char *images;
|
||||||
|
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLTextRenderer_drawGlyphList");
|
||||||
|
|
||||||
|
images = (unsigned char *)
|
||||||
|
(*env)->GetPrimitiveArrayCritical(env, imgArray, NULL);
|
||||||
|
if (images != NULL) {
|
||||||
|
MTLContext *mtlc = MTLRenderQueue_GetCurrentContext();
|
||||||
|
BMTLSDOps *dstOps = MTLRenderQueue_GetCurrentDestination();
|
||||||
|
|
||||||
|
if (usePositions) {
|
||||||
|
unsigned char *positions = (unsigned char *)
|
||||||
|
(*env)->GetPrimitiveArrayCritical(env, posArray, NULL);
|
||||||
|
if (positions != NULL) {
|
||||||
|
MTLTR_DrawGlyphList(env, mtlc, dstOps,
|
||||||
|
numGlyphs, usePositions,
|
||||||
|
subPixPos, rgbOrder, lcdContrast,
|
||||||
|
glyphListOrigX, glyphListOrigY,
|
||||||
|
images, positions);
|
||||||
|
(*env)->ReleasePrimitiveArrayCritical(env, posArray,
|
||||||
|
positions, JNI_ABORT);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
MTLTR_DrawGlyphList(env, mtlc, dstOps,
|
||||||
|
numGlyphs, usePositions,
|
||||||
|
subPixPos, rgbOrder, lcdContrast,
|
||||||
|
glyphListOrigX, glyphListOrigY,
|
||||||
|
images, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
(*env)->ReleasePrimitiveArrayCritical(env, imgArray,
|
||||||
|
images, JNI_ABORT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* !HEADLESS */
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
#ifndef MTLTexturePool_h_Included
|
||||||
|
#define MTLTexturePool_h_Included
|
||||||
|
#import "MTLUtils.h"
|
||||||
|
|
||||||
|
@interface MTLTexturePoolItem : NSObject
|
||||||
|
@property (readwrite, retain) id<MTLTexture> texture;
|
||||||
|
@property (readwrite) bool isBusy;
|
||||||
|
@property (readwrite, retain) NSDate * lastUsed;
|
||||||
|
@property (readwrite) bool isMultiSample;
|
||||||
|
|
||||||
|
- (id) initWithTexture:(id<MTLTexture>)tex;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MTLPooledTextureHandle : NSObject
|
||||||
|
@property (readonly, assign) id<MTLTexture> texture;
|
||||||
|
@property (readonly) MTLRegion rect;
|
||||||
|
- (void) releaseTexture;
|
||||||
|
@end
|
||||||
|
|
||||||
|
// NOTE: owns all MTLTexture objects
|
||||||
|
@interface MTLTexturePool : NSObject
|
||||||
|
@property (readwrite, retain) id<MTLDevice> device;
|
||||||
|
|
||||||
|
- (id) initWithDevice:(id<MTLDevice>)device;
|
||||||
|
- (MTLPooledTextureHandle *) getTexture:(int)width height:(int)height format:(MTLPixelFormat)format;
|
||||||
|
- (MTLPooledTextureHandle *) getTexture:(int)width height:(int)height format:(MTLPixelFormat)format
|
||||||
|
isMultiSample:(bool)isMultiSample;
|
||||||
|
@end
|
||||||
|
|
||||||
|
#endif /* MTLTexturePool_h_Included */
|
||||||
@@ -0,0 +1,234 @@
|
|||||||
|
#import "MTLTexturePool.h"
|
||||||
|
#import "Trace.h"
|
||||||
|
|
||||||
|
#define SCREEN_MEMORY_SIZE_4K (4096*2160*4) //~33,7 mb
|
||||||
|
#define MAX_POOL_MEMORY SCREEN_MEMORY_SIZE_4K/2
|
||||||
|
#define MAX_POOL_ITEM_LIFETIME_SEC 30
|
||||||
|
|
||||||
|
#define CELL_WIDTH_BITS 5 // ~ 32 pixel
|
||||||
|
#define CELL_HEIGHT_BITS 5 // ~ 32 pixel
|
||||||
|
|
||||||
|
@implementation MTLTexturePoolItem
|
||||||
|
|
||||||
|
@synthesize texture, isBusy, lastUsed, isMultiSample;
|
||||||
|
|
||||||
|
- (id) initWithTexture:(id<MTLTexture>)tex {
|
||||||
|
self = [super init];
|
||||||
|
if (self == nil) return self;
|
||||||
|
self.texture = tex;
|
||||||
|
isBusy = NO;
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) dealloc {
|
||||||
|
[lastUsed release];
|
||||||
|
[texture release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MTLPooledTextureHandle
|
||||||
|
{
|
||||||
|
MTLRegion _rect;
|
||||||
|
id<MTLTexture> _texture;
|
||||||
|
MTLTexturePoolItem * _poolItem;
|
||||||
|
}
|
||||||
|
@synthesize texture = _texture, rect = _rect;
|
||||||
|
|
||||||
|
- (id) initWithPoolItem:(id<MTLTexture>)texture rect:(MTLRegion)rectangle poolItem:(MTLTexturePoolItem *)poolItem {
|
||||||
|
self = [super init];
|
||||||
|
if (self == nil) return self;
|
||||||
|
|
||||||
|
self->_rect = rectangle;
|
||||||
|
self->_texture = texture;
|
||||||
|
self->_poolItem = poolItem;
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) releaseTexture {
|
||||||
|
self->_poolItem.isBusy = NO;
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MTLTexturePool {
|
||||||
|
int _memoryTotalAllocated;
|
||||||
|
|
||||||
|
void ** _cells;
|
||||||
|
int _poolCellWidth;
|
||||||
|
int _poolCellHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
@synthesize device;
|
||||||
|
|
||||||
|
- (id) initWithDevice:(id<MTLDevice>)dev {
|
||||||
|
self = [super init];
|
||||||
|
if (self == nil) return self;
|
||||||
|
|
||||||
|
_memoryTotalAllocated = 0;
|
||||||
|
_poolCellWidth = 10;
|
||||||
|
_poolCellHeight = 10;
|
||||||
|
const int cellsCount = _poolCellWidth * _poolCellHeight;
|
||||||
|
_cells = (void **)malloc(cellsCount * sizeof(void*));
|
||||||
|
memset(_cells, 0, cellsCount * sizeof(void*));
|
||||||
|
self.device = dev;
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) dealloc {
|
||||||
|
for (int c = 0; c < _poolCellWidth * _poolCellHeight; ++c) {
|
||||||
|
NSMutableArray * cell = _cells[c];
|
||||||
|
if (cell != NULL) {
|
||||||
|
[cell release];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(_cells);
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: called from RQ-thread (on blit operations)
|
||||||
|
- (MTLPooledTextureHandle *) getTexture:(int)width height:(int)height format:(MTLPixelFormat)format {
|
||||||
|
return [self getTexture:width height:height format:format isMultiSample:NO];
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: called from RQ-thread (on blit operations)
|
||||||
|
- (MTLPooledTextureHandle *) getTexture:(int)width height:(int)height format:(MTLPixelFormat)format
|
||||||
|
isMultiSample:(bool)isMultiSample {
|
||||||
|
@autoreleasepool {
|
||||||
|
// 1. clean pool if necessary
|
||||||
|
const int requestedPixels = width*height;
|
||||||
|
const int requestedBytes = requestedPixels*4;
|
||||||
|
if (_memoryTotalAllocated + requestedBytes > MAX_POOL_MEMORY) {
|
||||||
|
[self cleanIfNecessary:0]; // release all free textures
|
||||||
|
} else if (_memoryTotalAllocated + requestedBytes > MAX_POOL_MEMORY/2) {
|
||||||
|
[self cleanIfNecessary:MAX_POOL_ITEM_LIFETIME_SEC]; // release only old free textures
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. find free item
|
||||||
|
const int cellX0 = width >> CELL_WIDTH_BITS;
|
||||||
|
const int cellY0 = height >> CELL_HEIGHT_BITS;
|
||||||
|
const int cellX1 = cellX0 + 1;
|
||||||
|
const int cellY1 = cellY0 + 1;
|
||||||
|
if (cellX1 > _poolCellWidth || cellY1 > _poolCellHeight) {
|
||||||
|
const int newCellWidth = cellX1 <= _poolCellWidth ? _poolCellWidth : cellX1;
|
||||||
|
const int newCellHeight = cellY1 <= _poolCellHeight ? _poolCellHeight : cellY1;
|
||||||
|
const int newCellsCount = newCellWidth*newCellHeight;
|
||||||
|
J2dTraceLn2(J2D_TRACE_VERBOSE, "MTLTexturePool: resize: %d -> %d", _poolCellWidth * _poolCellHeight, newCellsCount);
|
||||||
|
void ** newcells = malloc(newCellsCount*sizeof(void*));
|
||||||
|
const int strideBytes = _poolCellWidth * sizeof(void*);
|
||||||
|
for (int cy = 0; cy < _poolCellHeight; ++cy) {
|
||||||
|
void ** dst = newcells + cy*newCellWidth;
|
||||||
|
void ** src = _cells + cy * _poolCellWidth;
|
||||||
|
memcpy(dst, src, strideBytes);
|
||||||
|
if (newCellWidth > _poolCellWidth)
|
||||||
|
memset(dst + _poolCellWidth, 0, (newCellWidth - _poolCellWidth) * sizeof(void*));
|
||||||
|
}
|
||||||
|
if (newCellHeight > _poolCellHeight) {
|
||||||
|
void ** dst = newcells + _poolCellHeight * newCellWidth;
|
||||||
|
memset(dst, 0, (newCellHeight - _poolCellHeight) * newCellWidth * sizeof(void*));
|
||||||
|
}
|
||||||
|
free(_cells);
|
||||||
|
_cells = newcells;
|
||||||
|
_poolCellWidth = newCellWidth;
|
||||||
|
_poolCellHeight = newCellHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
MTLTexturePoolItem * minDeltaTpi = nil;
|
||||||
|
for (int cy = cellY0; cy < cellY1; ++cy) {
|
||||||
|
for (int cx = cellX0; cx < cellX1; ++cx) {
|
||||||
|
NSMutableArray * cell = _cells[cy * _poolCellWidth + cx];
|
||||||
|
if (cell == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const int count = [cell count];
|
||||||
|
int minDeltaArea = -1;
|
||||||
|
int minDeltaAreaIndex = -1;
|
||||||
|
for (int c = 0; c < count; ++c) {
|
||||||
|
MTLTexturePoolItem *tpi = [cell objectAtIndex:c];
|
||||||
|
if (tpi == nil || tpi.isBusy || tpi.texture.pixelFormat != format
|
||||||
|
|| tpi.isMultiSample != isMultiSample) { // TODO: use swizzle when formats are not equal
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (tpi.texture.width < width || tpi.texture.height < height) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const int deltaArea = tpi.texture.width*tpi.texture.height - requestedPixels;
|
||||||
|
if (minDeltaArea < 0 || deltaArea < minDeltaArea) {
|
||||||
|
minDeltaAreaIndex = c;
|
||||||
|
minDeltaArea = deltaArea;
|
||||||
|
minDeltaTpi = tpi;
|
||||||
|
if (deltaArea == 0) {
|
||||||
|
// found exact match in current cell
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (minDeltaTpi != nil) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (minDeltaTpi != nil) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (minDeltaTpi == NULL) {
|
||||||
|
MTLTextureDescriptor *textureDescriptor =
|
||||||
|
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:format
|
||||||
|
width:(NSUInteger) width
|
||||||
|
height:(NSUInteger) height
|
||||||
|
mipmapped:NO];
|
||||||
|
if (isMultiSample) {
|
||||||
|
textureDescriptor.textureType = MTLTextureType2DMultisample;
|
||||||
|
textureDescriptor.sampleCount = MTLAASampleCount;
|
||||||
|
textureDescriptor.storageMode = MTLStorageModePrivate;
|
||||||
|
}
|
||||||
|
|
||||||
|
id <MTLTexture> tex = [[self.device newTextureWithDescriptor:textureDescriptor] autorelease];
|
||||||
|
minDeltaTpi = [[[MTLTexturePoolItem alloc] initWithTexture:tex] autorelease];
|
||||||
|
minDeltaTpi.isMultiSample = isMultiSample;
|
||||||
|
NSMutableArray * cell = _cells[cellY0 * _poolCellWidth + cellX0];
|
||||||
|
if (cell == NULL) {
|
||||||
|
cell = [[NSMutableArray arrayWithCapacity:10] retain];
|
||||||
|
_cells[cellY0 * _poolCellWidth + cellX0] = cell;
|
||||||
|
}
|
||||||
|
[cell addObject:minDeltaTpi];
|
||||||
|
_memoryTotalAllocated += requestedBytes;
|
||||||
|
J2dTraceLn5(J2D_TRACE_VERBOSE, "MTLTexturePool: created pool item: tex=%p, w=%d h=%d, pf=%d | total memory = %d Kb", tex, width, height, format, _memoryTotalAllocated/1024);
|
||||||
|
}
|
||||||
|
|
||||||
|
minDeltaTpi.isBusy = YES;
|
||||||
|
minDeltaTpi.lastUsed = [NSDate date];
|
||||||
|
return [[MTLPooledTextureHandle alloc] initWithPoolItem:minDeltaTpi.texture rect:MTLRegionMake2D(0, 0, minDeltaTpi.texture.width, minDeltaTpi.texture.height) poolItem:minDeltaTpi];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) cleanIfNecessary:(int)lastUsedTimeThreshold {
|
||||||
|
for (int cy = 0; cy < _poolCellHeight; ++cy) {
|
||||||
|
for (int cx = 0; cx < _poolCellWidth; ++cx) {
|
||||||
|
NSMutableArray * cell = _cells[cy * _poolCellWidth + cx];
|
||||||
|
if (cell == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (int c = 0; c < [cell count];) {
|
||||||
|
MTLTexturePoolItem *tpi = [cell objectAtIndex:c];
|
||||||
|
if (!tpi.isBusy) {
|
||||||
|
if (
|
||||||
|
lastUsedTimeThreshold <= 0
|
||||||
|
|| (int)(-[tpi.lastUsed timeIntervalSinceNow]) > lastUsedTimeThreshold
|
||||||
|
) {
|
||||||
|
#ifdef DEBUG
|
||||||
|
J2dTraceImpl(J2D_TRACE_VERBOSE, JNI_TRUE, "MTLTexturePool: remove pool item: tex=%p, w=%d h=%d, elapsed=%d", tpi.texture, tpi.texture.width, tpi.texture.height, (int)(-[tpi.lastUsed timeIntervalSinceNow]));
|
||||||
|
#endif //DEBUG
|
||||||
|
_memoryTotalAllocated -= tpi.texture.width * tpi.texture.height * 4;
|
||||||
|
[cell removeObjectAtIndex:c];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#ifndef MTLTransform_h_Included
|
||||||
|
#define MTLTransform_h_Included
|
||||||
|
|
||||||
|
#import <Metal/Metal.h>
|
||||||
|
|
||||||
|
#include <jni.h>
|
||||||
|
|
||||||
|
@interface MTLTransform : NSObject
|
||||||
|
- (id)init;
|
||||||
|
- (BOOL)isEqual:(MTLTransform *)other;
|
||||||
|
- (void)copyFrom:(MTLTransform *)other;
|
||||||
|
|
||||||
|
- (void)setTransformM00:(jdouble) m00 M10:(jdouble) m10
|
||||||
|
M01:(jdouble) m01 M11:(jdouble) m11
|
||||||
|
M02:(jdouble) m02 M12:(jdouble) m12;
|
||||||
|
- (void)resetTransform;
|
||||||
|
|
||||||
|
- (void)setVertexMatrix:(id<MTLRenderCommandEncoder>)encoder
|
||||||
|
destWidth:(NSUInteger)dw
|
||||||
|
destHeight:(NSUInteger)dh;
|
||||||
|
@end
|
||||||
|
|
||||||
|
#endif // MTLTransform_h_Included
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
#include "MTLTransform.h"
|
||||||
|
|
||||||
|
#include <jni.h>
|
||||||
|
#include <simd/simd.h>
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
@implementation MTLTransform {
|
||||||
|
jboolean _useTransform;
|
||||||
|
simd_float4x4 _transform4x4;
|
||||||
|
simd_float4x4 _normalize4x4; // just a buffer for setVertexMatrix
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)init {
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
memset(&_normalize4x4, 0, sizeof(_normalize4x4));
|
||||||
|
_normalize4x4.columns[3][0] = -1.f;
|
||||||
|
_normalize4x4.columns[3][1] = 1.f;
|
||||||
|
_normalize4x4.columns[3][3] = 1.0;
|
||||||
|
|
||||||
|
_useTransform = JNI_FALSE;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isEqual:(MTLTransform *)other {
|
||||||
|
if (self == other)
|
||||||
|
return YES;
|
||||||
|
return _useTransform == other->_useTransform
|
||||||
|
&& simd_equal(_transform4x4, other->_transform4x4);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)copyFrom:(MTLTransform *)other {
|
||||||
|
_useTransform = other->_useTransform;
|
||||||
|
if (_useTransform) {
|
||||||
|
_transform4x4 = other->_transform4x4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setTransformM00:(jdouble) m00 M10:(jdouble) m10
|
||||||
|
M01:(jdouble) m01 M11:(jdouble) m11
|
||||||
|
M02:(jdouble) m02 M12:(jdouble) m12 {
|
||||||
|
memset(&(_transform4x4), 0, sizeof(_transform4x4));
|
||||||
|
_transform4x4.columns[0][0] = m00;
|
||||||
|
_transform4x4.columns[0][1] = m10;
|
||||||
|
_transform4x4.columns[1][0] = m01;
|
||||||
|
_transform4x4.columns[1][1] = m11;
|
||||||
|
_transform4x4.columns[3][0] = m02;
|
||||||
|
_transform4x4.columns[3][1] = m12;
|
||||||
|
_transform4x4.columns[3][3] = 1.0;
|
||||||
|
_useTransform = JNI_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)resetTransform {
|
||||||
|
_useTransform = JNI_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setVertexMatrix:(id<MTLRenderCommandEncoder>)encoder
|
||||||
|
destWidth:(NSUInteger)dw
|
||||||
|
destHeight:(NSUInteger)dh {
|
||||||
|
// update matrix for vertex shader
|
||||||
|
_normalize4x4.columns[0][0] = 2/(double)dw;
|
||||||
|
_normalize4x4.columns[1][1] = -2/(double)dh;
|
||||||
|
|
||||||
|
if (_useTransform) {
|
||||||
|
simd_float4x4 vertexMatrix = simd_mul(_normalize4x4, _transform4x4);
|
||||||
|
[encoder setVertexBytes:&(vertexMatrix) length:sizeof(vertexMatrix) atIndex:MatrixBuffer];
|
||||||
|
} else {
|
||||||
|
[encoder setVertexBytes:&(_normalize4x4) length:sizeof(_normalize4x4) atIndex:MatrixBuffer];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#ifndef MTLUtils_h_Included
|
||||||
|
#define MTLUtils_h_Included
|
||||||
|
|
||||||
|
#import <Metal/Metal.h>
|
||||||
|
|
||||||
|
#define MTLAASampleCount 4
|
||||||
|
|
||||||
|
#endif /* MTLUtils_h_Included */
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
#include "MTLUtils.h"
|
||||||
|
|
||||||
|
#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(float * position, simd_float4x4 transform4x4) {
|
||||||
|
J2dTraceImpl(J2D_TRACE_VERBOSE, JNI_FALSE, "check transform: ");
|
||||||
|
|
||||||
|
simd_float4 fpt = simd_make_float4(position[0], position[1], position[2], 1.f);
|
||||||
|
simd_float4 fpt_trans = simd_mul(transform4x4, fpt);
|
||||||
|
J2dTraceTraceVector(fpt);
|
||||||
|
J2dTraceImpl(J2D_TRACE_VERBOSE, JNI_FALSE, " ===>>> ");
|
||||||
|
J2dTraceTraceVector(fpt_trans);
|
||||||
|
J2dTraceImpl(J2D_TRACE_VERBOSE, JNI_TRUE, " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void traceMatrix(simd_float4x4 * mtx) {
|
||||||
|
for (int row = 0; row < 4; ++row) {
|
||||||
|
J2dTraceImpl(J2D_TRACE_VERBOSE, JNI_FALSE, " [%lf %lf %lf %lf]",
|
||||||
|
mtx->columns[0][row], mtx->columns[1][row], mtx->columns[2][row], mtx->columns[3][row]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void traceRaster(char * p, int width, int height, int stride) {
|
||||||
|
for (int y = 0; y < height; ++y) {
|
||||||
|
for (int x = 0; x < width; ++x) {
|
||||||
|
unsigned char pix0 = p[y*stride + x*4];
|
||||||
|
unsigned char pix1 = p[y*stride + x*4 + 1];
|
||||||
|
unsigned char pix2 = p[y*stride + x*4 + 2];
|
||||||
|
unsigned char pix3 = p[y*stride + x*4 + 3];
|
||||||
|
J2dTraceImpl(J2D_TRACE_INFO, JNI_FALSE,"[%u,%u,%u,%u], ", pix0, pix1, pix2, pix3);
|
||||||
|
}
|
||||||
|
J2dTraceImpl(J2D_TRACE_INFO, JNI_TRUE, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tracePoints(jint nPoints, jint *xPoints, jint *yPoints) {
|
||||||
|
for (int i = 0; i < nPoints; i++)
|
||||||
|
J2dTraceImpl(J2D_TRACE_INFO, JNI_TRUE, "\t(%d, %d)", *(xPoints++), *(yPoints++));
|
||||||
|
}
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* 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"
|
||||||
|
#include "fontscalerdefs.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constants that control the size of the vertex cache.
|
||||||
|
*/
|
||||||
|
#define MTLVC_MAX_INDEX 1536
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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();
|
||||||
|
void MTLVertexCache_FlushVertexCache(MTLContext *mtlc);
|
||||||
|
void MTLVertexCache_FlushGlyphVertexCache();
|
||||||
|
void MTLVertexCache_FreeVertexCache();
|
||||||
|
void MTLVertexCache_RestoreColorState(MTLContext *mtlc);
|
||||||
|
|
||||||
|
void MTLVertexCache_EnableMaskCache(MTLContext *mtlc, BMTLSDOps *dstOps);
|
||||||
|
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,
|
||||||
|
BMTLSDOps *dstOps,
|
||||||
|
jint fullwidth);
|
||||||
|
void
|
||||||
|
MTLVertexCache_AddGlyphQuad(MTLContext *mtlc,
|
||||||
|
jfloat tx1, jfloat ty1, jfloat tx2, jfloat ty2,
|
||||||
|
jfloat dx1, jfloat dy1, jfloat dx2, jfloat dy2);
|
||||||
|
void MTLVertexCache_CreateSamplingEncoder(MTLContext *mtlc, BMTLSDOps *dstOps);
|
||||||
|
#endif /* MTLVertexCache_h_Included */
|
||||||
@@ -0,0 +1,372 @@
|
|||||||
|
/*
|
||||||
|
* 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"
|
||||||
|
#include "MTLTexturePool.h"
|
||||||
|
#include "MTLTextRenderer.h"
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
typedef struct _J2DVertex {
|
||||||
|
float position[2];
|
||||||
|
float txtpos[2];
|
||||||
|
} J2DVertex;
|
||||||
|
|
||||||
|
static J2DVertex *vertexCache = NULL;
|
||||||
|
static jint vertexCacheIndex = 0;
|
||||||
|
|
||||||
|
static MTLPooledTextureHandle * maskCacheTex = NULL;
|
||||||
|
static jint maskCacheIndex = 0;
|
||||||
|
static id<MTLRenderCommandEncoder> encoder = NULL;
|
||||||
|
|
||||||
|
#define MTLVC_ADD_VERTEX(TX, TY, DX, DY, DZ) \
|
||||||
|
do { \
|
||||||
|
J2DVertex *v = &vertexCache[vertexCacheIndex++]; \
|
||||||
|
v->txtpos[0] = TX; \
|
||||||
|
v->txtpos[1] = TY; \
|
||||||
|
v->position[0]= DX; \
|
||||||
|
v->position[1] = DY; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define MTLVC_ADD_TRIANGLES(TX1, TY1, TX2, TY2, DX1, DY1, DX2, DY2) \
|
||||||
|
do { \
|
||||||
|
MTLVC_ADD_VERTEX(TX1, TY1, DX1, DY1, 0); \
|
||||||
|
MTLVC_ADD_VERTEX(TX2, TY1, DX2, DY1, 0); \
|
||||||
|
MTLVC_ADD_VERTEX(TX2, TY2, DX2, DY2, 0); \
|
||||||
|
MTLVC_ADD_VERTEX(TX2, TY2, DX2, DY2, 0); \
|
||||||
|
MTLVC_ADD_VERTEX(TX1, TY2, DX1, DY2, 0); \
|
||||||
|
MTLVC_ADD_VERTEX(TX1, TY1, DX1, DY1, 0); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
jboolean
|
||||||
|
MTLVertexCache_InitVertexCache()
|
||||||
|
{
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_InitVertexCache");
|
||||||
|
|
||||||
|
if (vertexCache == NULL) {
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_InitVertexCache : vertexCache == NULL");
|
||||||
|
vertexCache = (J2DVertex *)malloc(MTLVC_MAX_INDEX * sizeof(J2DVertex));
|
||||||
|
if (vertexCache == NULL) {
|
||||||
|
return JNI_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return JNI_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MTLVertexCache_FlushVertexCache(MTLContext *mtlc)
|
||||||
|
{
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_FlushVertexCache");
|
||||||
|
|
||||||
|
if (vertexCacheIndex > 0) {
|
||||||
|
[encoder setVertexBytes: vertexCache length:vertexCacheIndex * sizeof(J2DVertex)
|
||||||
|
atIndex:MeshVertexBuffer];
|
||||||
|
|
||||||
|
[encoder setFragmentTexture:maskCacheTex.texture atIndex: 0];
|
||||||
|
J2dTraceLn1(J2D_TRACE_INFO,
|
||||||
|
"MTLVertexCache_FlushVertexCache : encode %d characters", (vertexCacheIndex / 6));
|
||||||
|
[encoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:vertexCacheIndex];
|
||||||
|
}
|
||||||
|
vertexCacheIndex = 0;
|
||||||
|
maskCacheIndex = 0;
|
||||||
|
|
||||||
|
if (maskCacheTex != nil) {
|
||||||
|
[[mtlc getCommandBufferWrapper] registerPooledTexture:maskCacheTex];
|
||||||
|
[maskCacheTex release];
|
||||||
|
maskCacheTex = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MTLVertexCache_FlushGlyphVertexCache()
|
||||||
|
{
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_FlushGlyphVertexCache");
|
||||||
|
|
||||||
|
if (vertexCacheIndex > 0) {
|
||||||
|
[encoder setVertexBytes: vertexCache length:vertexCacheIndex * sizeof(J2DVertex)
|
||||||
|
atIndex:MeshVertexBuffer];
|
||||||
|
id<MTLTexture> glyphCacheTex = MTLTR_GetGlyphCacheTexture();
|
||||||
|
[encoder setFragmentTexture:glyphCacheTex atIndex: 0];
|
||||||
|
J2dTraceLn1(J2D_TRACE_INFO,
|
||||||
|
"MTLVertexCache_FlushGlyphVertexCache : encode %d characters", (vertexCacheIndex / 6));
|
||||||
|
[encoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:vertexCacheIndex];
|
||||||
|
}
|
||||||
|
vertexCacheIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MTLVertexCache_FreeVertexCache()
|
||||||
|
{
|
||||||
|
free(vertexCache);
|
||||||
|
vertexCache = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
// if (mtlc.paint.paintState == sun_java2d_SunGraphics2D_PAINT_ALPHACOLOR) {
|
||||||
|
// //mtlc.paint.color = mtlc.paint.pixel;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
static jboolean
|
||||||
|
MTLVertexCache_InitMaskCache(MTLContext *mtlc) {
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_InitMaskCache");
|
||||||
|
// TODO : We are creating mask cache only of type MTLPixelFormatA8Unorm
|
||||||
|
// when we need more than 1 byte to store a pixel(LCD) we need to update
|
||||||
|
// below code.
|
||||||
|
if (maskCacheTex == NULL) {
|
||||||
|
maskCacheTex = [mtlc.texturePool getTexture:MTLVC_MASK_CACHE_WIDTH_IN_TEXELS
|
||||||
|
height:MTLVC_MASK_CACHE_HEIGHT_IN_TEXELS
|
||||||
|
format:MTLPixelFormatA8Unorm];
|
||||||
|
if (maskCacheTex == nil) {
|
||||||
|
J2dTraceLn(J2D_TRACE_ERROR, "MTLVertexCache_InitMaskCache: can't obtain temporary texture object from pool");
|
||||||
|
return JNI_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// init special fully opaque tile in the upper-right corner of
|
||||||
|
// the mask cache texture
|
||||||
|
|
||||||
|
char tile[MTLVC_MASK_CACHE_TILE_SIZE];
|
||||||
|
memset(tile, 0xff, MTLVC_MASK_CACHE_TILE_SIZE);
|
||||||
|
|
||||||
|
jint texx = MTLVC_MASK_CACHE_TILE_WIDTH * (MTLVC_MASK_CACHE_WIDTH_IN_TILES - 1);
|
||||||
|
|
||||||
|
jint texy = MTLVC_MASK_CACHE_TILE_HEIGHT * (MTLVC_MASK_CACHE_HEIGHT_IN_TILES - 1);
|
||||||
|
|
||||||
|
NSUInteger bytesPerRow = 1 * MTLVC_MASK_CACHE_TILE_WIDTH;
|
||||||
|
|
||||||
|
MTLRegion region = {
|
||||||
|
{texx, texy, 0},
|
||||||
|
{MTLVC_MASK_CACHE_TILE_WIDTH, MTLVC_MASK_CACHE_TILE_HEIGHT, 1}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// do we really need this??
|
||||||
|
[maskCacheTex.texture replaceRegion:region
|
||||||
|
mipmapLevel:0
|
||||||
|
withBytes:tile
|
||||||
|
bytesPerRow:bytesPerRow];
|
||||||
|
|
||||||
|
return JNI_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MTLVertexCache_EnableMaskCache(MTLContext *mtlc, BMTLSDOps *dstOps)
|
||||||
|
{
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_EnableMaskCache");
|
||||||
|
|
||||||
|
if (!MTLVertexCache_InitVertexCache()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maskCacheTex == NULL) {
|
||||||
|
if (!MTLVertexCache_InitMaskCache(mtlc)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MTLVertexCache_CreateSamplingEncoder(mtlc, dstOps);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MTLVertexCache_DisableMaskCache(MTLContext *mtlc)
|
||||||
|
{
|
||||||
|
// TODO : Once we enable check_previous_op
|
||||||
|
// we will start using DisableMaskCache until then
|
||||||
|
// we are force flusging vertexcache.
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_DisableMaskCache");
|
||||||
|
MTLVertexCache_FlushVertexCache(mtlc);
|
||||||
|
MTLVertexCache_RestoreColorState(mtlc);
|
||||||
|
if (maskCacheTex != nil) {
|
||||||
|
[[mtlc getCommandBufferWrapper] registerPooledTexture:maskCacheTex];
|
||||||
|
[maskCacheTex release];
|
||||||
|
maskCacheTex = nil;
|
||||||
|
}
|
||||||
|
maskCacheIndex = 0;
|
||||||
|
free(vertexCache);
|
||||||
|
vertexCache = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MTLVertexCache_CreateSamplingEncoder(MTLContext *mtlc, BMTLSDOps *dstOps) {
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_CreateSamplingEncoder");
|
||||||
|
encoder = [mtlc.encoderManager getTextureEncoder:dstOps isSrcOpaque:NO];
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MTLVertexCache_AddMaskQuad(MTLContext *mtlc,
|
||||||
|
jint srcx, jint srcy,
|
||||||
|
jint dstx, jint dsty,
|
||||||
|
jint width, jint height,
|
||||||
|
jint maskscan, void *mask,
|
||||||
|
BMTLSDOps *dstOps,
|
||||||
|
jint fullwidth)
|
||||||
|
{
|
||||||
|
jfloat tx1, ty1, tx2, ty2;
|
||||||
|
jfloat dx1, dy1, dx2, dy2;
|
||||||
|
|
||||||
|
J2dTraceLn1(J2D_TRACE_INFO, "MTLVertexCache_AddMaskQuad: %d",
|
||||||
|
maskCacheIndex);
|
||||||
|
|
||||||
|
if (maskCacheIndex >= MTLVC_MASK_CACHE_MAX_INDEX)
|
||||||
|
{
|
||||||
|
J2dTraceLn2(J2D_TRACE_INFO, "maskCacheIndex = %d, vertexCacheIndex = %d", maskCacheIndex, vertexCacheIndex);
|
||||||
|
MTLVertexCache_FlushVertexCache(mtlc);
|
||||||
|
// TODO : Since we are not committing command buffer
|
||||||
|
// in FlushVertexCache we need to create new maskcache
|
||||||
|
// after present cache is full. Check whether we can
|
||||||
|
// avoid multiple cache creation.
|
||||||
|
MTLVertexCache_EnableMaskCache(mtlc, dstOps);
|
||||||
|
maskCacheIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mask != NULL) {
|
||||||
|
jint texx = MTLVC_MASK_CACHE_TILE_WIDTH *
|
||||||
|
(maskCacheIndex % MTLVC_MASK_CACHE_WIDTH_IN_TILES);
|
||||||
|
jint texy = MTLVC_MASK_CACHE_TILE_HEIGHT *
|
||||||
|
(maskCacheIndex / MTLVC_MASK_CACHE_WIDTH_IN_TILES);
|
||||||
|
J2dTraceLn5(J2D_TRACE_INFO, "texx = %d texy = %d width = %d height = %d fullwidth = %d", texx, texy, width,
|
||||||
|
height, fullwidth);
|
||||||
|
NSUInteger bytesPerRow = 1 * width;
|
||||||
|
NSUInteger slice = bytesPerRow * srcy + srcx;
|
||||||
|
MTLRegion region = {
|
||||||
|
{texx, texy, 0},
|
||||||
|
{width, height, 1}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Whenever we have source stride bigger that destination stride
|
||||||
|
// we need to pick appropriate source subtexture. In repalceRegion
|
||||||
|
// we can give destination subtexturing properly but we can't
|
||||||
|
// subtexture from system memory glyph we have. So in such
|
||||||
|
// cases we are creating seperate tile and scan the source
|
||||||
|
// stride into destination using memcpy. In case of OpenGL we
|
||||||
|
// can update source pointers, in case of D3D we ar doing memcpy.
|
||||||
|
// We can use MTLBuffer and then copy source subtexture but that
|
||||||
|
// adds extra blitting logic.
|
||||||
|
// TODO : Research more and try removing memcpy logic.
|
||||||
|
if (fullwidth <= width) {
|
||||||
|
int height_offset = bytesPerRow * srcy;
|
||||||
|
[maskCacheTex.texture replaceRegion:region
|
||||||
|
mipmapLevel:0
|
||||||
|
withBytes:mask + height_offset
|
||||||
|
bytesPerRow:bytesPerRow];
|
||||||
|
} else {
|
||||||
|
int dst_offset, src_offset;
|
||||||
|
int size = 1 * width * height;
|
||||||
|
char tile[size];
|
||||||
|
dst_offset = 0;
|
||||||
|
for (int i = srcy; i < srcy + height; i++) {
|
||||||
|
J2dTraceLn2(J2D_TRACE_INFO, "srcx = %d srcy = %d", srcx, srcy);
|
||||||
|
src_offset = fullwidth * i + srcx;
|
||||||
|
J2dTraceLn2(J2D_TRACE_INFO, "src_offset = %d dst_offset = %d", src_offset, dst_offset);
|
||||||
|
memcpy(tile + dst_offset, mask + src_offset, width);
|
||||||
|
dst_offset = dst_offset + width;
|
||||||
|
}
|
||||||
|
[maskCacheTex.texture replaceRegion:region
|
||||||
|
mipmapLevel:0
|
||||||
|
withBytes:tile
|
||||||
|
bytesPerRow:bytesPerRow];
|
||||||
|
}
|
||||||
|
|
||||||
|
tx1 = ((jfloat) texx) / MTLVC_MASK_CACHE_WIDTH_IN_TEXELS;
|
||||||
|
ty1 = ((jfloat) texy) / MTLVC_MASK_CACHE_HEIGHT_IN_TEXELS;
|
||||||
|
} else {
|
||||||
|
tx1 = ((jfloat)MTLVC_MASK_CACHE_SPECIAL_TILE_X) /
|
||||||
|
MTLVC_MASK_CACHE_WIDTH_IN_TEXELS;
|
||||||
|
ty1 = ((jfloat)MTLVC_MASK_CACHE_SPECIAL_TILE_Y) /
|
||||||
|
MTLVC_MASK_CACHE_HEIGHT_IN_TEXELS;
|
||||||
|
}
|
||||||
|
maskCacheIndex++;
|
||||||
|
|
||||||
|
tx2 = tx1 + (((jfloat)width) / MTLVC_MASK_CACHE_WIDTH_IN_TEXELS);
|
||||||
|
ty2 = ty1 + (((jfloat)height) / MTLVC_MASK_CACHE_HEIGHT_IN_TEXELS);
|
||||||
|
|
||||||
|
dx1 = (jfloat)dstx;
|
||||||
|
dy1 = (jfloat)dsty;
|
||||||
|
dx2 = dx1 + width;
|
||||||
|
dy2 = dy1 + height;
|
||||||
|
|
||||||
|
J2dTraceLn8(J2D_TRACE_INFO, "tx1 = %f ty1 = %f tx2 = %f ty2 = %f dx1 = %f dy1 = %f dx2 = %f dy2 = %f", tx1, ty1, tx2, ty2, dx1, dy1, dx2, dy2);
|
||||||
|
MTLVC_ADD_TRIANGLES(tx1, ty1, tx2, ty2,
|
||||||
|
dx1, dy1, dx2, dy2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MTLVertexCache_AddGlyphQuad(MTLContext *mtlc,
|
||||||
|
jfloat tx1, jfloat ty1, jfloat tx2, jfloat ty2,
|
||||||
|
jfloat dx1, jfloat dy1, jfloat dx2, jfloat dy2)
|
||||||
|
{
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_AddGlyphQuad");
|
||||||
|
|
||||||
|
if (vertexCacheIndex >= MTLVC_MAX_INDEX)
|
||||||
|
{
|
||||||
|
J2dTraceLn2(J2D_TRACE_INFO, "maskCacheIndex = %d, vertexCacheIndex = %d", maskCacheIndex, vertexCacheIndex);
|
||||||
|
MTLVertexCache_FlushGlyphVertexCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
MTLVC_ADD_TRIANGLES(tx1, ty1, tx2, ty2,
|
||||||
|
dx1, dy1, dx2, dy2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* !HEADLESS */
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
|||||||
@@ -263,13 +263,13 @@ public class BufferedPaints {
|
|||||||
|
|
||||||
double xp0, xp1, xp3, yp0, yp1, yp3;
|
double xp0, xp1, xp3, yp0, yp1, yp3;
|
||||||
try {
|
try {
|
||||||
at.invert();
|
at.invert();
|
||||||
xp0 = at.getScaleX();
|
xp0 = at.getScaleX();
|
||||||
xp1 = at.getShearX();
|
xp1 = at.getShearX();
|
||||||
xp3 = at.getTranslateX();
|
xp3 = at.getTranslateX();
|
||||||
yp0 = at.getShearY();
|
yp0 = at.getShearY();
|
||||||
yp1 = at.getScaleY();
|
yp1 = at.getScaleY();
|
||||||
yp3 = at.getTranslateY();
|
yp3 = at.getTranslateY();
|
||||||
} catch (java.awt.geom.NoninvertibleTransformException e) {
|
} catch (java.awt.geom.NoninvertibleTransformException e) {
|
||||||
xp0 = xp1 = xp3 = yp0 = yp1 = yp3 = 0.0;
|
xp0 = xp1 = xp3 = yp0 = yp1 = yp3 = 0.0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2019, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@@ -190,6 +190,7 @@ public class RenderBuffer {
|
|||||||
public final RenderBuffer putInt(int pos, int x) {
|
public final RenderBuffer putInt(int pos, int x) {
|
||||||
// assert (baseAddress + pos % SIZEOF_INT == 0);
|
// assert (baseAddress + pos % SIZEOF_INT == 0);
|
||||||
unsafe.putInt(baseAddress + pos, x);
|
unsafe.putInt(baseAddress + pos, x);
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,6 +198,7 @@ public class RenderBuffer {
|
|||||||
// assert (position() % SIZEOF_INT == 0);
|
// assert (position() % SIZEOF_INT == 0);
|
||||||
unsafe.putInt(curAddress, x);
|
unsafe.putInt(curAddress, x);
|
||||||
curAddress += SIZEOF_INT;
|
curAddress += SIZEOF_INT;
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
#include "stdlib.h"
|
#include "stdlib.h"
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
|
#include "Trace.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This include file contains information on how to use a SurfaceData
|
* This include file contains information on how to use a SurfaceData
|
||||||
@@ -80,6 +81,8 @@ Java_sun_java2d_SurfaceData_initIDs(JNIEnv *env, jclass sd)
|
|||||||
{
|
{
|
||||||
jclass pICMClass;
|
jclass pICMClass;
|
||||||
|
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "Java_sun_java2d_SurfaceData_initIDs --- invoked ");
|
||||||
|
|
||||||
InitGlobalClassRef(pInvalidPipeClass, env,
|
InitGlobalClassRef(pInvalidPipeClass, env,
|
||||||
"sun/java2d/InvalidPipeException");
|
"sun/java2d/InvalidPipeException");
|
||||||
|
|
||||||
@@ -235,6 +238,9 @@ JNIEXPORT SurfaceDataOps * JNICALL
|
|||||||
SurfaceData_InitOps(JNIEnv *env, jobject sData, int opsSize)
|
SurfaceData_InitOps(JNIEnv *env, jobject sData, int opsSize)
|
||||||
{
|
{
|
||||||
SurfaceDataOps *ops = malloc(opsSize);
|
SurfaceDataOps *ops = malloc(opsSize);
|
||||||
|
|
||||||
|
J2dTraceLn(J2D_TRACE_INFO, "SurfaceData_InitOps --- invoked ");
|
||||||
|
|
||||||
SurfaceData_SetOps(env, sData, ops);
|
SurfaceData_SetOps(env, sData, ops);
|
||||||
if (ops != NULL) {
|
if (ops != NULL) {
|
||||||
memset(ops, 0, opsSize);
|
memset(ops, 0, opsSize);
|
||||||
|
|||||||
Reference in New Issue
Block a user