Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,20 @@ jobs:
repo-username: ${{ secrets.REPOSILITE_USERNAME }}
repo-password: ${{ secrets.REPOSILITE_PASSWORD }}
tests: false
java-version: 11
java-version: 17
platform: ${{ github.job }}
windows-x86_64:
runs-on: windows-latest
steps:
- uses: silenium-dev/actions/jni-natives/windows@main
with:
gradle-cache-encryption-key: ${{ secrets.GRADLE_CACHE_ENCRYPTION_KEY }}
snapshot-repo-url: "https://reposilite.silenium.dev/snapshots"
release-repo-url: "https://reposilite.silenium.dev/releases"
repo-username: ${{ secrets.REPOSILITE_USERNAME }}
repo-password: ${{ secrets.REPOSILITE_PASSWORD }}
tests: false
java-version: 17
platform: ${{ github.job }}
kotlin:
runs-on: ubuntu-22.04
Expand All @@ -40,4 +53,4 @@ jobs:
repo-username: ${{ secrets.REPOSILITE_USERNAME }}
repo-password: ${{ secrets.REPOSILITE_PASSWORD }}
tests: false
java-version: 11
java-version: 17
92 changes: 58 additions & 34 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
import java.net.URLClassLoader
import kotlin.reflect.full.functions
import kotlin.reflect.jvm.isAccessible

plugins {
alias(libs.plugins.kotlin)
alias(libs.plugins.kotlin.compose)
alias(libs.plugins.compose)
alias(libs.plugins.bytebuddy)
`maven-publish`
}

Expand All @@ -18,10 +22,31 @@ repositories {
google()
}

allprojects {
apply<MavenPublishPlugin>()
apply<BasePlugin>()

this.group = "dev.silenium.compose.gl"
this.version = findProperty("deploy.version") as String? ?: "0.0.0-SNAPSHOT"

publishing {
repositories {
val url = System.getenv("MAVEN_REPO_URL") ?: return@repositories
maven(url) {
name = "reposilite"
credentials {
username = System.getenv("MAVEN_REPO_USERNAME") ?: ""
password = System.getenv("MAVEN_REPO_PASSWORD") ?: ""
}
}
}
}
}

val deployNative = (findProperty("deploy.native") as String?)?.toBoolean() ?: true
val deployKotlin = (findProperty("deploy.kotlin") as String?)?.toBoolean() ?: true

val lwjglNatives = "natives-linux"
val lwjglNatives = arrayOf("natives-linux", "natives-windows")

