Unverified Commit 6e963769 authored by Nikita Lipsky's avatar Nikita Lipsky Committed by GitHub

Provide a way to configure Skia's DirectContext GPU Resource Cache size (#1095)

Fixes:
[CMP-8916](https://youtrack.jetbrains.com/issue/CMP-8916/Provide-a-way-to-configure-Skias-DirectContext-GPU-Resource-Cache-size)

The cache can be limited on Desktop platforms by specifying
`-Dskiko.gpu.resourceCacheLimit` VM property (accepts numbers optionally
suffixed with "K", "M" or "G").
parent efcc0529
......@@ -28,7 +28,7 @@ import kotlin.math.floor
actual open class SkiaLayer internal constructor(
externalAccessibleFactory: ((Component) -> Accessible)? = null,
private val properties: SkiaLayerProperties,
val properties: SkiaLayerProperties,
private val renderFactory: RenderFactory = RenderFactory.Default,
private val analytics: SkiaLayerAnalytics = SkiaLayerAnalytics.Empty,
actual val pixelGeometry: PixelGeometry = PixelGeometry.UNKNOWN,
......
......@@ -2,29 +2,15 @@ package org.jetbrains.skiko.context
import org.jetbrains.skia.*
import org.jetbrains.skiko.AngleApi
import org.jetbrains.skiko.Logger
import org.jetbrains.skiko.RenderException
import org.jetbrains.skiko.SkiaLayer
import org.jetbrains.skiko.redrawer.AngleRedrawer
internal class AngleContextHandler(layer: SkiaLayer) : JvmContextHandler(layer) {
internal class AngleContextHandler(layer: SkiaLayer) : ContextBasedContextHandler(layer, "ANGLE") {
private val angleRedrawer: AngleRedrawer
get() = layer.redrawer!! as AngleRedrawer
override fun initContext(): Boolean {
try {
if (context == null) {
context = angleRedrawer.makeContext()
if (System.getProperty("skiko.hardwareInfo.enabled") == "true") {
Logger.info { "Renderer info:\n ${rendererInfo()}" }
}
}
} catch (e: Exception) {
Logger.warn(e) { "Failed to create Skia ANGLE context!" }
return false
}
return true
}
override fun makeContext() = angleRedrawer.makeContext()
private var currentWidth = 0
private var currentHeight = 0
......
package org.jetbrains.skiko.context
import org.jetbrains.skia.DirectContext
import org.jetbrains.skiko.Logger
import org.jetbrains.skiko.SkiaLayer
internal abstract class ContextBasedContextHandler(layer: SkiaLayer, val name: String) : JvmContextHandler(layer) {
abstract protected fun makeContext(): DirectContext
override fun initContext(): Boolean {
try {
if (context == null) {
context = makeContext()
onContextInitialized()
}
} catch (e: Exception) {
Logger.warn(e) { "Failed to create Skia $name context!" }
return false
}
return true
}
}
\ No newline at end of file
package org.jetbrains.skiko.context
import org.jetbrains.skiko.SkiaLayer
internal abstract class ContextFreeContextHandler(layer: SkiaLayer) : JvmContextHandler(layer) {
private var isInited = false
override fun initContext(): Boolean {
if (!isInited) {
isInited = true
onContextInitialized()
}
return isInited
}
}
\ No newline at end of file
package org.jetbrains.skiko.context
import org.jetbrains.skia.DirectContext
import org.jetbrains.skia.Surface
import org.jetbrains.skia.SurfaceProps
import org.jetbrains.skia.impl.getPtr
......@@ -8,7 +9,7 @@ import org.jetbrains.skiko.SkiaLayer
import org.jetbrains.skiko.redrawer.Direct3DRedrawer
import java.lang.ref.Reference
internal class Direct3DContextHandler(layer: SkiaLayer) : JvmContextHandler(layer) {
internal class Direct3DContextHandler(layer: SkiaLayer) : ContextBasedContextHandler(layer, "Direct3D") {
private val bufferCount = 2
private var surfaces: Array<Surface?> = arrayOfNulls(bufferCount)
private fun isSurfacesNull() = surfaces.all { it == null }
......@@ -16,20 +17,7 @@ internal class Direct3DContextHandler(layer: SkiaLayer) : JvmContextHandler(laye
private val directXRedrawer: Direct3DRedrawer
get() = layer.redrawer!! as Direct3DRedrawer
override fun initContext(): Boolean {
try {
if (context == null) {
context = directXRedrawer.makeContext()
if (System.getProperty("skiko.hardwareInfo.enabled") == "true") {
Logger.info { "Renderer info:\n ${rendererInfo()}" }
}
}
} catch (e: Exception) {
Logger.warn(e) { "Failed to create Skia Direct3D context!" }
return false
}
return true
}
override fun makeContext(): DirectContext = directXRedrawer.makeContext()
private var currentWidth = 0
private var currentHeight = 0
......
package org.jetbrains.skiko.context
import org.jetbrains.skia.impl.getPtr
import org.jetbrains.skiko.Logger
import org.jetbrains.skiko.SkiaLayer
import org.jetbrains.skiko.redrawer.AbstractDirectSoftwareRedrawer
import java.lang.ref.Reference
internal class DirectSoftwareContextHandler(layer: SkiaLayer) : JvmContextHandler(layer) {
var isInited = false
internal class DirectSoftwareContextHandler(layer: SkiaLayer) : ContextFreeContextHandler(layer) {
private val softwareRedrawer: AbstractDirectSoftwareRedrawer
get() = layer.redrawer!! as AbstractDirectSoftwareRedrawer
......@@ -23,16 +20,6 @@ internal class DirectSoftwareContextHandler(layer: SkiaLayer) : JvmContextHandle
return false
}
override fun initContext(): Boolean {
if (!isInited) {
if (System.getProperty("skiko.hardwareInfo.enabled") == "true") {
Logger.info { "Renderer info:\n ${rendererInfo()}" }
}
isInited = true
}
return isInited
}
override fun initCanvas() {
val scale = layer.contentScale
val w = (layer.width * scale).toInt().coerceAtLeast(0)
......
package org.jetbrains.skiko.context
import org.jetbrains.skiko.Logger
import org.jetbrains.skiko.SkiaLayer
internal abstract class JvmContextHandler(layer: SkiaLayer) : ContextHandler(layer, layer::draw)
\ No newline at end of file
internal abstract class JvmContextHandler(layer: SkiaLayer) : ContextHandler(layer, layer::draw) {
protected fun onContextInitialized() {
if (System.getProperty("skiko.hardwareInfo.enabled") == "true") {
Logger.info { "Renderer info:\n ${rendererInfo()}" }
}
context?.run {
val gpuResourceCacheLimit = layer.properties.gpuResourceCacheLimit
if (gpuResourceCacheLimit >= 0) {
resourceCacheLimit = gpuResourceCacheLimit
}
}
}
}
......@@ -19,22 +19,7 @@ internal class MetalContextHandler(
layer: SkiaLayer,
private val device: MetalDevice,
private val adapter: MetalAdapter
) : JvmContextHandler(layer) {
override fun initContext(): Boolean {
try {
if (context == null) {
context = makeContext()
if (System.getProperty("skiko.hardwareInfo.enabled") == "true") {
Logger.info { "Renderer info:\n ${rendererInfo()}" }
}
}
} catch (e: Exception) {
Logger.warn(e) { "Failed to create Skia Metal context!" }
return false
}
return true
}
) : ContextBasedContextHandler(layer, "Metal") {
override fun initCanvas() {
disposeCanvas()
......@@ -79,7 +64,7 @@ internal class MetalContextHandler(
makeMetalRenderTarget(device.ptr, width, height)
)
private fun makeContext() = DirectContext(
override fun makeContext() = DirectContext(
makeMetalContext(device.ptr)
)
......
......@@ -3,21 +3,9 @@ package org.jetbrains.skiko.context
import org.jetbrains.skia.*
import org.jetbrains.skiko.*
internal class OpenGLContextHandler(layer: SkiaLayer) : JvmContextHandler(layer) {
override fun initContext(): Boolean {
try {
if (context == null) {
context = makeGLContext()
if (System.getProperty("skiko.hardwareInfo.enabled") == "true") {
Logger.info { "Renderer info:\n ${rendererInfo()}" }
}
}
} catch (e: Exception) {
Logger.warn(e) { "Failed to create Skia OpenGL context!" }
return false
}
return true
}
internal class OpenGLContextHandler(layer: SkiaLayer) : ContextBasedContextHandler(layer, "OpenGL") {
override fun makeContext() = makeGLContext()
private var currentWidth = 0
private var currentHeight = 0
......
package org.jetbrains.skiko.context
import org.jetbrains.skia.*
import org.jetbrains.skiko.Logger
import org.jetbrains.skiko.OS
import org.jetbrains.skiko.SkiaLayer
import org.jetbrains.skiko.hostOs
......@@ -10,7 +9,7 @@ import java.awt.Transparency
import java.awt.color.ColorSpace
import java.awt.image.*
internal class SoftwareContextHandler(layer: SkiaLayer) : JvmContextHandler(layer) {
internal class SoftwareContextHandler(layer: SkiaLayer) : ContextFreeContextHandler(layer) {
override fun isTransparentBackground(): Boolean {
// TODO: why Software rendering has another transparency logic from the begginning
return hostOs == OS.MacOS && layer.transparency
......@@ -27,18 +26,6 @@ internal class SoftwareContextHandler(layer: SkiaLayer) : JvmContextHandler(laye
var image: BufferedImage? = null
var imageData: ByteArray? = null
var raster: WritableRaster? = null
var isInited = false
override fun initContext(): Boolean {
// Raster does not need context
if (!isInited) {
if (System.getProperty("skiko.hardwareInfo.enabled") == "true") {
Logger.info { "Renderer info:\n ${rendererInfo()}" }
}
isInited = true
}
return isInited
}
override fun initCanvas() {
disposeCanvas()
......
......@@ -45,7 +45,7 @@ internal class Direct3DSwingRedrawer(
private var bytesToDraw = ByteArray(0)
init {
onContextInit()
onContextInit(context)
}
override fun dispose() {
......
......@@ -29,7 +29,7 @@ internal class LinuxOpenGLSwingRedrawer(
private var bytesToDraw = ByteArray(0)
init {
onContextInit()
onContextInit(null)
}
override fun dispose() {
......@@ -65,7 +65,7 @@ internal class LinuxOpenGLSwingRedrawer(
).autoClose()
// TODO: may be it is possible to reuse [makeGLContext]
val directContext = makeGLContext().autoClose()
val directContext = makeGLContext().configureContext().autoClose()
val surface = Surface.makeFromBackendRenderTarget(
directContext,
renderTarget,
......
......@@ -42,7 +42,7 @@ internal class MetalSwingRedrawer(
private var texturePtr: Long = 0
init {
onContextInit()
onContextInit(context)
}
private val painter: SwingPainter = createSwingPainter(swingLayerProperties)
......
......@@ -63,6 +63,8 @@ open class SkiaSwingLayer(
get() = this@SkiaSwingLayer.graphicsConfiguration
override val adapterPriority: GpuPriority
get() = this@SkiaSwingLayer.properties.adapterPriority
override val gpuResourceCacheLimit: Long
get() = this@SkiaSwingLayer.properties.gpuResourceCacheLimit
}
private val redrawerManager = RedrawerManager<SwingRedrawer>(
......
......@@ -33,7 +33,7 @@ internal class SoftwareSwingRedrawer(
private val storage = Bitmap()
init {
onContextInit()
onContextInit(null)
}
override fun dispose() {
......
......@@ -11,6 +11,8 @@ internal interface SwingLayerProperties {
val graphicsConfiguration: GraphicsConfiguration
val adapterPriority: GpuPriority
val gpuResourceCacheLimit: Long
}
internal val SwingLayerProperties.scale: Float get() = graphicsConfiguration.defaultTransform.scaleX.toFloat()
\ No newline at end of file
......@@ -68,15 +68,24 @@ internal abstract class SwingRedrawerBase(
"OS: ${hostOs.id} ${hostArch.id}\n"
}
protected fun onContextInit() {
protected fun onContextInit(context: DirectContext?) {
require(!isDisposed) { "$javaClass is disposed" }
requireNotNull(deviceAnalytics) { "deviceAnalytics is not null. Call onDeviceChosen after choosing the drawing device" }
if (System.getProperty("skiko.hardwareInfo.enabled") == "true") {
Logger.info { "Renderer info:\n ${rendererInfo()}" }
}
context?.configureContext()
deviceAnalytics?.contextInit()
}
protected fun DirectContext.configureContext(
gpuResourceCacheLimit: Long = swingLayerProperties.gpuResourceCacheLimit
): DirectContext = apply {
if (gpuResourceCacheLimit >= 0) {
resourceCacheLimit = gpuResourceCacheLimit
}
}
private inline fun inDrawScope(body: () -> Unit) {
check(SwingUtilities.isEventDispatchThread()) { "Method should be called from AWT event dispatch thread" }
requireNotNull(deviceAnalytics) { "deviceAnalytics is not null. Call onDeviceChosen after choosing the drawing device" }
......
......@@ -127,6 +127,28 @@ class DirectContext internal constructor(ptr: NativePointer) : RefCnt(ptr) {
reachabilityBarrier(this)
}
}
/**
* GPU resource cache limit. If the cache currently exceeds this limit,
* it will be purged (LRU) to keep the cache within the limit.
*/
var resourceCacheLimit: Long
get() {
try {
Stats.onNativeCall()
return DirectContext_nGetResourceCacheLimit(_ptr)
} finally {
reachabilityBarrier(this)
}
}
set(value) {
try {
Stats.onNativeCall()
DirectContext_nSetResourceCacheLimit(_ptr, value)
} finally {
reachabilityBarrier(this)
}
}
}
fun <R> DirectContext.useContext(block: (ctx: DirectContext) -> R): R = use {
......@@ -139,6 +161,12 @@ private external fun DirectContext_nFlush(ptr: NativePointer, surfacePtr: Native
@ExternalSymbolName("org_jetbrains_skia_DirectContext__1nFlushDefault")
private external fun DirectContext_nFlushDefault(ptr: NativePointer)
@ExternalSymbolName("org_jetbrains_skia_DirectContext__1nGetResourceCacheLimit")
private external fun DirectContext_nGetResourceCacheLimit(ptr: NativePointer): Long
@ExternalSymbolName("org_jetbrains_skia_DirectContext__1nSetResourceCacheLimit")
private external fun DirectContext_nSetResourceCacheLimit(ptr: NativePointer, maxResourceBytes: Long)
@ExternalSymbolName("org_jetbrains_skia_DirectContext__1nMakeGL")
private external fun _nMakeGL(): NativePointer
......
package org.jetbrains.skia
import org.jetbrains.skiko.tests.TestGlContext
import kotlin.test.Test
import kotlin.test.assertEquals
class DirectContextNativeTest {
@Test
fun resourceCacheLimitTest() {
if (!TestGlContext.isAvailabale()) return
TestGlContext.run {
DirectContext.makeGL().useContext { context ->
context.resourceCacheLimit = 1024
assertEquals(1024, context.resourceCacheLimit)
}
}
}
}
\ No newline at end of file
......@@ -2,12 +2,6 @@ package org.jetbrains.skia
import org.jetbrains.skia.impl.interopScope
import org.jetbrains.skia.impl.use
import org.jetbrains.skiko.Arch
import org.jetbrains.skiko.KotlinBackend
import org.jetbrains.skiko.OS
import org.jetbrains.skiko.hostArch
import org.jetbrains.skiko.hostOs
import org.jetbrains.skiko.kotlinBackend
import org.jetbrains.skiko.tests.TestGlContext
import org.jetbrains.skiko.tests.allocateBytesForPixels
import org.jetbrains.skiko.tests.runTest
......@@ -111,14 +105,7 @@ class SurfaceTest {
@Test
fun canMakeRenderTarget() {
if (hostOs != OS.Linux || kotlinBackend != KotlinBackend.Native) {
// TODO implement for other platforms and render targets
return
}
if (hostArch == Arch.Arm64) {
// TODO implement and test EGL on arm64
return
}
if (!TestGlContext.isAvailabale()) return
val pixels = TestGlContext.run {
DirectContext.makeGL().useContext { ctx ->
......
......@@ -2,6 +2,12 @@ package org.jetbrains.skiko.tests
import org.jetbrains.skia.*
import org.jetbrains.skia.impl.*
import org.jetbrains.skiko.Arch
import org.jetbrains.skiko.KotlinBackend
import org.jetbrains.skiko.OS
import org.jetbrains.skiko.hostArch
import org.jetbrains.skiko.hostOs
import org.jetbrains.skiko.kotlinBackend
internal class TestGlContext : Managed(TestGlContext_nCreate(), FinalizerHolder.PTR) {
private object FinalizerHolder {
......@@ -17,7 +23,21 @@ internal class TestGlContext : Managed(TestGlContext_nCreate(), FinalizerHolder.
}
companion object {
fun isAvailabale(): Boolean {
if (hostOs != OS.Linux || kotlinBackend != KotlinBackend.Native) {
// TODO implement for other platforms and render targets
return false
}
if (hostArch == Arch.Arm64) {
// TODO implement and test EGL on arm64
return false
}
return true
}
inline fun <T> run(block: TestGlContext.() -> T): T {
check(isAvailabale()) { "TestGlContext is not available" }
return TestGlContext().use {
it.makeCurrent()
val result = it.block()
......
......@@ -62,6 +62,18 @@ extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_DirectContextKt_Direct
context->flush(skSurface);
}
extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skia_DirectContextKt_DirectContext_1nGetResourceCacheLimit
(JNIEnv* env, jclass jclass, jlong ptr) {
GrDirectContext* context = reinterpret_cast<GrDirectContext*>(static_cast<uintptr_t>(ptr));
return (jlong) context->getResourceCacheLimit();
}
extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_DirectContextKt_DirectContext_1nSetResourceCacheLimit
(JNIEnv* env, jclass jclass, jlong ptr, jlong maxResourceBytes) {
GrDirectContext* context = reinterpret_cast<GrDirectContext*>(static_cast<uintptr_t>(ptr));
context->setResourceCacheLimit((size_t) maxResourceBytes);
}
GrSyncCpu grSyncCpuFromBool(bool syncCpu) {
if (syncCpu) return GrSyncCpu::kYes;
return GrSyncCpu::kNo;
......
......@@ -21,6 +21,7 @@ class SkiaLayerProperties(
val frameBuffering: FrameBuffering = SkikoProperties.frameBuffering,
val renderApi: GraphicsApi = SkikoProperties.renderApi,
val adapterPriority: GpuPriority = SkikoProperties.gpuPriority,
val gpuResourceCacheLimit: Long = SkikoProperties.gpuResourceCacheLimit
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
......
......@@ -87,6 +87,22 @@ object SkikoProperties {
val macOsOpenGLEnabled: Boolean get() = getProperty("skiko.macos.opengl.enabled")?.toBoolean() ?: false
val gpuResourceCacheLimit: Long get() = parseSize(getProperty("skiko.gpu.resourceCacheLimit"))
private fun parseSize(size: String?): Long {
if (size == null) return -1L
val size = size.uppercase()
val multiplier = when {
size.endsWith("K") -> 1024L
size.endsWith("M") -> 1024L * 1024L
size.endsWith("G") -> 1024L * 1024L * 1024L
else -> 1L
}
val numericPart = if (multiplier != 1L) size.substring(0, size.length - 1) else size
return numericPart.toLongOrNull()?.times(multiplier)
?: throw IllegalArgumentException("Invalid size format: $size")
}
private val properties = run {
val resourcePropertiesEnabled = System.getProperty("skiko.resource.properties.enabled")?.toBoolean() ?: false
val resources = if (resourcePropertiesEnabled) {
......@@ -101,33 +117,37 @@ object SkikoProperties {
private fun getProperty(key: String): String? = properties.getProperty(key)
internal fun parseRenderApi(text: String?): GraphicsApi {
when(text) {
when (text) {
"SOFTWARE_COMPAT" -> return GraphicsApi.SOFTWARE_COMPAT
"SOFTWARE_FAST", "DIRECT_SOFTWARE" -> return GraphicsApi.SOFTWARE_FAST
"SOFTWARE" -> return if (hostOs == OS.MacOS) GraphicsApi.SOFTWARE_COMPAT else GraphicsApi.SOFTWARE_FAST
"OPENGL" -> {
// Skia isn't properly tested on OpenGL and Windows ARM (https://groups.google.com/g/skia-discuss/c/McoclAhLpvg?pli=1)
return if (hostOs != OS.Windows || hostArch != Arch.Arm64) GraphicsApi.OPENGL
else throw Exception("$hostOs-$hostArch does not support OpenGL rendering API.")
else throw Exception("$hostOs-$hostArch does not support OpenGL rendering API.")
}
"ANGLE" -> {
return if (hostOs == OS.Windows) GraphicsApi.ANGLE
else throw Exception("$hostOs does not support ANGLE rendering API.")
else throw Exception("$hostOs does not support ANGLE rendering API.")
}
"DIRECT3D" -> {
return if (hostOs == OS.Windows) GraphicsApi.DIRECT3D
else throw Exception("$hostOs does not support DirectX rendering API.")
else throw Exception("$hostOs does not support DirectX rendering API.")
}
"METAL" -> {
return if (hostOs == OS.MacOS) GraphicsApi.METAL
else throw Exception("$hostOs does not support Metal rendering API.")
else throw Exception("$hostOs does not support Metal rendering API.")
}
else -> return bestRenderApiForCurrentOS()
}
}
private fun bestRenderApiForCurrentOS(): GraphicsApi {
return when(hostOs) {
return when (hostOs) {
OS.MacOS -> GraphicsApi.METAL
OS.Linux -> GraphicsApi.OPENGL
OS.Windows -> if (renderingAngleEnabled) GraphicsApi.ANGLE else GraphicsApi.DIRECT3D
......@@ -136,15 +156,28 @@ object SkikoProperties {
}
}
internal fun fallbackRenderApiQueue(initialApi: GraphicsApi) : List<GraphicsApi> {
internal fun fallbackRenderApiQueue(initialApi: GraphicsApi): List<GraphicsApi> {
var fallbackApis = when (hostOs) {
OS.Linux -> listOf(GraphicsApi.OPENGL, GraphicsApi.SOFTWARE_FAST, GraphicsApi.SOFTWARE_COMPAT)
OS.MacOS -> listOf(GraphicsApi.METAL, GraphicsApi.SOFTWARE_COMPAT)
OS.Windows -> when (hostArch) {
// Skia isn't properly tested on OpenGL and Windows ARM (https://groups.google.com/g/skia-discuss/c/McoclAhLpvg?pli=1)
Arch.Arm64 -> listOf(GraphicsApi.ANGLE, GraphicsApi.DIRECT3D, GraphicsApi.SOFTWARE_FAST, GraphicsApi.SOFTWARE_COMPAT)
else -> listOf(GraphicsApi.ANGLE, GraphicsApi.DIRECT3D, GraphicsApi.OPENGL, GraphicsApi.SOFTWARE_FAST, GraphicsApi.SOFTWARE_COMPAT)
Arch.Arm64 -> listOf(
GraphicsApi.ANGLE,
GraphicsApi.DIRECT3D,
GraphicsApi.SOFTWARE_FAST,
GraphicsApi.SOFTWARE_COMPAT
)
else -> listOf(
GraphicsApi.ANGLE,
GraphicsApi.DIRECT3D,
GraphicsApi.OPENGL,
GraphicsApi.SOFTWARE_FAST,
GraphicsApi.SOFTWARE_COMPAT
)
}
OS.Android -> return listOf(GraphicsApi.OPENGL)
else -> return listOf(GraphicsApi.UNKNOWN)
}
......
......@@ -3,7 +3,9 @@ package org.jetbrains.skia
import org.jetbrains.skia.impl.Native.Companion.NullPointer
import org.jetbrains.skia.impl.NativePointer
import org.jetbrains.skia.impl.interopScope
import org.jetbrains.skiko.Library
import kotlin.test.Test
import kotlin.test.assertEquals
fun getMakeGLAssembledInterfaceFunc(): NativePointer {
return interopScope {
......@@ -12,11 +14,29 @@ fun getMakeGLAssembledInterfaceFunc(): NativePointer {
}
class DirectContextTest {
@Test
fun makeFromInterfaceTest() {
private companion object {
init {
Library.load()
}
}
private fun makeFromInterface(): DirectContext {
val fPtr = getMakeGLAssembledInterfaceFunc()
val i = GLAssembledInterface.createFromNativePointers(NullPointer, fPtr)
DirectContext.makeGLWithInterface(i)
return DirectContext.makeGLWithInterface(i)
}
@Test
fun makeFromInterfaceTest() {
makeFromInterface()
}
@Test
fun resourceCacheLimitTest() {
val context = makeFromInterface()
context.resourceCacheLimit = 1024
assertEquals(1024, context.resourceCacheLimit)
}
}
......
......@@ -68,6 +68,18 @@ SKIKO_EXPORT void org_jetbrains_skia_DirectContext__1nFlush
context->flush(skSurface);
}
SKIKO_EXPORT KLong org_jetbrains_skia_DirectContext__1nGetResourceCacheLimit
(KNativePointer ptr) {
GrDirectContext* context = reinterpret_cast<GrDirectContext*>(ptr);
return (KLong) context->getResourceCacheLimit();
}
SKIKO_EXPORT void org_jetbrains_skia_DirectContext__1nSetResourceCacheLimit
(KNativePointer ptr, KLong maxResourceBytes) {
GrDirectContext* context = reinterpret_cast<GrDirectContext*>(ptr);
context->setResourceCacheLimit((size_t) maxResourceBytes);
}
GrSyncCpu grSyncCpuFromBool(bool syncCpu) {
if (syncCpu) return GrSyncCpu::kYes;
return GrSyncCpu::kNo;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment