Skip to content

Commit c6d653e

Browse files
authored
Merge pull request #48 from silenium-dev/feature/direct-render
Complete rewrite of the rendering and composable part
2 parents b7a2eeb + acad856 commit c6d653e

38 files changed

+1163
-1711
lines changed

.github/workflows/build.yaml

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,20 @@ jobs:
2727
repo-username: ${{ secrets.REPOSILITE_USERNAME }}
2828
repo-password: ${{ secrets.REPOSILITE_PASSWORD }}
2929
tests: false
30-
java-version: 11
30+
java-version: 17
31+
platform: ${{ github.job }}
32+
windows-x86_64:
33+
runs-on: windows-latest
34+
steps:
35+
- uses: silenium-dev/actions/jni-natives/windows@main
36+
with:
37+
gradle-cache-encryption-key: ${{ secrets.GRADLE_CACHE_ENCRYPTION_KEY }}
38+
snapshot-repo-url: "https://reposilite.silenium.dev/snapshots"
39+
release-repo-url: "https://reposilite.silenium.dev/releases"
40+
repo-username: ${{ secrets.REPOSILITE_USERNAME }}
41+
repo-password: ${{ secrets.REPOSILITE_PASSWORD }}
42+
tests: false
43+
java-version: 17
3144
platform: ${{ github.job }}
3245
kotlin:
3346
runs-on: ubuntu-22.04
@@ -40,4 +53,4 @@ jobs:
4053
repo-username: ${{ secrets.REPOSILITE_USERNAME }}
4154
repo-password: ${{ secrets.REPOSILITE_PASSWORD }}
4255
tests: false
43-
java-version: 11
56+
java-version: 17

build.gradle.kts

Lines changed: 58 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
22
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
33
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
4+
import java.net.URLClassLoader
5+
import kotlin.reflect.full.functions
6+
import kotlin.reflect.jvm.isAccessible
47

58
plugins {
69
alias(libs.plugins.kotlin)
710
alias(libs.plugins.kotlin.compose)
811
alias(libs.plugins.compose)
12+
alias(libs.plugins.bytebuddy)
913
`maven-publish`
1014
}
1115

@@ -18,10 +22,31 @@ repositories {
1822
google()
1923
}
2024

25+
allprojects {
26+
apply<MavenPublishPlugin>()
27+
apply<BasePlugin>()
28+
29+
this.group = "dev.silenium.compose.gl"
30+
this.version = findProperty("deploy.version") as String? ?: "0.0.0-SNAPSHOT"
31+
32+
publishing {
33+
repositories {
34+
val url = System.getenv("MAVEN_REPO_URL") ?: return@repositories
35+
maven(url) {
36+
name = "reposilite"
37+
credentials {
38+
username = System.getenv("MAVEN_REPO_USERNAME") ?: ""
39+
password = System.getenv("MAVEN_REPO_PASSWORD") ?: ""
40+
}
41+
}
42+
}
43+
}
44+
}
45+
2146
val deployNative = (findProperty("deploy.native") as String?)?.toBoolean() ?: true
2247
val deployKotlin = (findProperty("deploy.kotlin") as String?)?.toBoolean() ?: true
2348

24-
val lwjglNatives = "natives-linux"
49+
val lwjglNatives = arrayOf("natives-linux", "natives-windows")
2550

