Unverified Commit 0adc7e6a authored by Roman Sedaikin's avatar Roman Sedaikin Committed by GitHub

Merge pull request #85 from JetBrains/angle

Angle rendering prototype (in conservation).
parents 84dc8035 45766dcf
......@@ -319,6 +319,10 @@ tasks.withType(CppCompile::class.java).configureEach {
"-DSK_DIRECT3D",
"/utf-8",
"/GR-", // no-RTTI.
// LATER. Ange rendering arguments:
// "-I$skiaDir/third_party/externals/angle2/include",
// "-I$skiaDir/src/gpu",
// "-DSK_ANGLE",
*buildType.msvcFlags
)
)
......
#ifdef SK_ANGLE
#include <Windows.h>
#include <jawt_md.h>
#include "jni_helpers.h"
#include "GrBackendSurface.h"
#include "GrDirectContext.h"
#include "SkSurface.h"
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include "gl/GrGLAssembleInterface.h"
#include "gl/GrGLDefines.h"
#include <GL/gl.h>
class AngleDevice
{
public:
HWND window;
HDC device;
EGLDisplay display = EGL_NO_DISPLAY;
EGLContext context = EGL_NO_CONTEXT;
EGLSurface surface = EGL_NO_SURFACE;
sk_sp<const GrGLInterface> backendContext;
~AngleDevice()
{
backendContext.reset(nullptr);
eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
if (EGL_NO_CONTEXT != context)
{
eglDestroyContext(display, context);
}
if (EGL_NO_SURFACE != surface)
{
eglDestroySurface(display, surface);
}
if (EGL_NO_DISPLAY != display)
{
eglTerminate(display);
}
}
};
extern "C"
{
EGLDisplay getAngleEGLDisplay(HDC hdc)
{
PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT;
eglGetPlatformDisplayEXT = (PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT");
// We expect ANGLE to support this extension
if (!eglGetPlatformDisplayEXT)
{
return EGL_NO_DISPLAY;
}
// We currently only support D3D11 ANGLE.
static constexpr EGLint kType = EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE;
static constexpr EGLint attribs[] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE, kType, EGL_NONE};
return eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, hdc, attribs);
}
JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_AngleRedrawer_createAngleDevice(
JNIEnv *env, jobject redrawer, jlong windowHandle)
{
AngleDevice *angleDevice = new AngleDevice();
angleDevice->window = (HWND)windowHandle;
angleDevice->device = GetDC(angleDevice->window);
angleDevice->display = getAngleEGLDisplay(angleDevice->device);
if (EGL_NO_DISPLAY == angleDevice->display)
{
fprintf(stderr, "Could not get display!\n");
return 0;
}
EGLint majorVersion;
EGLint minorVersion;
if (!eglInitialize(angleDevice->display, &majorVersion, &minorVersion))
{
fprintf(stderr, "Could not initialize display!\n");
return 0;
}
EGLint numConfigs;
const int sampleBuffers = 1;
const EGLint configAttribs[] = {EGL_RENDERABLE_TYPE,
// We currently only support ES3.
EGL_OPENGL_ES3_BIT,
EGL_RED_SIZE,
8,
EGL_GREEN_SIZE,
8,
EGL_BLUE_SIZE,
8,
EGL_ALPHA_SIZE,
8,
EGL_SAMPLE_BUFFERS,
sampleBuffers,
EGL_SAMPLES,
0,
EGL_NONE};
EGLConfig surfaceConfig;
if (!eglChooseConfig(angleDevice->display, configAttribs, &surfaceConfig, 1, &numConfigs))
{
fprintf(stderr, "Could not create choose config!\n");
return 0;
}
// We currently only support ES3.
const EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE};
angleDevice->context = eglCreateContext(angleDevice->display, surfaceConfig, nullptr, contextAttribs);
if (EGL_NO_CONTEXT == angleDevice->context)
{
fprintf(stderr, "Could not create context!\n");
return 0;
}
angleDevice->surface = eglCreateWindowSurface(angleDevice->display, surfaceConfig, angleDevice->window, nullptr);
if (EGL_NO_SURFACE == angleDevice->surface)
{
fprintf(stderr, "Could not create surface!\n");
return 0;
}
if (!eglMakeCurrent(angleDevice->display, angleDevice->surface, angleDevice->surface, angleDevice->context))
{
fprintf(stderr, "Could not make contxt current!\n");
return 0;
}
sk_sp<const GrGLInterface> interface(GrGLMakeAssembledInterface(
nullptr,
[](void *ctx, const char name[]) -> GrGLFuncPtr { return eglGetProcAddress(name); }));
angleDevice->backendContext = interface;
return toJavaPointer(angleDevice);
}
JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_AngleRedrawer_makeAngleContext(
JNIEnv *env, jobject redrawer, jlong devicePtr)
{
AngleDevice *angleDevice = fromJavaPointer<AngleDevice *>(devicePtr);
sk_sp<const GrGLInterface> backendContext = angleDevice->backendContext;
return toJavaPointer(GrDirectContext::MakeGL(backendContext).release());
}
JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_AngleRedrawer_makeAngleRenderTarget(
JNIEnv *env, jobject redrawer, jlong devicePtr, jint width, jint height)
{
AngleDevice *angleDevice = fromJavaPointer<AngleDevice *>(devicePtr);
eglMakeCurrent(angleDevice->display, angleDevice->surface, angleDevice->surface, angleDevice->context);
angleDevice->backendContext->fFunctions.fViewport(0, 0, width, height);
GrGLint buffer;
angleDevice->backendContext->fFunctions.fGetIntegerv(GR_GL_FRAMEBUFFER_BINDING, &buffer);
GrGLFramebufferInfo info;
info.fFBOID = buffer;
info.fFormat = GR_GL_RGBA8;
GrBackendRenderTarget *renderTarget = new GrBackendRenderTarget(width,
height,
0,
8,
info);
return toJavaPointer(renderTarget);
}
JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_AngleRedrawer_resizeBuffers(
JNIEnv *env, jobject redrawer, jlong devicePtr, jint width, jint height)
{
}
JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_AngleRedrawer_finishFrame(
JNIEnv *env, jobject redrawer, jlong devicePtr, jboolean isVsyncEnabled)
{
AngleDevice *angleDevice = fromJavaPointer<AngleDevice *>(devicePtr);
eglMakeCurrent(angleDevice->display, angleDevice->surface, angleDevice->surface, angleDevice->context);
eglSwapInterval(angleDevice->display, (int)isVsyncEnabled); // wait for vsync
if (!eglSwapBuffers(angleDevice->display, angleDevice->surface))
{
fprintf(stderr, "Could not complete eglSwapBuffers.\n");
}
}
JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_AngleRedrawer_disposeDevice(
JNIEnv *env, jobject redrawer, jlong devicePtr)
{
AngleDevice *angleDevice = fromJavaPointer<AngleDevice *>(devicePtr);
delete angleDevice;
}
} // end extern C
#endif
\ No newline at end of file
package org.jetbrains.skiko.context
import java.lang.ref.Reference
import org.jetbrains.skija.ColorSpace
import org.jetbrains.skija.FramebufferFormat
import org.jetbrains.skija.Picture
import org.jetbrains.skija.Surface
import org.jetbrains.skija.SurfaceColorFormat
import org.jetbrains.skija.SurfaceOrigin
import org.jetbrains.skija.impl.Native
import org.jetbrains.skiko.SkiaLayer
import org.jetbrains.skiko.redrawer.AngleRedrawer
import org.jetbrains.skiko.redrawer.Redrawer
import org.jetbrains.skiko.destroyContext
internal class AngleContextHandler(layer: SkiaLayer) : ContextHandler(layer) {
val angleRedrawer: AngleRedrawer
get() = layer.redrawer!! as AngleRedrawer
var device: Long = 0
override fun initContext(): Boolean {
try {
if (context == null) {
device = angleRedrawer.createDevice()
if (device == 0L) {
throw Exception("Failed to create Angle device.")
}
context = angleRedrawer.makeContext()
}
} catch (e: Exception) {
println("${e.message}\nFailed to create Skia Angle context!")
return false
}
return true
}
override fun initCanvas() {
dispose()
val scale = layer.contentScale
val w = (layer.width * scale).toInt().coerceAtLeast(0)
val h = (layer.height * scale).toInt().coerceAtLeast(0)
renderTarget = angleRedrawer.makeRenderTarget(w, h)
surface = Surface.makeFromBackendRenderTarget(
context!!,
renderTarget!!,
SurfaceOrigin.BOTTOM_LEFT,
SurfaceColorFormat.RGBA_8888,
ColorSpace.getSRGB()
)
canvas = surface!!.canvas
}
override fun flush() {
super.flush()
angleRedrawer.finishFrame()
}
}
package org.jetbrains.skiko.redrawer
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.swing.Swing
import org.jetbrains.skija.BackendRenderTarget
import org.jetbrains.skija.DirectContext
import org.jetbrains.skiko.FrameDispatcher
import org.jetbrains.skiko.SkiaLayer
import org.jetbrains.skiko.SkiaLayerProperties
internal class AngleRedrawer(
private val layer: SkiaLayer,
private val properties: SkiaLayerProperties
) : Redrawer {
private var isDisposed = false
private var device: Long = 0
private val frameDispatcher = FrameDispatcher(Dispatchers.Swing) {
update(System.nanoTime())
draw()
}
override fun dispose() {
frameDispatcher.cancel()
disposeDevice(device)
isDisposed = true
}
override fun needRedraw() {
check(!isDisposed)
frameDispatcher.scheduleFrame()
}
override fun redrawImmediately() {
check(!isDisposed)
update(System.nanoTime())
draw()
}
private fun update(nanoTime: Long) {
layer.update(nanoTime)
}
private fun draw() {
layer.draw()
}
fun createDevice(): Long {
device = createAngleDevice(layer.windowHandle)
return device
}
fun makeContext() = DirectContext(
makeAngleContext(device)
)
fun makeRenderTarget(width: Int, height: Int) = BackendRenderTarget(
makeAngleRenderTarget(device, width, height)
)
fun finishFrame() = finishFrame(device, properties.isVsyncEnabled)
external fun createAngleDevice(windowHandle: Long): Long
external fun makeAngleContext(device: Long): Long
external fun makeAngleRenderTarget(device: Long, width: Int, height: Int): Long
external fun resizeBuffers(device: Long, width: Int, height: Int)
external fun finishFrame(device: Long, isVsyncEnabled: Boolean)
external fun disposeDevice(device: Long)
}
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