From fc58daa814b4562bc667400ddb1e8d32046f1469 Mon Sep 17 00:00:00 2001 From: David Capello Date: Tue, 9 Feb 2016 23:12:59 -0300 Subject: [PATCH] Add support for ANGLE (D3D) on Skia port Anyway we've disable the GPU support temporally (related to #960) --- src/she/CMakeLists.txt | 4 +- src/she/gl/gl_context.h | 3 +- src/she/gl/gl_context_cgl.h | 6 +- src/she/gl/gl_context_egl.h | 165 +++++++++++++++++++++++++++++++ src/she/gl/gl_context_wgl.h | 4 +- src/she/skia/gl_context_skia.h | 55 ----------- src/she/skia/skia_system.h | 8 +- src/she/skia/skia_window_osx.mm | 50 +++++++--- src/she/skia/skia_window_win.cpp | 77 ++++++++++++--- src/she/skia/skia_window_win.h | 9 +- 10 files changed, 279 insertions(+), 102 deletions(-) create mode 100644 src/she/gl/gl_context_egl.h delete mode 100644 src/she/skia/gl_context_skia.h diff --git a/src/she/CMakeLists.txt b/src/she/CMakeLists.txt index d0f728518..c1d97e2cb 100644 --- a/src/she/CMakeLists.txt +++ b/src/she/CMakeLists.txt @@ -85,12 +85,11 @@ if(USE_SKIA_BACKEND) find_library(SKIA_GPU_LIBRARY skia_skgpu PATH "${SKIA_BUILD_OUT_DIR}") find_library(SKIA_UTILS_LIBRARY skia_utils PATH "${SKIA_BUILD_OUT_DIR}") - set(SKIA_LIBEGL_LIBRARY "") if(WIN32) find_library(SKIA_ETC1_LIBRARY libetc1 PATH "${SKIA_BUILD_OUT_DIR}/obj/gyp") find_library(SKIA_LIBSKKTX_LIBRARY libSkKTX PATH "${SKIA_BUILD_OUT_DIR}/obj/gyp") find_library(SKIA_OPENGL_LIBRARY opengl32) - find_library(SKIA_LIBEGL_LIBRARY libEGL.dll.lib PATH "${SKIA_BUILD_OUT_DIR}") + find_library(SKIA_LIBEGL_LIBRARY libEGL.dll PATH "${SKIA_BUILD_OUT_DIR}") if(SKIA_LIBEGL_LIBRARY) add_definitions(-DSK_ANGLE=1) endif() @@ -98,6 +97,7 @@ if(USE_SKIA_BACKEND) find_library(SKIA_ETC1_LIBRARY etc1 PATH "${SKIA_BUILD_OUT_DIR}") find_library(SKIA_LIBSKKTX_LIBRARY SkKTX PATH "${SKIA_BUILD_OUT_DIR}") find_library(SKIA_OPENGL_LIBRARY opengl) + set(SKIA_LIBEGL_LIBRARY "") endif() find_path(SKIA_CONFIG_INCLUDE_DIR SkUserConfig.h HINTS "${SKIA_DIR}/include/config") diff --git a/src/she/gl/gl_context.h b/src/she/gl/gl_context.h index 8772ad962..c7f18fecd 100644 --- a/src/she/gl/gl_context.h +++ b/src/she/gl/gl_context.h @@ -1,5 +1,5 @@ // SHE library -// Copyright (C) 2015 David Capello +// Copyright (C) 2015, 2016 David Capello // // This file is released under the terms of the MIT license. // Read LICENSE.txt for more information. @@ -17,6 +17,7 @@ public: virtual void destroyGLContext() = 0; virtual int getStencilBits() = 0; virtual int getSampleCount() = 0; + virtual void swapBuffers() { } }; } // namespace she diff --git a/src/she/gl/gl_context_cgl.h b/src/she/gl/gl_context_cgl.h index 24b80b6e8..277f20e05 100644 --- a/src/she/gl/gl_context_cgl.h +++ b/src/she/gl/gl_context_cgl.h @@ -1,5 +1,5 @@ // SHE library -// Copyright (C) 2015 David Capello +// Copyright (C) 2015, 2016 David Capello // // This file is released under the terms of the MIT license. // Read LICENSE.txt for more information. @@ -17,9 +17,7 @@ namespace she { class GLContextCGL : public GLContext { public: - typedef void* NativeHandle; - - GLContextCGL(NativeHandle window) + GLContextCGL() : m_glctx(nullptr) , m_stencilBits(0) , m_sampleCount(0) { diff --git a/src/she/gl/gl_context_egl.h b/src/she/gl/gl_context_egl.h new file mode 100644 index 000000000..f4a661cc2 --- /dev/null +++ b/src/she/gl/gl_context_egl.h @@ -0,0 +1,165 @@ +// SHE library +// Copyright (C) 2016 David Capello +// +// This file is released under the terms of the MIT license. +// Read LICENSE.txt for more information. + +#ifndef SHE_GL_CONTEXT_EGL_INCLUDED +#define SHE_GL_CONTEXT_EGL_INCLUDED +#pragma once + +#include "she/gl/gl_context.h" + +#include +#include + +namespace she { + +class GLContextEGL : public GLContext { +public: + GLContextEGL(void* nativeDisplay) + : m_nativeDisplay(nativeDisplay) + , m_context(EGL_NO_CONTEXT) + , m_display(EGL_NO_DISPLAY) + , m_surface(EGL_NO_SURFACE) + { + } + + ~GLContextEGL() { + destroyGLContext(); + } + + bool createGLContext() override { + m_display = getD3DEGLDisplay((HDC)GetDC((HWND)m_nativeDisplay)); + if (m_display == EGL_NO_DISPLAY) { + LOG("Cannot create EGL display"); + return false; + } + + EGLint majorVersion; + EGLint minorVersion; + if (!eglInitialize(m_display, &majorVersion, &minorVersion)) + return false; + + static const EGLint configAttribs[] = { + EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 8, + EGL_NONE + }; + EGLConfig surfaceConfig; + EGLint numConfigs; + if (!eglChooseConfig(m_display, configAttribs, &surfaceConfig, 1, &numConfigs)) + return false; + + static const EGLint surfaceAttribs[] = { + EGL_WIDTH, 1, + EGL_HEIGHT, 1, + EGL_NONE + }; + m_surface = eglCreateWindowSurface( + m_display, + surfaceConfig, + (EGLNativeWindowType)m_nativeDisplay, + surfaceAttribs); + if (m_surface == EGL_NO_SURFACE) + return false; + + static const EGLint contextAttribs[] = { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE + }; + m_context = eglCreateContext(m_display, surfaceConfig, + EGL_NO_CONTEXT, + contextAttribs); + if (m_context == EGL_NO_CONTEXT) + return false; + + if (!eglMakeCurrent(m_display, m_surface, m_surface, m_context)) + return false; + + eglGetConfigAttrib(m_display, surfaceConfig, EGL_STENCIL_SIZE, &m_stencilBits); + eglGetConfigAttrib(m_display, surfaceConfig, EGL_SAMPLES, &m_sampleCount); + + return true; + } + + void destroyGLContext() override { + if (m_display != EGL_NO_DISPLAY) { + eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + + if (m_surface != EGL_NO_SURFACE) { + eglDestroySurface(m_display, m_surface); + m_surface = EGL_NO_SURFACE; + } + + if (m_context != EGL_NO_CONTEXT) { + eglDestroyContext(m_display, m_context); + m_context = EGL_NO_CONTEXT; + } + + eglTerminate(m_display); + m_display = EGL_NO_DISPLAY; + } + } + + int getStencilBits() override { + return m_stencilBits; + } + + int getSampleCount() override { + return m_sampleCount; + } + + void swapBuffers() override { + eglSwapBuffers(m_display, m_surface); + } + +private: + static void* getD3DEGLDisplay(void* nativeDisplay) { + PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT; + eglGetPlatformDisplayEXT = + (PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT"); + if (!eglGetPlatformDisplayEXT) + return eglGetDisplay(static_cast(nativeDisplay)); + + EGLint attribs[3][3] = { + { + EGL_PLATFORM_ANGLE_TYPE_ANGLE, + EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, + EGL_NONE + }, + { + EGL_PLATFORM_ANGLE_TYPE_ANGLE, + EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE, + EGL_NONE + }, + { + EGL_PLATFORM_ANGLE_TYPE_ANGLE, + EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, + EGL_NONE + } + }; + + EGLDisplay display = EGL_NO_DISPLAY; + for (int i=0; i<3 && display == EGL_NO_DISPLAY; ++i) { + display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, + nativeDisplay, attribs[i]); + } + return display; + } + + void* m_nativeDisplay; + void* m_context; + void* m_display; + void* m_surface; + EGLint m_stencilBits; + EGLint m_sampleCount; +}; + +} // namespace she + +#endif diff --git a/src/she/gl/gl_context_wgl.h b/src/she/gl/gl_context_wgl.h index 24747269e..ce69ad997 100644 --- a/src/she/gl/gl_context_wgl.h +++ b/src/she/gl/gl_context_wgl.h @@ -1,5 +1,5 @@ // SHE library -// Copyright (C) 2015 David Capello +// Copyright (C) 2015-2016 David Capello // // This file is released under the terms of the MIT license. // Read LICENSE.txt for more information. @@ -16,8 +16,6 @@ namespace she { class GLContextWGL : public GLContext { public: - typedef HWND NativeHandle; - GLContextWGL(HWND hwnd) : m_hwnd(hwnd) , m_glrc(nullptr) { diff --git a/src/she/skia/gl_context_skia.h b/src/she/skia/gl_context_skia.h deleted file mode 100644 index 9dcb60711..000000000 --- a/src/she/skia/gl_context_skia.h +++ /dev/null @@ -1,55 +0,0 @@ -// SHE library -// Copyright (C) 2012-2015 David Capello -// -// This file is released under the terms of the MIT license. -// Read LICENSE.txt for more information. - -#ifndef SHE_SKIA_GL_CONTEXT_INCLUDED -#define SHE_SKIA_GL_CONTEXT_INCLUDED -#pragma once - -#ifndef SK_SUPPORT_GPU - #error Skia was compiled without GPU support -#endif - -#include "gl/GrGLInterface.h" - -#include - -namespace she { - -template -class GLContextSkia : public Base { -public: - GLContextSkia(typename Base::NativeHandle nativeHandle) : Base(nativeHandle) { - Base::createGLContext(); - if (!createSkiaInterfaces()) { - Base::destroyGLContext(); - throw std::runtime_error("Cannot create OpenGL context"); - } - } - - ~GLContextSkia() { - m_gl.reset(nullptr); - } - - const GrGLInterface* gl() const { - return m_gl.get(); - } - -private: - bool createSkiaInterfaces() { - SkAutoTUnref gl(GrGLCreateNativeInterface()); - if (!gl || !gl->validate()) - return false; - - m_gl.reset(gl.detach()); - return true; - } - - SkAutoTUnref m_gl; -}; - -} // namespace she - -#endif diff --git a/src/she/skia/skia_system.h b/src/she/skia/skia_system.h index c5dfea22a..46c43e6be 100644 --- a/src/she/skia/skia_system.h +++ b/src/she/skia/skia_system.h @@ -1,5 +1,5 @@ // SHE library -// Copyright (C) 2012-2015 David Capello +// Copyright (C) 2012-2016 David Capello // // This file is released under the terms of the MIT license. // Read LICENSE.txt for more information. @@ -48,10 +48,8 @@ public: int(Capabilities::MultipleDisplays) | int(Capabilities::CanResizeDisplay) | int(Capabilities::DisplayScale) -#ifdef _WIN32 - // GPU acceleration is available on Windows at this moment - | int(Capabilities::GpuAccelerationSwitch) -#endif + // GPU acceleration is disabled at this moment + //| int(Capabilities::GpuAccelerationSwitch) ); } diff --git a/src/she/skia/skia_window_osx.mm b/src/she/skia/skia_window_osx.mm index 82d9ee736..03fafac72 100644 --- a/src/she/skia/skia_window_osx.mm +++ b/src/she/skia/skia_window_osx.mm @@ -1,5 +1,5 @@ // SHE library -// Copyright (C) 2012-2015 David Capello +// Copyright (C) 2012-2016 David Capello // // This file is released under the terms of the MIT license. // Read LICENSE.txt for more information. @@ -23,8 +23,8 @@ #if SK_SUPPORT_GPU #include "GrContext.h" + #include "gl/GrGLInterface.h" #include "she/gl/gl_context_cgl.h" - #include "she/skia/gl_context_skia.h" #include "she/skia/skia_surface.h" #endif @@ -39,6 +39,7 @@ public: , m_backend(Backend::NONE) #if SK_SUPPORT_GPU , m_nsGL(nil) + , m_skSurface(nullptr) #endif { m_closing = false; @@ -123,7 +124,7 @@ public: bool gpu = she::instance()->gpuAcceleration(); (void)gpu; - // Disable GPU acceleration because it isn't ready yet. + // Disable GPU acceleration. gpu = false; #if SK_SUPPORT_GPU @@ -183,19 +184,29 @@ private: bool attachGL() { if (!m_glCtx) { try { - auto ctx = new GLContextSkia(nullptr); + SkAutoTDelete ctx(new GLContextCGL); + if (!ctx->createGLContext()) + throw std::runtime_error("Cannot create CGL context"); + + m_glInterfaces.reset(GrGLCreateNativeInterface()); + if (!m_glInterfaces || !m_glInterfaces->validate()) { + LOG("Cannot create GL interfaces\n"); + detachGL(); + return false; + } m_glCtx.reset(ctx); m_grCtx.reset(GrContext::Create(kOpenGL_GrBackend, - (GrBackendContext)m_glCtx->gl())); + (GrBackendContext)m_glInterfaces.get())); m_nsGL = [[NSOpenGLContext alloc] - initWithCGLContextObj:m_glCtx->cglContext()]; + initWithCGLContextObj:static_cast(m_glCtx.get())->cglContext()]; [m_nsGL setView:m_window.contentView]; + LOG("Using CGL backend\n"); } catch (const std::exception& ex) { - //LOG("Cannot create GL context: %s\n", ex.what()); + LOG("Cannot create GL context: %s\n", ex.what()); detachGL(); return false; } @@ -206,6 +217,11 @@ private: void detachGL() { if (m_nsGL) m_nsGL = nil; + + setSurface(nullptr); + m_skSurfaceDirect.reset(nullptr); + m_grRenderTarget.reset(nullptr); + m_grCtx.reset(nullptr); m_glCtx.reset(nullptr); } @@ -222,14 +238,16 @@ private: desc.fStencilBits = m_glCtx->getStencilBits(); desc.fRenderTargetHandle = 0; // direct frame buffer m_grRenderTarget.reset(m_grCtx->textureProvider()->wrapBackendRenderTarget(desc)); + + setSurface(nullptr); // set m_skSurface comparing with the old m_skSurfaceDirect m_skSurfaceDirect.reset( SkSurface::NewRenderTargetDirect(m_grRenderTarget)); if (scale == 1) { - m_skSurface.reset(m_skSurfaceDirect); + setSurface(m_skSurfaceDirect); } else { - m_skSurface.reset( + setSurface( SkSurface::NewRenderTarget( m_grCtx, SkSurface::kYes_Budgeted, @@ -239,13 +257,20 @@ private: } if (!m_skSurface) - throw std::runtime_error("Error creating OpenGL surface for main display"); + throw std::runtime_error("Error creating surface for main display"); m_display->setSkiaSurface(new SkiaSurface(m_skSurface)); if (m_nsGL) [m_nsGL update]; } + + void setSurface(SkSurface* surface) { + if (m_skSurface && m_skSurface != m_skSurfaceDirect) + delete m_skSurface; + m_skSurface = surface; + } + #endif void paintGC(const gfx::Rect& rect) { @@ -281,12 +306,13 @@ private: bool m_closing; OSXWindow* m_window; #if SK_SUPPORT_GPU - base::UniquePtr > m_glCtx; + base::UniquePtr m_glCtx; + SkAutoTUnref m_glInterfaces; NSOpenGLContext* m_nsGL; SkAutoTUnref m_grCtx; SkAutoTUnref m_grRenderTarget; SkAutoTDelete m_skSurfaceDirect; - SkAutoTDelete m_skSurface; + SkSurface* m_skSurface; gfx::Size m_lastSize; #endif }; diff --git a/src/she/skia/skia_window_win.cpp b/src/she/skia/skia_window_win.cpp index 544f27be3..a8bd5e298 100644 --- a/src/she/skia/skia_window_win.cpp +++ b/src/she/skia/skia_window_win.cpp @@ -19,13 +19,16 @@ #include "GrContext.h" #include "she/gl/gl_context_wgl.h" + #if SK_ANGLE + #include "she/gl/gl_context_egl.h" + #endif #endif #ifdef _WIN32 #include - #include "she/win/window_dde.h" // Include this one time to + #include "she/win/window_dde.h" #endif @@ -117,7 +120,8 @@ void SkiaWindow::paintImpl(HDC hdc) } // Flush GL context - m_glCtx->gl()->fFunctions.fFlush(); + m_glInterfaces->fFunctions.fFlush(); + m_glCtx->swapBuffers(); break; #endif // SK_SUPPORT_GPU @@ -154,20 +158,32 @@ void SkiaWindow::paintHDC(HDC hdc) #if SK_SUPPORT_GPU -bool SkiaWindow::attachGL() +#if SK_ANGLE + +bool SkiaWindow::attachANGLE() { if (!m_glCtx) { try { - auto ctx = new GLContextSkia(handle()); + SkAutoTDelete ctx(new GLContextEGL(handle())); + if (!ctx->createGLContext()) + throw std::runtime_error("Cannot create EGL context"); + + m_glInterfaces.reset(GrGLCreateANGLEInterface()); + if (!m_glInterfaces || !m_glInterfaces->validate()) + throw std::runtime_error("Cannot create EGL interfaces\n"); + m_stencilBits = ctx->getStencilBits(); m_sampleCount = ctx->getSampleCount(); - m_glCtx.reset(ctx); - m_grCtx.reset(GrContext::Create(kOpenGL_GrBackend, - (GrBackendContext)m_glCtx->gl())); + m_glCtx.reset(ctx.detach()); + m_grCtx.reset( + GrContext::Create(kOpenGL_GrBackend, + (GrBackendContext)m_glInterfaces.get())); + + LOG("Using EGL backend\n"); } catch (const std::exception& ex) { - LOG("Cannot create GL context: %s\n", ex.what()); + LOG("Error initializing EGL backend: %s\n", ex.what()); detachGL(); } } @@ -178,15 +194,41 @@ bool SkiaWindow::attachGL() return false; } -#if SK_ANGLE - -bool SkiaWindow::attachANGLE() -{ - return false; // TODO -} - #endif // SK_ANGLE +bool SkiaWindow::attachGL() +{ + if (!m_glCtx) { + try { + SkAutoTDelete ctx(new GLContextWGL(handle())); + if (!ctx->createGLContext()) + throw std::runtime_error("Cannot create WGL context\n"); + + m_glInterfaces.reset(GrGLCreateNativeInterface()); + if (!m_glInterfaces || !m_glInterfaces->validate()) + throw std::runtime_error("Cannot create WGL interfaces\n"); + + m_stencilBits = ctx->getStencilBits(); + m_sampleCount = ctx->getSampleCount(); + + m_glCtx.reset(ctx.detach()); + m_grCtx.reset(GrContext::Create(kOpenGL_GrBackend, + (GrBackendContext)m_glInterfaces.get())); + + LOG("Using WGL backend\n"); + } + catch (const std::exception& ex) { + LOG("Error initializing WGL backend: %s\n", ex.what()); + detachGL(); + } + } + + if (m_glCtx) + return true; + else + return false; +} + void SkiaWindow::detachGL() { if (m_glCtx && m_display) @@ -232,7 +274,7 @@ void SkiaWindow::createRenderTarget(const gfx::Size& size) } if (!m_skSurface) - throw std::runtime_error("Error creating OpenGL surface for main display"); + throw std::runtime_error("Error creating surface for main display"); m_display->setSkiaSurface(new SkiaSurface(m_skSurface)); } @@ -251,6 +293,9 @@ void SkiaWindow::resizeImpl(const gfx::Size& size) bool gpu = instance()->gpuAcceleration(); (void)gpu; + // Disable GPU acceleration. + gpu = false; + #if SK_SUPPORT_GPU #if SK_ANGLE if (gpu && attachANGLE()) { diff --git a/src/she/skia/skia_window_win.h b/src/she/skia/skia_window_win.h index 34e9c0d21..13dd64d0c 100644 --- a/src/she/skia/skia_window_win.h +++ b/src/she/skia/skia_window_win.h @@ -14,8 +14,8 @@ #include "she/win/window.h" #if SK_SUPPORT_GPU - #include "she/gl/gl_context_wgl.h" - #include "she/skia/gl_context_skia.h" + #include "gl/GrGLInterface.h" + #include "she/gl/gl_context.h" #endif namespace she { @@ -39,10 +39,10 @@ private: void paintHDC(HDC dc); #if SK_SUPPORT_GPU - bool attachGL(); #if SK_ANGLE bool attachANGLE(); #endif // SK_ANGLE + bool attachGL(); void detachGL(); void createRenderTarget(const gfx::Size& size); void setSurface(SkSurface* surface); @@ -52,7 +52,8 @@ private: SkiaDisplay* m_display; Backend m_backend; #if SK_SUPPORT_GPU - base::UniquePtr > m_glCtx; + base::UniquePtr m_glCtx; + SkAutoTUnref m_glInterfaces; SkAutoTUnref m_grCtx; SkAutoTUnref m_grRenderTarget; SkAutoTDelete m_skSurfaceDirect;