skui-org / skui

Skia-based C++ UI framework
MIT License
399 stars 62 forks source link

Skia.lib does not support OpenGL rendering? sk_abort_no_print #13

Closed libaineu2004 closed 4 years ago

libaineu2004 commented 4 years ago

==========Win7 x64/MSVC 2017==========

My code is: void QSkiaOpenGLWidget::initializeGL() { initializeOpenGLFunctions(); sk_sp glInterface = nullptr; sk_sp context = nullptr; context = GrContext::MakeGL(glInterface); SkASSERT(context); //error here }

//context will be equal to null, SkASSERT () will throw an exception!

void sk_abort_no_print() {

if defined(SK_BUILD_FOR_WIN) && defined(SK_IS_BOT)

// do not display a system dialog before aborting the process _set_abort_behavior(0, _WRITE_ABORT_MSG);

endif

if defined(SK_DEBUG) && defined(SK_BUILD_FOR_WIN)

__debugbreak();

elif defined(clang)

__builtin_debugtrap();

else

abort();

endif

}

Is there any problem with the skia library included in the skui project? Is it the same as Google's official source code and compilation options?

libaineu2004 commented 4 years ago

By the way, my computer's opengl environment configuration is correct, the computer can run other opengl-related programs normally.

rubenvb commented 4 years ago

You should be able to debug through the creation of your glInterface and the context objects and see exactly what is wrong. Skia does not set up everything required for it to use OpenGL itself: it expects OpenGL to be initialized (skui::gui::native_visual contains some Windows code that does at least part of this). Your best bet is to step into the GrContext::MakeGL and see what exactly is going wrong. Note I only ever tested my Windows GL with the Mesa software implementation. It's highly likely this code doesn't set up the proper OpenGL context required by Skia and Mesa is just giving me a sensible default that is enough for Skia, where other graphics drivers might not. Now that I think about it, this fact may explain people not being able to use SkUI with OpenGL on Windows (see #11). If this would be the case, you'd see Skia checking for various OpenGL features it needs and one of them will fail due to a bad OpenGL context version being used.

SkUI's 3rdparty repository contains unmodified Google Skia source code (currently branch m83), but is built through my handmade CMakeLists.txt to not have to interface with GN or whatever other build system Google dreams up to build Skia with in the future. As far as I could tell when I first created my CMakeLists.txt, there's no special build options in the original Skia build system that seem to matter.

libaineu2004 commented 4 years ago

@rubenvb

I compiled the example widget_gallery.exe that comes with skui. Enable F5 breakpoint entry, First reach the source file:

   skia_gl_context :: skia_gl_context (gr_gl_get_function get_function)      : context {}      , gr_gl_interface {GrGLAssembleInterface (nullptr, get_function)}    {      SkASSERT (get_function);      SkASSERT (gr_gl_interface); // error here    }

Finally reach the source file: skia \ skui \ 3rdparty \ skia \ src \ gpu \ gl \ GrGLAssembleInterface.cpp In the end I found that the "nullptr == GetString" condition is true.

define GET_PROC_LOCAL (F) GrGL ## F ## Fn F = (GrGL ## F ## Fn ) get (ctx, "gl" #F)

sk_sp GrGLMakeAssembledInterface (void * ctx, GrGLGetProc get) {      GET_PROC_LOCAL (GetString); // error here      if (nullptr == GetString) {          return nullptr;      } }

The implication is to say      GrGLGetStringFn GetString = (GrGLGetStringFn ) get (ctx, "glGetString"); The value of GetString is nullptr;

so I get: gr_gl_interface = nullptr;

Why? Does the function glGetString not exist?

rubenvb commented 4 years ago

What it's doing here is calling the get function, for which I picked the same logic as the one used by Skia, which is also what the OpenGL wiki says to do. The one SkUI uses on Windows is located here. I used skui::core::library which in the end calls GetProcAddress instead of direcly loading the opengl32 library directly.

Could you try replacing the get_gl function in wgl.c++ with Skia's simpler version directly and see if that works?

rubenvb commented 4 years ago

Ah wait never mind I see the problem. skui::core::library::load is trying to be smart but in reality isn't.

I pushed an update to master which should let skui::core::library::load do the correct thing.

libaineu2004 commented 4 years ago

@rubenvb It may not be a skui problem, but a sklib problem. I created a minimal demo. "sk_sp context = GrContext::MakeGL(interface);" context == nullptr. Details are as follows:

What steps will reproduce the problem? SkSurface::MakeRenderTarget returned null

What is the expected output? What do you see instead? sk_sp context = GrContext::MakeGL(interface); but "context == nullptr",why??

What version of the product are you using? On what operating system? skia-m83/Win7 x64/MSVC 2017/NVIDIA GeForce GT 630

Please submit a code sample. void draw(SkCanvas *canvas) { canvas->drawColor(SK_ColorWHITE); SkPaint paint; paint.setStyle(SkPaint::kFill_Style); paint.setAntiAlias(true); paint.setStrokeWidth(4); paint.setColor(0xff4285F4); SkRect rect = SkRect::MakeXYWH(10, 10, 100, 160); canvas->drawRect(rect, paint); SkRRect oval; oval.setOval(rect); oval.offset(40, 80); paint.setColor(0xffDB4437); canvas->drawRRect(oval, paint); paint.setColor(0xff0F9D58); canvas->drawCircle(180, 50, 25, paint); rect.offset(80, 50); paint.setColor(0xffF4B400); paint.setStyle(SkPaint::kStroke_Style); canvas->drawRoundRect(rect, 10, 10, paint); }

void gl_example(int width, int height, void (draw)(SkCanvas ), const char path) { // You've already created your OpenGL context and bound it. sk_sp interface = nullptr; // Leaving interface as null makes Skia extract pointers to OpenGL functions for the current // context in a platform-specific way. Alternatively, you may create your own GrGLInterface and // initialize it however you like to attach to an alternate OpenGL implementation or intercept // Skia's OpenGL calls. sk_sp context = GrContext::MakeGL(interface);//error here SkImageInfo info = SkImageInfo::MakeN32Premul(width, height); sk_sp gpuSurface( SkSurface::MakeRenderTarget(context.get(), SkBudgeted::kNo, info)); if (!gpuSurface) { SkDebugf("SkSurface::MakeRenderTarget returned null\n"); return; } SkCanvas gpuCanvas = gpuSurface->getCanvas(); draw(gpuCanvas); sk_sp img(gpuSurface->makeImageSnapshot()); if (!img) { return; } sk_sp png(img->encodeToData(SkEncodedImageFormat::kPNG, 100)); if (!png) { return; } SkFILEWStream out(path); (void)out.write(png->data(), png->size()); }

int main(int argc, char *argv[]) { gl_example(300, 300, draw, "d:\demo3.jpg"); return 0; }

rubenvb commented 4 years ago
void gl_example(int width, int height, void (*draw)(SkCanvas *), const char *path)
{
  // You've already created your OpenGL context and bound it.
  sk_sp interface = nullptr;
  // Leaving interface as null makes Skia extract pointers to OpenGL functions for the current
  // context in a platform-specific way. Alternatively, you may create your own GrGLInterface and
  // initialize it however you like to attach to an alternate OpenGL implementation or intercept
  // Skia's OpenGL calls.
  **sk_sp context = GrContext::MakeGL(interface);//error here**

/* ~SNIP~ */

int main(int argc, char *argv[])
{
  gl_example(300, 300, draw, "d:\demo3.jpg");
  return 0;
  }

You are immediately calling GrContext::MakeGL expecting it to work, but it doesn't. You first need to set up a proper OpenGL context yourself (I believe Skia needs OpenGL 2.1 at the very least) . This happens in SkUI code in the native_visual subclasses, which are responsible for setting up the underlying state of the graphics stuff to draw on screen.

Note again that on Windows, it does not do the right thing, and it only sort of works with the Mesa software GL implementation in its current form.

This project is not the right place to ask help with the Skia library. It only uses it to do the actual drawing. Skia have a nice community here: https://groups.google.com/forum/#!forum/skia-discuss. Feel free to use my Skia 3rdparty setup, but I can't help you set up Skia for you purposes. If you have questions about SkUI code, feel free to ask me, but not through the issues here.