Skip to content

Commit ff5a113

Browse files
authored
add BackendTexture and Image.adoptTextureFrom (#1030)
### New: (related #1019) 1. Adds bindings to GrBackendTextures::MakeGL 2. Adds bindings to SkImages::AdoptTextureFrom 3. Adds bindings to GrBackendTextures::GLTextureParametersModdified ### Changes in build scripts: (related #742) 1. Add file paths treating if building on Windows machine 2. Use "emcc.bat" instead of "emcc" if building on Windows machine, as described on Emscripten website ### Use-case: Allows skia to draw images, rendered externally on gpu. Compose would benefit greatly, allowing to embed VideoPlayer or Browser without any friction or need to use Swing.
1 parent 9ec0e8c commit ff5a113

10 files changed

Lines changed: 269 additions & 6 deletions

File tree

‎skiko/buildSrc/src/main/kotlin/internal/utils/ArgBuilder.kt‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package internal.utils
22

3+
import org.apache.tools.ant.taskdefs.condition.Os
34
import org.gradle.api.file.FileSystemLocation
45
import org.gradle.api.provider.Provider
56
import java.io.File
@@ -86,6 +87,15 @@ internal abstract class BaseVisualStudioBuildToolsArgBuilder : AbstractArgBuilde
8687

8788
internal class DefaultArgBuilder() : AbstractArgBuilder() {
8889
override fun newSelfInstance(): ArgBuilder = DefaultArgBuilder()
90+
override fun escapePathIfNeeded(file: File): String {
91+
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
92+
val path = file.absolutePath
93+
.replace("/", "\\")
94+
.replace("\\", "\\\\")
95+
return if (" " in path) "\"$path\"" else path
96+
}
97+
else return super.escapePathIfNeeded(file)
98+
}
8999
}
90100

91101
internal class VisualCppCompilerArgBuilder : BaseVisualStudioBuildToolsArgBuilder() {

‎skiko/buildSrc/src/main/kotlin/properties.kt‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import org.apache.tools.ant.taskdefs.condition.Os
12
import org.gradle.api.GradleException
23
import org.gradle.api.Project
34
import java.io.File
@@ -50,7 +51,7 @@ fun compilerForTarget(os: OS, arch: Arch, isJvm: Boolean = false): String =
5051
OS.Android -> "clang++"
5152
OS.Windows -> "clang-cl.exe"
5253
OS.MacOS, OS.IOS, OS.TVOS -> "clang++"
53-
OS.Wasm -> "emcc"
54+
OS.Wasm -> if (Os.isFamily(Os.FAMILY_WINDOWS)) "emcc.bat" else "emcc"
5455
}
5556

5657
fun linkerForTarget(os: OS, arch: Arch, isJvm: Boolean = false): String =

‎skiko/buildSrc/src/main/kotlin/tasks/configuration/CommonTasksConfiguration.kt‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,10 @@ fun skiaPreprocessorFlags(os: OS, buildType: SkiaBuildType): Array<String> {
9797
"-DSK_BUILD_FOR_LINUX",
9898
"-D_GLIBCXX_USE_CXX11_ABI=0"
9999
)
100-
OS.Wasm -> mutableListOf<String>().apply {
101-
add("-DSKIKO_WASM")
102-
add("-sSUPPORT_LONGJMP=wasm")
103-
}
100+
OS.Wasm -> listOf(
101+
"-DSKIKO_WASM",
102+
"-sSUPPORT_LONGJMP=wasm"
103+
)
104104
OS.Android -> listOf(
105105
"-DSK_BUILD_FOR_ANDROID"
106106
)

‎skiko/src/commonMain/kotlin/org/jetbrains/skia/BackendRenderTarget.kt‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ import org.jetbrains.skiko.loadOpenGLLibrary
99

