| /* |
| * Copyright 2022 Rive |
| */ |
| |
| #include "viewer/viewer_host.hpp" |
| #include "viewer/viewer_content.hpp" |
| |
| #ifdef RIVE_RENDERER_SKIA |
| |
| #ifdef RIVE_BUILD_FOR_APPLE |
| #include "cg_skia_factory.hpp" |
| static rive::CGSkiaFactory skiaFactory; |
| #else |
| #include "skia_factory.hpp" |
| static rive::SkiaFactory skiaFactory; |
| #endif |
| #include "skia_renderer.hpp" |
| |
| #include "include/core/SkSurface.h" |
| #include "include/core/SkCanvas.h" |
| #include "include/core/SkPaint.h" |
| #include "include/core/SkSize.h" |
| #include "GrDirectContext.h" |
| |
| sk_sp<GrDirectContext> makeSkiaContext(); |
| sk_sp<SkSurface> makeSkiaSurface(GrDirectContext* context, int width, int height); |
| void skiaPresentSurface(sk_sp<SkSurface> surface); |
| |
| // Experimental flag, until we complete coregraphics_host |
| //#define TEST_CG_RENDERER |
| |
| //#define SW_SKIA_MODE |
| |
| #ifdef TEST_CG_RENDERER |
| #include "cg_factory.hpp" |
| #include "cg_renderer.hpp" |
| #include "mac_utils.hpp" |
| static void render_with_cg(SkCanvas* canvas, int w, int h, ViewerContent* content, double elapsed) |
| { |
| // cons up a CGContext |
| auto pixels = SkData::MakeUninitialized(w * h * 4); |
| auto bytes = (uint8_t*)pixels->writable_data(); |
| std::fill(bytes, bytes + pixels->size(), 0); |
| AutoCF space = CGColorSpaceCreateDeviceRGB(); |
| auto info = kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast; |
| AutoCF ctx = CGBitmapContextCreate(bytes, w, h, 8, w * 4, space, info); |
| |
| // Wrap it with our renderer |
| rive::CGRenderer renderer(ctx, w, h); |
| content->handleDraw(&renderer, elapsed); |
| CGContextFlush(ctx); |
| |
| // Draw the pixels into the canvas |
| auto img = SkImage::MakeRasterData(SkImageInfo::MakeN32Premul(w, h), pixels, w * 4); |
| canvas->drawImage(img, 0, 0, SkSamplingOptions(SkFilterMode::kNearest), nullptr); |
| } |
| #endif |
| |
| class SkiaViewerHost : public ViewerHost |
| { |
| public: |
| sk_sp<GrDirectContext> m_context; |
| SkISize m_dimensions; |
| |
| bool init(sg_pass_action* action, int width, int height) override |
| { |
| m_dimensions = {width, height}; |
| |
| #if defined(SK_METAL) |
| // Skia is layered behind the Sokol view, so we need to make sure Sokol |
| // clears transparent. Skia will draw the background. |
| *action = (sg_pass_action){.colors[0] = { |
| .action = SG_ACTION_CLEAR, |
| .value = |
| { 0.0f, |
| 0.0, |
| 0.0f, |
| 0.0 } |
| }}; |
| #elif defined(SK_GL) |
| // Skia commands are issued to the same GL context before Sokol, so we need |
| // to make sure Sokol does not clear the buffer. |
| *action = (sg_pass_action){.colors[0] = {.action = SG_ACTION_DONTCARE }}; |
| #endif |
| |
| m_context = makeSkiaContext(); |
| return m_context != nullptr; |
| } |
| |
| void handleResize(int width, int height) override { m_dimensions = {width, height}; } |
| |
| void beforeDefaultPass(ViewerContent* content, double elapsed) override |
| { |
| m_context->resetContext(); |
| auto surf = makeSkiaSurface(m_context.get(), m_dimensions.width(), m_dimensions.height()); |
| SkCanvas* canvas = surf->getCanvas(); |
| SkPaint paint; |
| paint.setColor(0xFF161616); |
| canvas->drawPaint(paint); |
| |
| if (content) |
| { |
| #ifdef TEST_CG_RENDERER |
| render_with_cg(canvas, m_dimensions.width(), m_dimensions.height(), content, elapsed); |
| #elif defined(SW_SKIA_MODE) |
| auto info = SkImageInfo::MakeN32Premul(m_dimensions.width(), m_dimensions.height()); |
| auto swsurf = SkSurface::MakeRaster(info); |
| rive::SkiaRenderer skiaRenderer(swsurf->getCanvas()); |
| content->handleDraw(&skiaRenderer, elapsed); |
| auto img = swsurf->makeImageSnapshot(); |
| canvas->drawImage(img, 0, 0, SkSamplingOptions(SkFilterMode::kNearest), nullptr); |
| #else |
| rive::SkiaRenderer skiaRenderer(canvas); |
| content->handleDraw(&skiaRenderer, elapsed); |
| #endif |
| } |
| |
| canvas->flush(); |
| skiaPresentSurface(surf); |
| sg_reset_state_cache(); |
| } |
| }; |
| |
| std::unique_ptr<ViewerHost> ViewerHost::Make() { return rivestd::make_unique<SkiaViewerHost>(); } |
| |
| rive::Factory* ViewerHost::Factory() |
| { |
| #ifdef TEST_CG_RENDERER |
| static rive::CGFactory gFactory; |
| return &gFactory; |
| #else |
| return &skiaFactory; |
| #endif |
| } |
| |
| #endif |