Unverified Commit 82445626 authored by Manuel Unterhofer's avatar Manuel Unterhofer Committed by GitHub

Fix passing of PixelGeometry to JNI on Windows 11 (#656)

... and make software renderers respect the pixel geometry

We accidentally didn't prepare the SurfaceProps into an IntArray when passing them down into the JNI in the Windows version. The memory layout must have accidentally matched between both representations on Windows 10, but it doesn't work on Windows 11 for some reason. This is the proper fix.
parent 5766e0b3
package SkiaAwtSample
import kotlinx.coroutines.*
import org.jetbrains.skia.PixelGeometry
import org.jetbrains.skiko.*
import java.awt.Color
import java.awt.Dimension
import java.awt.Toolkit
import java.awt.event.*
import java.awt.RenderingHints
import javax.swing.*
import java.io.File
import java.nio.file.Files
......@@ -22,7 +24,15 @@ fun main(args: Array<String>) {
}
fun createWindow(title: String, exitOnClose: Boolean) = SwingUtilities.invokeLater {
val skiaLayer = SkiaLayer()
val renderingHints = Toolkit.getDefaultToolkit().getDesktopProperty("awt.font.desktophints") as Map<Any, Any>
val pixelGeometry = when (renderingHints[RenderingHints.KEY_TEXT_ANTIALIASING]) {
RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB -> PixelGeometry.RGB_H
RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HBGR -> PixelGeometry.BGR_H
RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VRGB -> PixelGeometry.RGB_V
RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VBGR -> PixelGeometry.BGR_V
else -> PixelGeometry.UNKNOWN
}
val skiaLayer = SkiaLayer(pixelGeometry = pixelGeometry)
val clocks = ClocksAwt(skiaLayer)
val window = JFrame(title)
......
......@@ -2,17 +2,17 @@ package SkiaAwtSample
import org.jetbrains.skiko.*
import org.jetbrains.skia.*
import org.jetbrains.skia.paragraph.FontCollection
import org.jetbrains.skia.paragraph.ParagraphBuilder
import org.jetbrains.skia.paragraph.ParagraphStyle
import org.jetbrains.skia.paragraph.TextStyle
import org.jetbrains.skia.paragraph.*
import kotlin.math.cos
import kotlin.math.sin
import kotlin.math.PI
class ClocksAwt(private val layer: SkiaLayer): SkikoView {
class ClocksAwt(private val layer: SkiaLayer) : SkikoView {
private val typeface = Typeface.makeFromFile("fonts/JetBrainsMono-Regular.ttf")
private val font = Font(typeface, 40f)
private val font = Font(typeface, 13f).apply {
edging = FontEdging.SUBPIXEL_ANTI_ALIAS
hinting = FontHinting.SLIGHT
}
private val paint = Paint().apply {
color = 0xff9BC730L.toInt()
mode = PaintMode.FILL
......@@ -75,16 +75,20 @@ class ClocksAwt(private val layer: SkiaLayer): SkikoView {
}
val text = "Frames: ${frame++}!"
canvas.drawString(text, xpos.toFloat(), ypos.toFloat(), font, paint)
val x = xpos.toFloat()
val y = ypos.toFloat()
canvas.drawString(text, x, y, font, paint)
val style = ParagraphStyle()
val renderInfo = ParagraphBuilder(style, fontCollection)
val style = ParagraphStyle().apply {
fontRastrSettings = FontRastrSettings(FontEdging.SUBPIXEL_ANTI_ALIAS, FontHinting.SLIGHT, true)
}
val paragraph = ParagraphBuilder(style, fontCollection)
.pushStyle(TextStyle().setColor(0xFF000000.toInt()))
.addText("Graphics API: ${layer.renderApi} ✿゚ $currentSystemTheme")
.popStyle()
.build()
renderInfo.layout(Float.POSITIVE_INFINITY)
renderInfo.paint(canvas, 5f, 5f)
paragraph.layout(Float.POSITIVE_INFINITY)
paragraph.paint(canvas, 5f, 5f)
// Alpha layers test
val rectW = 100f
......
......@@ -7,12 +7,14 @@
#include "SkColorSpace.h"
#include "SkSurface.h"
#include "src/core/SkAutoMalloc.h"
#include "../common/interop.hh"
class SoftwareDevice
{
public:
HWND window;
RECT clientRect;
std::unique_ptr<SkSurfaceProps> surfaceProps;
SkAutoMalloc surfaceMemory;
sk_sp<SkSurface> surface;
......@@ -22,10 +24,11 @@ public:
extern "C"
{
JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_WindowsSoftwareRedrawer_createDevice(
JNIEnv *env, jobject redrawer, jlong contentHandle, jboolean transparency)
JNIEnv *env, jobject redrawer, jlong contentHandle, jintArray surfacePropsInts, jboolean transparency)
{
SoftwareDevice *device = new SoftwareDevice();
device->window = (HWND)contentHandle;
device->surfaceProps = skija::SurfaceProps::toSkSurfaceProps(env, surfacePropsInts);
if (transparency)
{
HWND parent = GetAncestor(device->window, GA_PARENT);
......@@ -56,7 +59,7 @@ extern "C"
SkImageInfo info = SkImageInfo::Make(
width, height, kBGRA_8888_SkColorType, kPremul_SkAlphaType,
SkColorSpace::MakeSRGB());
device->surface = SkSurface::MakeRasterDirect(info, pixels, sizeof(uint32_t) * width);
device->surface = SkSurface::MakeRasterDirect(info, pixels, sizeof(uint32_t) * width, device->surfaceProps.get());
GetClientRect(device->window, &device->clientRect);
}
__except(EXCEPTION_EXECUTE_HANDLER) {
......
......@@ -4,6 +4,7 @@ import org.jetbrains.skia.Bitmap
import org.jetbrains.skia.Canvas
import org.jetbrains.skia.ColorAlphaType
import org.jetbrains.skia.ImageInfo
import org.jetbrains.skia.SurfaceProps
import org.jetbrains.skiko.SkiaLayer
import org.jetbrains.skiko.hostOs
import org.jetbrains.skiko.OS
......@@ -55,7 +56,7 @@ internal class SoftwareContextHandler(layer: SkiaLayer) : JvmContextHandler(laye
storage.allocPixelsFlags(ImageInfo.makeS32(w, h, ColorAlphaType.PREMUL), false)
}
canvas = Canvas(storage)
canvas = Canvas(storage, SurfaceProps(pixelGeometry = layer.pixelGeometry))
}
override fun flush() {
......
......@@ -5,6 +5,8 @@ import kotlinx.coroutines.withContext
import org.jetbrains.skia.DirectContext
import org.jetbrains.skia.Surface
import org.jetbrains.skia.SurfaceProps
import org.jetbrains.skia.impl.interopScope
import org.jetbrains.skia.impl.InteropPointer
import org.jetbrains.skiko.*
import org.jetbrains.skiko.context.Direct3DContextHandler
......@@ -86,9 +88,11 @@ internal class Direct3DRedrawer(
makeDirectXContext(device)
)
fun makeSurface(context: Long, width: Int, height: Int, surfaceProps: SurfaceProps, index: Int) = Surface(
makeDirectXSurface(device, context, width, height, surfaceProps, index)
)
fun makeSurface(context: Long, width: Int, height: Int, surfaceProps: SurfaceProps, index: Int): Surface {
return interopScope {
Surface(makeDirectXSurface(device, context, width, height, toInterop(surfaceProps.packToIntArray()), index))
}
}
fun resizeBuffers(width: Int, height: Int) = resizeBuffers(device, width, height)
......@@ -102,7 +106,7 @@ internal class Direct3DRedrawer(
private external fun chooseAdapter(adapterPriority: Int): Long
private external fun createDirectXDevice(adapter: Long, contentHandle: Long, transparency: Boolean): Long
private external fun makeDirectXContext(device: Long): Long
private external fun makeDirectXSurface(device: Long, context: Long, width: Int, height: Int, surfaceProps: SurfaceProps, index: Int): Long
private external fun makeDirectXSurface(device: Long, context: Long, width: Int, height: Int, surfacePropsIntArray: InteropPointer, index: Int): Long
private external fun resizeBuffers(device: Long, width: Int, height: Int)
private external fun swap(device: Long, isVsyncEnabled: Boolean)
private external fun disposeDevice(device: Long)
......
package org.jetbrains.skiko.redrawer
import org.jetbrains.skia.impl.interopScope
import org.jetbrains.skia.impl.InteropPointer
import org.jetbrains.skia.SurfaceProps
import org.jetbrains.skiko.SkiaLayer
import org.jetbrains.skiko.SkiaLayerProperties
import org.jetbrains.skiko.RenderException
......@@ -13,13 +16,15 @@ internal class WindowsSoftwareRedrawer(
init {
onDeviceChosen("Software")
device = createDevice(layer.contentHandle, layer.transparency).also {
device = interopScope {
createDevice(layer.contentHandle, toInterop(SurfaceProps(pixelGeometry = layer.pixelGeometry).packToIntArray()), layer.transparency).also {
if (it == 0L) {
throw RenderException("Failed to create Software device")
}
}
}
onContextInit()
}
private external fun createDevice(contentHandle: Long, transparency: Boolean): Long
private external fun createDevice(contentHandle: Long, surfacePropsIntArray: InteropPointer, transparency: Boolean): Long
}
\ No newline at end of file
package org.jetbrains.skia
// The order and values must be aligned with SkPixelGeometry from the C++ side
enum class PixelGeometry {
UNKNOWN,
RGB_H,
......
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