1010
class BackendRenderTarget internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHolder.PTR) {
1111
companion object {
12+
/**
13+
* Creates BackendRenderTarget from GL framebuffer.
14+
*
15+
* @param stencilBits If wrapping in a Surface we require them to be either 0, 8 or 16.
16+
*
17+
* @throws RenderException if returned nullptr
18+
*/
1219
fun makeGL(
1320
width: Int,
1421
height: Int,
@@ -37,7 +44,7 @@ class BackendRenderTarget internal constructor(ptr: NativePointer) : Managed(ptr
3744
* @param width width of the render target in pixels
3845
* @param height height of the render target in pixels
3946
* @param texturePtr pointer to ID3D12Resource texture resource object; must be not zero
40-
* @param format pixel data DXGI_FORMAT fromat of the texturePtr resource
47+
* @param format pixel data DXGI_FORMAT format of the texturePtr resource
4148
* @param sampleCnt samples count for texture resource
4249
* @param levelCnt sampling quality level for texture resource
4350
*/
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package org.jetbrains.skia
2+
3+
import org.jetbrains.skia.impl.*
4+
import org.jetbrains.skia.impl.Library.Companion.staticLoad
5+
6+
class BackendTexture internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHolder.PTR) {
7+
companion object {
8+
/**
9+
* Creates BackendTexture from GL texture.
10+
*
11+
* @param width - width of the [BackendTexture] to be created
12+
* @param height - height of the [BackendTexture] to be created
13+
* @param isMipmapped - if the passed [textureId] has a GL mipmap, this should be true, otherwise false
14+
* @param textureId - GL id of the texture to use
15+
* @param textureTarget - GL enum, must be valid texture target for 2D, e.g. GL_TEXTURE_2D
16+
* @param textureFormat - GL enum, must be valid color format, e.g. GL_RGBA or GL_BGRA_INTEGER
17+
*
18+
* @see glTextureParametersModified
19+
*/
20+
fun makeGL(
21+
width: Int,
22+
height: Int,
23+
isMipmapped: Boolean,
24+
textureId: Int,
25+
textureTarget: Int,
26+
textureFormat: Int
27+
): BackendTexture {
28+
Stats.onNativeCall()
29+
val ptr = _nMakeGL(
30+
width,
31+
height,
32+
isMipmapped,
33+
textureId,
34+
textureTarget,
35+
textureFormat
36+
)
37+
return BackendTexture(ptr)
38+
}
39+
40+
init {
41+
staticLoad()
42+
}
43+
}
44+
45+
/**
46+
* Call this to indicate to DirectContext that the texture parameters have been modified in the GL context externally
47+
*/
48+
fun glTextureParametersModified() {
49+
return try {
50+
Stats.onNativeCall()
51+
_nGLTextureParametersModified(getPtr(this))
52+
} finally {
53+
reachabilityBarrier(this)
54+
}
55+
}
56+
57+
private object _FinalizerHolder {
58+
val PTR = BackendTexture_nGetFinalizer()
59+
}
60+
}
61+
62+
@ExternalSymbolName("org_jetbrains_skia_BackendTexture__1nGetFinalizer")
63+
@ModuleImport("./skiko.mjs", "org_jetbrains_skia_BackendTexture__1nGetFinalizer")
64+
private external fun BackendTexture_nGetFinalizer(): NativePointer
65+
66+
@ExternalSymbolName("org_jetbrains_skia_BackendTexture__1nMakeGL")
67+
@ModuleImport("./skiko.mjs", "org_jetbrains_skia_BackendTexture__1nMakeGL")
68+
private external fun _nMakeGL(
69+
width: Int,
70+
height: Int,
71+
isMipmapped: Boolean,
72+
textureId: Int,
73+
target: Int,
74+
format: Int
75+
): NativePointer
76+
77+
@ExternalSymbolName("org_jetbrains_skia_BackendTexture__1nGLTextureParametersModified")
78+
@ModuleImport("./skiko.mjs", "org_jetbrains_skia_BackendTexture__1nGLTextureParametersModified")
79+
private external fun _nGLTextureParametersModified(backendTexturePtr: NativePointer)

‎skiko/src/commonMain/kotlin/org/jetbrains/skia/Image.kt‎

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,44 @@ class Image internal constructor(ptr: NativePointer) : RefCnt(ptr), IHasImageInf
138138
return Image(ptr)
139139
}
140140

141+
/**
142+
* Creates GPU-backed SkImage from backendTexture associated with context.
143+
*
144+
* Skia will assume ownership of the resource and will release it when no longer needed.
145+
* A non-null Image is returned if format of backendTexture is recognized and supported.
146+
* Recognized formats vary by GPU backend.
147+
*
148+
* @param context GPU context
149+
* @param backendTexture texture residing on GPU
150+
* @param origin origin of backendTexture
151+
* @param colorType color type of the resulting Image
152+
* @return created Image
153+
*
154+
* @throws RuntimeException - if nullPtr is returned.
155+
*/
156+
fun adoptTextureFrom(
157+
context: DirectContext,
158+
backendTexture: BackendTexture,
159+
origin: SurfaceOrigin,
160+
colorType: ColorType,
161+
): Image {
162+
return try {
163+
Stats.onNativeCall()
164+
val ptr = _nAdoptTextureFrom(
165+
getPtr(context),
166+
getPtr(backendTexture),
167+
origin.ordinal,
168+
colorType.ordinal
169+
)
170+
if (ptr == NullPointer) throw RuntimeException("Failed to Image::makeFromTexture")
171+
Image(ptr)
172+
}
173+
finally {
174+
reachabilityBarrier(context)
175+
reachabilityBarrier(backendTexture)
176+
}
177+
}
178+
141179
init {
142180
staticLoad()
143181
}
@@ -457,3 +495,12 @@ private external fun _nReadPixelsBitmap(
457495
@ExternalSymbolName("org_jetbrains_skia_Image__1nReadPixelsPixmap")
458496
@ModuleImport("./skiko.mjs", "org_jetbrains_skia_Image__1nReadPixelsPixmap")
459497
private external fun _nReadPixelsPixmap(ptr: NativePointer, pixmapPtr: NativePointer, srcX: Int, srcY: Int, cache: Boolean): Boolean
498+
499+
@ExternalSymbolName("org_jetbrains_skia_Image__1nAdoptTextureFrom")
500+
@ModuleImport("./skiko.mjs", "org_jetbrains_skia_Image__1nAdoptTextureFrom")
501+
external fun _nAdoptTextureFrom(
502+
contextPtr: NativePointer,
503+
backendTexture: NativePointer,
504+
surfaceOrigin: Int,
505+
colorType: Int
506+
): NativePointer
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#include <iostream>
2+
#include <jni.h>
3+
#include "ganesh/GrBackendSurface.h"
4+
#include "SkData.h"
5+
#include "SkImage.h"
6+
#include <ganesh/gl/GrGLBackendSurface.h>
7+
#include "ganesh/gl/GrGLBackendSurface.h"
8+
#include "include/gpu/ganesh/SkImageGanesh.h"
9+
#include "ganesh/GrDirectContext.h"
10+
#include "ganesh/gl/GrGLDirectContext.h"
11+
12+
13+
static void deleteBackendTexture(GrBackendTexture* rt) {
14+
// std::cout << "Deleting [GrBackendTexture " << rt << "]" << std::endl;
15+
delete rt;
16+
}
17+
18+
extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skia_BackendTextureKt_BackendTexture_1nGetFinalizer
19+
(JNIEnv* env, jclass jclass) {
20+
return static_cast<jlong>(reinterpret_cast<uintptr_t>(&deleteBackendTexture));
21+
}
22+
23+
extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skia_BackendTextureKt__1nMakeGL
24+
(JNIEnv* env, jclass jclass, jint width, jint height, jboolean isMipmapped, jint textureId, jint target, jint format) {
25+
GrGLTextureInfo textureInfo;
26+
textureInfo.fID = static_cast<GrGLuint>(textureId);
27+
textureInfo.fTarget = static_cast<GrGLenum>(target);
28+
textureInfo.fFormat = static_cast<GrGLenum>(format);
29+
30+
GrBackendTexture obj = GrBackendTextures::MakeGL(
31+
width,
32+
height,
33+
isMipmapped ? skgpu::Mipmapped::kYes : skgpu::Mipmapped::kNo,
34+
textureInfo
35+
);
36+
37+
GrBackendTexture* instance = new GrBackendTexture(obj);
38+
return reinterpret_cast<jlong>(instance);
39+
}
40+
41+
extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_BackendTextureKt__1nGLTextureParametersModified
42+
(JNIEnv* env, jclass jclass, jlong backendTexturePtr) {
43+
GrBackendTexture* backendTexture = reinterpret_cast<GrBackendTexture*>(static_cast<uintptr_t>(backendTexturePtr));
44+
GrBackendTextures::GLTextureParametersModified(backendTexture);
45+
}

‎skiko/src/jvmMain/cpp/common/Image.cc‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22
#include <jni.h>
33
#include "SkData.h"
44
#include "SkImage.h"
5+
#include "ganesh/GrBackendSurface.h"
6+
#include "ganesh/gl/GrGLBackendSurface.h"
7+
#include "include/gpu/ganesh/SkImageGanesh.h"
8+
#include "ganesh/GrDirectContext.h"
9+
#include "ganesh/gl/GrGLDirectContext.h"
510
#include "SkBitmap.h"
611
#include "SkShader.h"
712
#include "SkEncodedImageFormat.h"
@@ -158,3 +163,17 @@ extern "C" JNIEXPORT jboolean JNICALL Java_org_jetbrains_skia_ImageKt__1nScalePi
158163
auto cachingHint = cache ? SkImage::CachingHint::kAllow_CachingHint : SkImage::CachingHint::kDisallow_CachingHint;
159164
return instance->scalePixels(*pixmap, skija::SamplingMode::unpackFrom2Ints(env, samplingOptionsVal1, samplingOptionsVal2), cachingHint);
160165
}
166+
167+
extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skia_ImageKt__1nAdoptTextureFrom
168+
(JNIEnv* env, jclass jclass, jlong contextPtr, jlong backendTexturePtr, jint surfaceOrigin, jint colorType) {
169+
GrBackendTexture* backendTexture = reinterpret_cast<GrBackendTexture*>(static_cast<uintptr_t>(backendTexturePtr));
170+
GrDirectContext* context = reinterpret_cast<GrDirectContext*>(static_cast<uintptr_t>(contextPtr));
171+
172+
sk_sp<SkImage> image = SkImages::AdoptTextureFrom(
173+
static_cast<GrRecordingContext*>(context),
174+
*backendTexture,
175+
static_cast<GrSurfaceOrigin>(surfaceOrigin),
176+
static_cast<SkColorType>(colorType)
177+
);
178+
return reinterpret_cast<jlong>(image.release());
179+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#include <iostream>
2+
#include <stdint.h>
3+
#include "common.h"
4+
#include "gpu/ganesh/gl/GrGLBackendSurface.h"
5+
#include "include/gpu/ganesh/SkImageGanesh.h"
6+
#include "include/gpu/ganesh/gl/GrGLTypes.h"
7+
#include "gpu/ganesh/GrBackendSurface.h"
8+
9+
static void deleteBackendTexture(GrBackendTexture* rt) {
10+
delete rt;
11+
}
12+
SKIKO_EXPORT KNativePointer org_jetbrains_skia_BackendTexture__1nGetFinalizer() {
13+
return reinterpret_cast<KNativePointer>(&deleteBackendTexture);
14+
}
15+
16+
SKIKO_EXPORT KNativePointer org_jetbrains_skia_BackendTexture__1nMakeGL
17+
(KInt width, KInt height, KBoolean isMipmapped, KInt textureId, KInt target, KInt format) {
18+
GrGLTextureInfo textureInfo;
19+
textureInfo.fID = static_cast<GrGLuint>(textureId);
20+
textureInfo.fTarget = static_cast<GrGLenum>(target);
21+
textureInfo.fFormat = static_cast<GrGLenum>(format);
22+
23+
GrBackendTexture obj = GrBackendTextures::MakeGL(
24+
width,
25+
height,
26+
isMipmapped ? skgpu::Mipmapped::kYes : skgpu::Mipmapped::kNo,
27+
textureInfo
28+
);
29+
30+
GrBackendTexture* instance = new GrBackendTexture(obj);
31+
return instance;
32+
}
33+
34+
SKIKO_EXPORT void org_jetbrains_skia_BackendTexture__1nGLTextureParametersModified
35+
(KNativePointer backendTexturePtr) {
36+
GrBackendTexture* backendTexture = reinterpret_cast<GrBackendTexture*>(backendTexturePtr);
37+
GrBackendTextures::GLTextureParametersModified(backendTexture);
38+
}

‎skiko/src/nativeJsMain/cpp/Image.cc‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22
#include "SkData.h"
33
#include "SkImage.h"
44
#include "SkBitmap.h"
5+
#include "ganesh/GrDirectContext.h"
56
#include "SkShader.h"
67
#include "SkEncodedImageFormat.h"
78
#include "encode/SkPngEncoder.h"
89
#include "encode/SkJpegEncoder.h"
910
#include "encode/SkWebpEncoder.h"
1011
#include "common.h"
12+
#include "include/gpu/ganesh/SkImageGanesh.h"
1113

1214

1315
SKIKO_EXPORT KNativePointer org_jetbrains_skia_Image__1nMakeRaster
@@ -154,3 +156,18 @@ SKIKO_EXPORT KBoolean org_jetbrains_skia_Image__1nScalePixels
154156
auto cachingHint = cache ? SkImage::CachingHint::kAllow_CachingHint : SkImage::CachingHint::kDisallow_CachingHint;
155157
return instance->scalePixels(*pixmap, skija::SamplingMode::unpackFrom2Ints(samplingOptionsVal1, samplingOptionsVal2), cachingHint);
156158
}
159+
160+
SKIKO_EXPORT KNativePointer org_jetbrains_skia_Image__1nAdoptTextureFrom
161+
(KNativePointer contextPtr, KNativePointer backendTexturePtr, KInt surfaceOrigin, KInt colorType) {
162+
GrDirectContext* context = reinterpret_cast<GrDirectContext*>(contextPtr);
163+
GrBackendTexture* backendTexture = reinterpret_cast<GrBackendTexture*>(backendTexturePtr);
164+
165+
sk_sp<SkImage> image = SkImages::AdoptTextureFrom(
166+
static_cast<GrRecordingContext*>(context),
167+
*backendTexture,
168+
static_cast<GrSurfaceOrigin>(surfaceOrigin),
169+
static_cast<SkColorType>(colorType)
170+
);
171+
172+
return reinterpret_cast<KNativePointer>(image.release());
173+
}

0 commit comments

Comments
 (0)