2651
dependencies {
2752
implementation(compose.desktop.common)
@@ -36,33 +61,24 @@ dependencies {
3661
api(libs.lwjgl.egl)
3762
libs.bundles.lwjgl.natives.get().forEach {
3863
api(it)
39-
runtimeOnly(variantOf(provider { it }) { classifier(lwjglNatives) })
64+
lwjglNatives.forEach { native ->
65+
runtimeOnly(variantOf(provider { it }) { classifier(native) })
66+
}
4067
}
4168

4269
implementation(libs.bundles.kotlinx.coroutines)
43-
// api(libs.bundles.skiko) {
44-
// version {
45-
// strictly(libs.skiko.awt.runtime.linux.x64.get().version!!)
46-
// }
47-
// }
70+
implementation("net.java.dev.jna:jna")
71+
api(libs.bundles.skiko) {
72+
version {
73+
strictly(libs.versions.skiko.get())
74+
}
75+
}
4876

4977
testImplementation(compose.desktop.currentOs)
5078
testImplementation(libs.logback.classic)
5179
testImplementation("me.saket.telephoto:zoomable:0.14.0")
5280
}
5381

54-
compose.desktop {
55-
application {
56-
mainClass = "MainKt"
57-
58-
nativeDistributions {
59-
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
60-
packageName = "compose-gl"
61-
packageVersion = "1.0.0"
62-
}
63-
}
64-
}
65-
6682
java {
6783
withSourcesJar()
6884
sourceCompatibility = JavaVersion.VERSION_11
@@ -77,23 +93,31 @@ kotlin {
7793
}
7894
}
7995

80-
allprojects {
81-
apply<MavenPublishPlugin>()
82-
apply<BasePlugin>()
96+
val skiaVersion = configurations.compileClasspath.map {
97+
it.filter { it.name.matches(Regex("skiko-awt-\\d.+.jar")) }.singleFile
98+
}.get().let {
99+
val loader = URLClassLoader(arrayOf(it.toURI().toURL()))
100+
val clazz = loader.loadClass("org.jetbrains.skiko.Version").kotlin
101+
val getSkikoVersion = clazz.functions.single { it.name == "getSkiko" }
102+
val getSkiaVersion = clazz.functions.single { it.name == "getSkia" }
103+
val constructor = clazz.constructors.single()
104+
constructor.isAccessible = true
105+
val instance = constructor.call()
106+
val skikoVersion = getSkikoVersion.call(instance)
107+
val skiaVersion = getSkiaVersion.call(instance)
108+
println("skiko version: $skikoVersion")
109+
println("skia version: $skiaVersion")
110+
rootProject.ext.set("skia.version", skiaVersion)
111+
}
83112

84-
group = "dev.silenium.compose.gl"
85-
version = findProperty("deploy.version") as String? ?: "0.0.0-SNAPSHOT"
113+
compose.desktop {
114+
application {
115+
mainClass = "MainKt"
86116

87-
publishing {
88-
repositories {
89-
val url = System.getenv("MAVEN_REPO_URL") ?: return@repositories
90-
maven(url) {
91-
name = "reposilite"
92-
credentials {
93-
username = System.getenv("MAVEN_REPO_USERNAME") ?: ""
94-
password = System.getenv("MAVEN_REPO_PASSWORD") ?: ""
95-
}
96-
}
117+
nativeDistributions {
118+
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
119+
packageName = "compose-gl"
120+
packageVersion = "1.0.0"
97121
}
98122
}
99123
}

gradle/libs.versions.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ logback-classic = { group = "ch.qos.logback", name = "logback-classic", version
3131
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
3232
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
3333
compose = { id = "org.jetbrains.compose", version.ref = "compose" }
34+
bytebuddy = { id = "net.bytebuddy.byte-buddy-gradle-plugin", version = "1.17.7" }
3435

3536
[bundles]
3637
kotlinx-coroutines = [

native/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
.idea/
22
*.iml
33
cmake-build-*/
4+
third_party/

native/CMakeLists.txt

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@ cmake_minimum_required(VERSION 3.16)
22
if (NOT DEFINED PROJECT_NAME)
33
set(PROJECT_NAME "compose-gl")
44
endif ()
5+
6+
if (NOT DEFINED JAVA_HOME)
7+
if (DEFINED ENV{JAVA_HOME})
8+
set(JAVA_HOME "$ENV{JAVA_HOME}")
9+
endif ()
10+
endif ()
11+
512
if (NOT DEFINED JAVA_HOME)
613
message(FATAL_ERROR "JAVA_HOME must be defined")
714
else ()
@@ -10,12 +17,12 @@ endif ()
1017

1118
project(${PROJECT_NAME} LANGUAGES CXX)
1219

13-
set(CMAKE_CXX_STANDARD 20)
20+
set(CMAKE_CXX_STANDARD 23)
1421
set(CMAKE_CXX_STANDARD_REQUIRED ON)
1522
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
1623

1724
set(SOURCES
18-
25+
src/cpp/library.cpp
1926
)
2027

2128
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
@@ -24,9 +31,11 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
2431
endif ()
2532

2633
list(APPEND SOURCES
27-
src/cpp/linux/GLXContext.cpp
2834
)
2935
elseif (CMAKE_SYSTEM_NAME STREQUAL "Windows")
36+
list(APPEND SOURCES
37+
src/cpp/windows/D3DInterop.cpp
38+
)
3039
endif ()
3140

3241
add_library(${PROJECT_NAME} SHARED ${SOURCES})
@@ -38,11 +47,13 @@ target_include_directories(${PROJECT_NAME} PUBLIC "${JAVA_HOME}/include")
3847
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
3948
target_compile_definitions(${PROJECT_NAME} PRIVATE -D_LINUX)
4049
find_package(PkgConfig REQUIRED)
41-
pkg_check_modules(GL REQUIRED IMPORTED_TARGET gl egl glx)
42-
target_link_libraries(${PROJECT_NAME} PUBLIC PkgConfig::GL)
4350
target_include_directories(${PROJECT_NAME} PUBLIC "${JAVA_HOME}/include/linux")
4451
elseif (CMAKE_SYSTEM_NAME STREQUAL "Windows")
52+
include(cmake/skia.cmake)
4553
target_compile_definitions(${PROJECT_NAME} PRIVATE -D_WINDOWS)
46-
target_link_libraries(${PROJECT_NAME} PUBLIC opengl32 dxgi d3d11 d3dcompiler)
54+
target_compile_definitions(${PROJECT_NAME} PRIVATE SK_DIRECT3D NOMINMAX WIN32_LEAN_AND_MEAN)
55+
target_compile_options(${PROJECT_NAME} PRIVATE /MT)
56+
target_link_libraries(${PROJECT_NAME} PUBLIC opengl32 dxgi d3d12 d3dcompiler)
4757
target_include_directories(${PROJECT_NAME} PUBLIC "${JAVA_HOME}/include/win32")
58+
target_link_libraries(${PROJECT_NAME} PUBLIC Skia)
4859
endif ()

native/build.gradle.kts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,21 +29,20 @@ val platform = platformString?.let(Platform::invoke) ?: NativePlatform.platform(
2929
val cmakeExe = findProperty("cmake.executable") as? String ?: "cmake"
3030
val generateMakefile = tasks.register<Exec>("generateMakefile") {
3131
workingDir = layout.buildDirectory.dir("cmake").get().asFile.apply { mkdirs() }
32-
val additionalFlags = mutableListOf(
33-
"-DJAVA_HOME=${System.getProperty("java.home")}",
34-
"-DPROJECT_NAME=${libName}",
32+
val additionalFlags = listOfNotNull(
33+
"JAVA_HOME" to System.getProperty("java.home"),
34+
"PROJECT_NAME" to libName,
35+
"CMAKE_BUILD_TYPE" to "Debug",
36+
rootProject.ext.get("skia.version")?.let { "SKIA_VERSION" to it },
3537
)
3638
commandLine(
3739
cmakeExe,
38-
*additionalFlags.toTypedArray(),
40+
*additionalFlags.map { "-D${it.first}=${it.second}" }.toTypedArray(),
3941
layout.projectDirectory.asFile.absolutePath,
4042
)
4143

4244
inputs.file(layout.projectDirectory.file("CMakeLists.txt"))
43-
inputs.properties(
44-
"JAVA_HOME" to System.getProperty("java.home"),
45-
"PROJECT_NAME" to libName,
46-
)
45+
inputs.properties(additionalFlags.toMap())
4746
outputs.dir(workingDir)
4847
standardOutput = System.out
4948
}
@@ -76,6 +75,7 @@ val jar = tasks.register<Jar>("nativeJar") {
7675
val libName = rootProject.name
7776
val platformString = findProperty("deploy.platform")?.toString()
7877
val platform = platformString?.let(Platform::invoke) ?: NativePlatform.platform()
78+
archiveBaseName.set("$libName-natives-$platform")
7979

8080
from(compileNative.get().outputs.files) {
8181
rename {

native/cmake/skia.cmake

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
set(SKIA_VERSION "m132-a00c390e98-1" CACHE STRING "Skia version")
2+
set(SKIA_OS "linux")
3+
set(SKIA_ARCH "x64")
4+
set(SKIA_VARIANT "Debug")
5+
6+
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
7+
set(SKIA_VARIANT "Debug")
8+
endif ()
9+
10+
if (CMAKE_BUILD_TYPE STREQUAL "Release")
11+
set(SKIA_VARIANT "Release")
12+
endif ()
13+
14+
if (CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
15+
set(SKIA_VARIANT "Debug")
16+
endif ()
17+
18+
if (CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")
19+
set(SKIA_VARIANT "Release")
20+
endif ()
21+
22+
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
23+
set(SKIA_OS "windows")
24+
elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux")
25+
set(SKIA_OS "linux")
26+
elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
27+
set(SKIA_OS "macos")
28+
endif ()
29+
30+
string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" PROCESSOR)
31+
32+
if (PROCESSOR MATCHES "arm" OR PROCESSOR MATCHES "aarch64")
33+
set(SKIA_ARCH "arm64")
34+
elseif (PROCESSOR MATCHES "x86_64" OR PROCESSOR MATCHES "amd64")
35+
set(SKIA_ARCH "x64")
36+
endif ()
37+
38+
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/download")
39+
40+
file(DOWNLOAD "https://api.github.com/repos/JetBrains/skia-pack/releases/tags/${SKIA_VERSION}" "${CMAKE_BINARY_DIR}/download/skia_assets.json" STATUS GH_RELEASE_STATUS SHOW_PROGRESS)
41+
list(GET GH_RELEASE_STATUS 0 GH_RELEASE_STATUS_CODE)
42+
if (GH_RELEASE_STATUS_CODE)
43+
message(FATAL_ERROR "Failed to download GitHub release: ${GH_RELEASE_STATUS_CODE}")
44+
return()
45+
endif ()
46+
47+
file(READ "${CMAKE_BINARY_DIR}/download/skia_assets.json" GH_RELEASE_JSON)
48+
49+
string(JSON ASSETS_COUNT LENGTH ${GH_RELEASE_JSON} "assets")
50+
math(EXPR ASSETS_COUNT "${ASSETS_COUNT} - 1")
51+
52+
foreach (assetIdx RANGE 0 ${ASSETS_COUNT} 1)
53+
string(JSON assetName GET ${GH_RELEASE_JSON} "assets" "${assetIdx}" "name")
54+
if (assetName MATCHES "Skia-${SKIA_VERSION}-${SKIA_OS}-${SKIA_VARIANT}-${SKIA_ARCH}.zip")
55+
message(STATUS "Found asset ${assetIdx} of ${ASSETS_COUNT}: ${assetName}")
56+
set(ASSET_IDX ${assetIdx})
57+
set(ASSET_NAME ${assetName})
58+
string(JSON ASSET_URL GET ${GH_RELEASE_JSON} "assets" "${assetIdx}" "browser_download_url")
59+
string(JSON ASSET_HASH GET ${GH_RELEASE_JSON} "assets" "${assetIdx}" "digest")
60+
break()
61+
endif ()
62+
endforeach ()
63+
64+
message(STATUS "Downloading Skia from ${ASSET_URL} with hash ${ASSET_HASH}")
65+
66+
set(SKIA_URL "${ASSET_URL}")
67+
string(REPLACE ":" "=" ASSET_HASH "${ASSET_HASH}")
68+
69+
if (NOT ASSET_HASH)
70+
message(WARNING "Failed to find Skia hash, just checking for the files existence to determine if we need to download Skia again.")
71+
if (NOT EXISTS "${CMAKE_BINARY_DIR}/download/${ASSET_NAME}")
72+
file(DOWNLOAD ${SKIA_URL} "${CMAKE_BINARY_DIR}/download/${ASSET_NAME}" STATUS SKIA_DOWNLOAD_STATUS SHOW_PROGRESS)
73+
endif ()
74+
else ()
75+
file(DOWNLOAD ${SKIA_URL} "${CMAKE_BINARY_DIR}/download/${ASSET_NAME}" STATUS SKIA_DOWNLOAD_STATUS EXPECTED_HASH "${ASSET_HASH}" SHOW_PROGRESS)
76+
endif ()
77+
78+
list(GET SKIA_DOWNLOAD_STATUS 0 SKIA_DOWNLOAD_STATUS_CODE)
79+
if (SKIA_DOWNLOAD_STATUS_CODE)
80+
message(FATAL_ERROR "Failed to download Skia: ${SKIA_DOWNLOAD_STATUS_CODE}")
81+
return()
82+
endif ()
83+
84+
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/third_party/skia")
85+
message(STATUS "Unpacking Skia to ${CMAKE_BINARY_DIR}/third_party/skia")
86+
file(REMOVE_RECURSE "${CMAKE_BINARY_DIR}/third_party/skia")
87+
file(ARCHIVE_EXTRACT INPUT "${CMAKE_BINARY_DIR}/download/${ASSET_NAME}" DESTINATION "${CMAKE_BINARY_DIR}/third_party/skia")
88+
89+
add_library(Skia INTERFACE)
90+
target_include_directories(Skia INTERFACE
91+
"${CMAKE_BINARY_DIR}/third_party/skia/include"
92+
"${CMAKE_BINARY_DIR}/third_party/skia/modules/svg/include"
93+
"${CMAKE_BINARY_DIR}/third_party/skia/src"
94+
"${CMAKE_BINARY_DIR}/third_party/skia"
95+
"${CMAKE_BINARY_DIR}/third_party/skia/third_party/externals/angle2/include"
96+
"${CMAKE_BINARY_DIR}/third_party/skia/third_party/externals/freetype/include"
97+
"${CMAKE_BINARY_DIR}/third_party/skia/third_party/externals/harfbuzz/src"
98+
"${CMAKE_BINARY_DIR}/third_party/skia/third_party/externals/icu/source/common"
99+
"${CMAKE_BINARY_DIR}/third_party/skia/third_party/externals/libpng"
100+
"${CMAKE_BINARY_DIR}/third_party/skia/third_party/externals/libwebp/src"
101+
"${CMAKE_BINARY_DIR}/third_party/skia/third_party/externals/swiftshader/include"
102+
"${CMAKE_BINARY_DIR}/third_party/skia/third_party/externals/zlib"
103+
"${CMAKE_BINARY_DIR}/third_party/skia/third_party/icu"
104+
)
105+
target_link_directories(Skia INTERFACE "${CMAKE_BINARY_DIR}/third_party/skia/out/${SKIA_VARIANT}-${SKIA_OS}-${SKIA_ARCH}")
106+
target_link_libraries(Skia INTERFACE
107+
bentleyottmann.lib libwebp.lib skottie.lib skshaper.lib svg.lib
108+
d3d12allocator.lib icu.lib libwebp_sse41.lib skparagraph.lib skunicode_core.lib wuffs.lib
109+
expat.lib libjpeg.lib skcms.lib skresources.lib skunicode_icu.lib zlib.lib
110+
harfbuzz.lib libpng.lib skia.lib sksg.lib spirv_cross.lib
111+
)

native/src/cpp/library.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
// empty

0 commit comments

Comments
 (0)