Skip to content

Commit

Permalink
add rendering API option to switch between hardware acceleration or s…
Browse files Browse the repository at this point in the history
…oftware rendering
  • Loading branch information
sunny-chung committed Nov 16, 2024
1 parent af8282a commit 2d27204
Show file tree
Hide file tree
Showing 8 changed files with 106 additions and 22 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
- Certificates in P7B (PKCS#7) format can now be imported
- Private keys in PEM or PKCS#1 formats can now be imported, and does not limit to RSA keys anymore.
- PKCS#12 (known as p12) and PFX files can now be imported as client certificates
- [Experimental] Options to change rendering APIs to work around display issues on some Windows devices. Hardware acceleration can be disabled via this setting.

### Changed
- The main monospace font has been changed to Pitagon Sans Mono and unified among all platforms
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ class AppContext {

lateinit var dataDir: File

lateinit var renderingApi: String

companion object {
var instance = AppContext()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ import com.jayway.jsonpath.spi.mapper.MappingProvider
import com.sunnychung.application.multiplatform.hellohttp.document.OperationalDI
import com.sunnychung.application.multiplatform.hellohttp.document.UserPreferenceDI
import com.sunnychung.application.multiplatform.hellohttp.error.MultipleProcessError
import com.sunnychung.application.multiplatform.hellohttp.model.UserPreference
import com.sunnychung.application.multiplatform.hellohttp.model.Version
import com.sunnychung.application.multiplatform.hellohttp.model.getApplicableRenderingApiList
import com.sunnychung.application.multiplatform.hellohttp.platform.LinuxOS
import com.sunnychung.application.multiplatform.hellohttp.platform.MacOS
import com.sunnychung.application.multiplatform.hellohttp.platform.WindowsOS
Expand All @@ -51,6 +53,8 @@ import kotlin.system.exitProcess

fun main() {
System.setProperty("apple.awt.application.appearance", "system")
// System.setProperty("skiko.renderApi", "OPENGL") // IllegalArgumentException: "MacOS does not support OPENGL rendering API."
// System.setProperty("skiko.renderApi", "SOFTWARE")
val appDir = AppDirsFactory.getInstance().getUserDataDir("Hello HTTP", null, null)
println("appDir = $appDir")
AppContext.dataDir = File(appDir)
Expand Down Expand Up @@ -79,6 +83,7 @@ fun main() {

var dataVersion: Version? = null
var appVersion: Version? = null
var userPreference: UserPreference? = null

coroutineScope {
withContext(Dispatchers.IO) {
Expand All @@ -88,6 +93,8 @@ fun main() {
dataVersion =
AppContext.OperationalRepository.read(OperationalDI())!!.data.appVersion.let { Version(it) }
appVersion = AppContext.MetadataManager.version.let { Version(it) }

userPreference = AppContext.UserPreferenceRepository.read(UserPreferenceDI())!!.preference
}

launch {
Expand All @@ -96,6 +103,12 @@ fun main() {
}
}

val applicableRenderingApis = getApplicableRenderingApiList(currentOS()).toSet()
userPreference!!.preferredRenderingApi_Experimental?.takeIf { it in applicableRenderingApis }?.value?.let {
System.setProperty("skiko.renderApi", it)
println("Set skiko.renderApi = $it")
}

val prepareCounter = AtomicInteger(0)

application {
Expand Down Expand Up @@ -150,6 +163,8 @@ fun main() {
icon = painterResource("image/appicon.svg"),
state = rememberWindowState(width = 1024.dp, height = 560.dp)
) {
AppContext.instance.renderingApi = this.window.renderApi.name

with(LocalDensity.current) {
window.minimumSize = if (isMacOs()) {
Dimension(800, 450)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.sunnychung.application.multiplatform.hellohttp.model

import com.sunnychung.application.multiplatform.hellohttp.platform.LinuxOS
import com.sunnychung.application.multiplatform.hellohttp.platform.MacOS
import com.sunnychung.application.multiplatform.hellohttp.platform.OS
import com.sunnychung.application.multiplatform.hellohttp.platform.WindowsOS

enum class RenderingApi(val value: String?) {
Default(null), OpenGL("OPENGL"), Software("SOFTWARE")
}

fun getApplicableRenderingApiList(os: OS): List<RenderingApi> {
return when (os) {
MacOS -> RenderingApi.values().filter { it != RenderingApi.OpenGL }
LinuxOS -> RenderingApi.values().filter { it != RenderingApi.OpenGL }
WindowsOS -> RenderingApi.values().toList()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ val DEFAULT_BACKUP_RETENTION_DAYS = 15
data class UserPreference(
var colourTheme: ColourTheme,
var backupRetentionDays: Int? = null,
var preferredRenderingApi_Experimental: RenderingApi? = null,
)

enum class ColourTheme {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,14 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.TextUnit
import com.sunnychung.application.multiplatform.hellohttp.util.annotatedString
import com.sunnychung.application.multiplatform.hellohttp.util.log
import com.sunnychung.application.multiplatform.hellohttp.ux.local.LocalColor
import com.sunnychung.application.multiplatform.hellohttp.ux.local.LocalFont

@Composable
fun AppText(
text: String,
text: CharSequence,
modifier: Modifier = Modifier,
isDisableWordWrap: Boolean = false,
color: Color = LocalColor.current.text,
Expand Down Expand Up @@ -57,13 +58,13 @@ fun AppText(
var isHover by remember { mutableStateOf(false) }

val textToUse = if (isDisableWordWrap) {
text.replace(' ', '\u00A0') // disable breaking by words
text.replace(" ".toRegex(), "\u00A0") // disable breaking by words
} else {
text
}

Text(
text = textToUse,
text = textToUse.annotatedString(),
modifier = modifier
.run {
@OptIn(ExperimentalComposeUiApi::class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
Expand All @@ -25,6 +26,9 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.dp
import com.darkrockstudios.libraries.mpfilepicker.DirectoryPicker
import com.sunnychung.application.multiplatform.hellohttp.AppContext
Expand All @@ -40,6 +44,9 @@ import com.sunnychung.application.multiplatform.hellohttp.importer.PostmanV2Json
import com.sunnychung.application.multiplatform.hellohttp.importer.PostmanV2ZipImporter
import com.sunnychung.application.multiplatform.hellohttp.model.ColourTheme
import com.sunnychung.application.multiplatform.hellohttp.model.DEFAULT_BACKUP_RETENTION_DAYS
import com.sunnychung.application.multiplatform.hellohttp.model.RenderingApi
import com.sunnychung.application.multiplatform.hellohttp.model.getApplicableRenderingApiList
import com.sunnychung.application.multiplatform.hellohttp.platform.currentOS
import com.sunnychung.application.multiplatform.hellohttp.util.log
import com.sunnychung.application.multiplatform.hellohttp.ux.local.LocalColor
import com.sunnychung.application.multiplatform.hellohttp.ux.viewmodel.rememberFileDialogState
Expand Down Expand Up @@ -80,7 +87,7 @@ private enum class SettingTab {
private val COLUMN_HEADER_WIDTH = 140.dp

@Composable
private fun Section(title: String, content: @Composable ColumnScope.() -> Unit) {
private fun Section(title: CharSequence, content: @Composable ColumnScope.() -> Unit) {
val colors = LocalColor.current
Column(modifier = Modifier.padding(bottom = 12.dp)) {
Row(verticalAlignment = Alignment.CenterVertically) {
Expand Down Expand Up @@ -336,26 +343,63 @@ private fun DataTab(modifier: Modifier = Modifier, closeDialog: () -> Unit) {
fun AppearanceTab() {
val currentColourTheme by AppContext.UserPreferenceViewModel.colourTheme.collectAsState()

val userPreferenceRepository = AppContext.UserPreferenceRepository
userPreferenceRepository.subscribeUpdates().collectAsState(null).value
val userPreference = runBlocking { // TODO don't use runBlocking
userPreferenceRepository.read(UserPreferenceDI())!!.preference
}

Column {
Row(verticalAlignment = Alignment.CenterVertically) {
AppText(text = "Colour Theme", modifier = Modifier.width(COLUMN_HEADER_WIDTH))
DropDownView(
selectedItem = DropDownValue(currentColourTheme.name),
items = ColourTheme.values().map { DropDownValue(it.name) },
onClickItem = {
val newColourTheme = ColourTheme.valueOf(it.displayText)
AppContext.UserPreferenceViewModel.setColorTheme(newColourTheme)

runBlocking {
val userPreferenceRepository = AppContext.UserPreferenceRepository
val userPreference = userPreferenceRepository.read(UserPreferenceDI())!!.preference
userPreference.colourTheme = newColourTheme
userPreferenceRepository.notifyUpdated(UserPreferenceDI())
}
Section("Theme") {
Row(verticalAlignment = Alignment.CenterVertically) {
AppText(text = "Colour Theme", modifier = Modifier.width(COLUMN_HEADER_WIDTH))
DropDownView(
selectedItem = DropDownValue(currentColourTheme.name),
items = ColourTheme.values().map { DropDownValue(it.name) },
onClickItem = {
val newColourTheme = ColourTheme.valueOf(it.displayText)
AppContext.UserPreferenceViewModel.setColorTheme(newColourTheme)

true
},
)
runBlocking {
val userPreferenceRepository = AppContext.UserPreferenceRepository
val userPreference = userPreferenceRepository.read(UserPreferenceDI())!!.preference
userPreference.colourTheme = newColourTheme
userPreferenceRepository.notifyUpdated(UserPreferenceDI())
}

true
},
)
}
}

Spacer(modifier = Modifier.height(12.dp))

Section(buildAnnotatedString {
append("Experimental ")
withStyle(SpanStyle(color = LocalColor.current.warning)) {
append("(Warning: Changing may cause something VERY BAD!)")
}
}) {
Column {
Row(verticalAlignment = Alignment.CenterVertically) {
AppText(text = "Preferred Rendering (Requires restarting the app to change) (Current: ${AppContext.instance.renderingApi})", modifier = Modifier.width(COLUMN_HEADER_WIDTH))
DropDownView(
selectedItem = run {
val item = userPreference.preferredRenderingApi_Experimental ?: RenderingApi.Default
DropDownKeyValue(item, item.name)
},
items = getApplicableRenderingApiList(currentOS()).map {
DropDownKeyValue(it, it.name)
},
onClickItem = {
userPreference.preferredRenderingApi_Experimental = it.key.takeIf { it != RenderingApi.Default }
userPreferenceRepository.notifyUpdated(UserPreferenceDI())
true
},
)
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import com.sunnychung.application.multiplatform.hellohttp.util.JvmLogger
import com.sunnychung.application.multiplatform.hellohttp.ux.bigtext.BigTextImpl
import com.sunnychung.lib.multiplatform.kdatetime.KDuration
import com.sunnychung.lib.multiplatform.kdatetime.KInstant
import org.junit.jupiter.api.Disabled
import kotlin.random.Random
import kotlin.test.Test

Expand All @@ -16,6 +17,7 @@ private val log = Logger(object : MutableLoggerConfig {
override var minSeverity: Severity = Severity.Info
}, tag = "BigTextImplBenchmarkTest")

@Disabled
class BigTextImplBenchmarkTest {

private fun chunkSizes() = listOf(64, 1024, 64 * 1024, 256 * 1024, 1024 * 1024, 2 * 1024 * 1024, 4 * 1024 * 1024)
Expand Down

0 comments on commit 2d27204

Please sign in to comment.