dependencies {
implementation(compose.desktop.common)
Expand All @@ -36,33 +61,24 @@ dependencies {
api(libs.lwjgl.egl)
libs.bundles.lwjgl.natives.get().forEach {
api(it)
runtimeOnly(variantOf(provider { it }) { classifier(lwjglNatives) })
lwjglNatives.forEach { native ->
runtimeOnly(variantOf(provider { it }) { classifier(native) })
}
}

implementation(libs.bundles.kotlinx.coroutines)
// api(libs.bundles.skiko) {
// version {
// strictly(libs.skiko.awt.runtime.linux.x64.get().version!!)
// }
// }
implementation("net.java.dev.jna:jna")
api(libs.bundles.skiko) {
version {
strictly(libs.versions.skiko.get())
}
}

testImplementation(compose.desktop.currentOs)
testImplementation(libs.logback.classic)
testImplementation("me.saket.telephoto:zoomable:0.14.0")
}

compose.desktop {
application {
mainClass = "MainKt"

nativeDistributions {
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
packageName = "compose-gl"
packageVersion = "1.0.0"
}
}
}

java {
withSourcesJar()
sourceCompatibility = JavaVersion.VERSION_11
Expand All @@ -77,23 +93,31 @@ kotlin {
}
}

allprojects {
apply<MavenPublishPlugin>()
apply<BasePlugin>()
val skiaVersion = configurations.compileClasspath.map {
it.filter { it.name.matches(Regex("skiko-awt-\\d.+.jar")) }.singleFile
}.get().let {
val loader = URLClassLoader(arrayOf(it.toURI().toURL()))
val clazz = loader.loadClass("org.jetbrains.skiko.Version").kotlin
val getSkikoVersion = clazz.functions.single { it.name == "getSkiko" }
val getSkiaVersion = clazz.functions.single { it.name == "getSkia" }
val constructor = clazz.constructors.single()
constructor.isAccessible = true
val instance = constructor.call()
val skikoVersion = getSkikoVersion.call(instance)
val skiaVersion = getSkiaVersion.call(instance)
println("skiko version: $skikoVersion")
println("skia version: $skiaVersion")
rootProject.ext.set("skia.version", skiaVersion)
}

group = "dev.silenium.compose.gl"
version = findProperty("deploy.version") as String? ?: "0.0.0-SNAPSHOT"
compose.desktop {
application {
mainClass = "MainKt"

publishing {
repositories {
val url = System.getenv("MAVEN_REPO_URL") ?: return@repositories
maven(url) {
name = "reposilite"
credentials {
username = System.getenv("MAVEN_REPO_USERNAME") ?: ""
password = System.getenv("MAVEN_REPO_PASSWORD") ?: ""
}
}
nativeDistributions {
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
packageName = "compose-gl"
packageVersion = "1.0.0"
}
}
}
Expand Down
1 change: 1 addition & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ logback-classic = { group = "ch.qos.logback", name = "logback-classic", version
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
compose = { id = "org.jetbrains.compose", version.ref = "compose" }
bytebuddy = { id = "net.bytebuddy.byte-buddy-gradle-plugin", version = "1.17.7" }

[bundles]
kotlinx-coroutines = [
Expand Down
1 change: 1 addition & 0 deletions native/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.idea/
*.iml
cmake-build-*/
third_party/
23 changes: 17 additions & 6 deletions native/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@ cmake_minimum_required(VERSION 3.16)
if (NOT DEFINED PROJECT_NAME)
set(PROJECT_NAME "compose-gl")
endif ()

if (NOT DEFINED JAVA_HOME)
if (DEFINED ENV{JAVA_HOME})
set(JAVA_HOME "$ENV{JAVA_HOME}")
endif ()
endif ()

if (NOT DEFINED JAVA_HOME)
message(FATAL_ERROR "JAVA_HOME must be defined")
else ()
Expand All @@ -10,12 +17,12 @@ endif ()

project(${PROJECT_NAME} LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)

set(SOURCES

src/cpp/library.cpp
)

if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
Expand All @@ -24,9 +31,11 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
endif ()

list(APPEND SOURCES
src/cpp/linux/GLXContext.cpp
)
elseif (CMAKE_SYSTEM_NAME STREQUAL "Windows")
list(APPEND SOURCES
src/cpp/windows/D3DInterop.cpp
)
endif ()

add_library(${PROJECT_NAME} SHARED ${SOURCES})
Expand All @@ -38,11 +47,13 @@ target_include_directories(${PROJECT_NAME} PUBLIC "${JAVA_HOME}/include")
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_compile_definitions(${PROJECT_NAME} PRIVATE -D_LINUX)
find_package(PkgConfig REQUIRED)
pkg_check_modules(GL REQUIRED IMPORTED_TARGET gl egl glx)
target_link_libraries(${PROJECT_NAME} PUBLIC PkgConfig::GL)
target_include_directories(${PROJECT_NAME} PUBLIC "${JAVA_HOME}/include/linux")
elseif (CMAKE_SYSTEM_NAME STREQUAL "Windows")
include(cmake/skia.cmake)
target_compile_definitions(${PROJECT_NAME} PRIVATE -D_WINDOWS)
target_link_libraries(${PROJECT_NAME} PUBLIC opengl32 dxgi d3d11 d3dcompiler)
target_compile_definitions(${PROJECT_NAME} PRIVATE SK_DIRECT3D NOMINMAX WIN32_LEAN_AND_MEAN)
target_compile_options(${PROJECT_NAME} PRIVATE /MT)
target_link_libraries(${PROJECT_NAME} PUBLIC opengl32 dxgi d3d12 d3dcompiler)
target_include_directories(${PROJECT_NAME} PUBLIC "${JAVA_HOME}/include/win32")
target_link_libraries(${PROJECT_NAME} PUBLIC Skia)
endif ()
16 changes: 8 additions & 8 deletions native/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,20 @@ val platform = platformString?.let(Platform::invoke) ?: NativePlatform.platform(
val cmakeExe = findProperty("cmake.executable") as? String ?: "cmake"
val generateMakefile = tasks.register<Exec>("generateMakefile") {
workingDir = layout.buildDirectory.dir("cmake").get().asFile.apply { mkdirs() }
val additionalFlags = mutableListOf(
"-DJAVA_HOME=${System.getProperty("java.home")}",
"-DPROJECT_NAME=${libName}",
val additionalFlags = listOfNotNull(
"JAVA_HOME" to System.getProperty("java.home"),
"PROJECT_NAME" to libName,
"CMAKE_BUILD_TYPE" to "Debug",
rootProject.ext.get("skia.version")?.let { "SKIA_VERSION" to it },
)
commandLine(
cmakeExe,
*additionalFlags.toTypedArray(),
*additionalFlags.map { "-D${it.first}=${it.second}" }.toTypedArray(),
layout.projectDirectory.asFile.absolutePath,
)

inputs.file(layout.projectDirectory.file("CMakeLists.txt"))
inputs.properties(
"JAVA_HOME" to System.getProperty("java.home"),
"PROJECT_NAME" to libName,
)
inputs.properties(additionalFlags.toMap())
outputs.dir(workingDir)
standardOutput = System.out
}
Expand Down Expand Up @@ -76,6 +75,7 @@ val jar = tasks.register<Jar>("nativeJar") {
val libName = rootProject.name
val platformString = findProperty("deploy.platform")?.toString()
val platform = platformString?.let(Platform::invoke) ?: NativePlatform.platform()
archiveBaseName.set("$libName-natives-$platform")

from(compileNative.get().outputs.files) {
rename {
Expand Down
111 changes: 111 additions & 0 deletions native/cmake/skia.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
set(SKIA_VERSION "m132-a00c390e98-1" CACHE STRING "Skia version")
set(SKIA_OS "linux")
set(SKIA_ARCH "x64")
set(SKIA_VARIANT "Debug")

if (CMAKE_BUILD_TYPE STREQUAL "Debug")
set(SKIA_VARIANT "Debug")
endif ()

if (CMAKE_BUILD_TYPE STREQUAL "Release")
set(SKIA_VARIANT "Release")
endif ()

if (CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
set(SKIA_VARIANT "Debug")
endif ()

if (CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")
set(SKIA_VARIANT "Release")
endif ()

if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
set(SKIA_OS "windows")
elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(SKIA_OS "linux")
elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
set(SKIA_OS "macos")
endif ()

string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" PROCESSOR)

if (PROCESSOR MATCHES "arm" OR PROCESSOR MATCHES "aarch64")
set(SKIA_ARCH "arm64")
elseif (PROCESSOR MATCHES "x86_64" OR PROCESSOR MATCHES "amd64")
set(SKIA_ARCH "x64")
endif ()

file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/download")

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)
list(GET GH_RELEASE_STATUS 0 GH_RELEASE_STATUS_CODE)
if (GH_RELEASE_STATUS_CODE)
message(FATAL_ERROR "Failed to download GitHub release: ${GH_RELEASE_STATUS_CODE}")
return()
endif ()

file(READ "${CMAKE_BINARY_DIR}/download/skia_assets.json" GH_RELEASE_JSON)

string(JSON ASSETS_COUNT LENGTH ${GH_RELEASE_JSON} "assets")
math(EXPR ASSETS_COUNT "${ASSETS_COUNT} - 1")

foreach (assetIdx RANGE 0 ${ASSETS_COUNT} 1)
string(JSON assetName GET ${GH_RELEASE_JSON} "assets" "${assetIdx}" "name")
if (assetName MATCHES "Skia-${SKIA_VERSION}-${SKIA_OS}-${SKIA_VARIANT}-${SKIA_ARCH}.zip")
message(STATUS "Found asset ${assetIdx} of ${ASSETS_COUNT}: ${assetName}")
set(ASSET_IDX ${assetIdx})
set(ASSET_NAME ${assetName})
string(JSON ASSET_URL GET ${GH_RELEASE_JSON} "assets" "${assetIdx}" "browser_download_url")
string(JSON ASSET_HASH GET ${GH_RELEASE_JSON} "assets" "${assetIdx}" "digest")
break()
endif ()
endforeach ()

message(STATUS "Downloading Skia from ${ASSET_URL} with hash ${ASSET_HASH}")

set(SKIA_URL "${ASSET_URL}")
string(REPLACE ":" "=" ASSET_HASH "${ASSET_HASH}")

if (NOT ASSET_HASH)
message(WARNING "Failed to find Skia hash, just checking for the files existence to determine if we need to download Skia again.")
if (NOT EXISTS "${CMAKE_BINARY_DIR}/download/${ASSET_NAME}")
file(DOWNLOAD ${SKIA_URL} "${CMAKE_BINARY_DIR}/download/${ASSET_NAME}" STATUS SKIA_DOWNLOAD_STATUS SHOW_PROGRESS)
endif ()
else ()
file(DOWNLOAD ${SKIA_URL} "${CMAKE_BINARY_DIR}/download/${ASSET_NAME}" STATUS SKIA_DOWNLOAD_STATUS EXPECTED_HASH "${ASSET_HASH}" SHOW_PROGRESS)
endif ()

list(GET SKIA_DOWNLOAD_STATUS 0 SKIA_DOWNLOAD_STATUS_CODE)
if (SKIA_DOWNLOAD_STATUS_CODE)
message(FATAL_ERROR "Failed to download Skia: ${SKIA_DOWNLOAD_STATUS_CODE}")
return()
endif ()

file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/third_party/skia")
message(STATUS "Unpacking Skia to ${CMAKE_BINARY_DIR}/third_party/skia")
file(REMOVE_RECURSE "${CMAKE_BINARY_DIR}/third_party/skia")
file(ARCHIVE_EXTRACT INPUT "${CMAKE_BINARY_DIR}/download/${ASSET_NAME}" DESTINATION "${CMAKE_BINARY_DIR}/third_party/skia")

add_library(Skia INTERFACE)
target_include_directories(Skia INTERFACE
"${CMAKE_BINARY_DIR}/third_party/skia/include"
"${CMAKE_BINARY_DIR}/third_party/skia/modules/svg/include"
"${CMAKE_BINARY_DIR}/third_party/skia/src"
"${CMAKE_BINARY_DIR}/third_party/skia"
"${CMAKE_BINARY_DIR}/third_party/skia/third_party/externals/angle2/include"
"${CMAKE_BINARY_DIR}/third_party/skia/third_party/externals/freetype/include"
"${CMAKE_BINARY_DIR}/third_party/skia/third_party/externals/harfbuzz/src"
"${CMAKE_BINARY_DIR}/third_party/skia/third_party/externals/icu/source/common"
"${CMAKE_BINARY_DIR}/third_party/skia/third_party/externals/libpng"
"${CMAKE_BINARY_DIR}/third_party/skia/third_party/externals/libwebp/src"
"${CMAKE_BINARY_DIR}/third_party/skia/third_party/externals/swiftshader/include"
"${CMAKE_BINARY_DIR}/third_party/skia/third_party/externals/zlib"
"${CMAKE_BINARY_DIR}/third_party/skia/third_party/icu"
)
target_link_directories(Skia INTERFACE "${CMAKE_BINARY_DIR}/third_party/skia/out/${SKIA_VARIANT}-${SKIA_OS}-${SKIA_ARCH}")
target_link_libraries(Skia INTERFACE
bentleyottmann.lib libwebp.lib skottie.lib skshaper.lib svg.lib
d3d12allocator.lib icu.lib libwebp_sse41.lib skparagraph.lib skunicode_core.lib wuffs.lib
expat.lib libjpeg.lib skcms.lib skresources.lib skunicode_icu.lib zlib.lib
harfbuzz.lib libpng.lib skia.lib sksg.lib spirv_cross.lib
)
1 change: 1 addition & 0 deletions native/src/cpp/library.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// empty
Loading