blob: 6a6e4bca70296968b36477770adddb3d32eec671 [file] [log] [blame]
Chris Dalton2b598902020-03-25 10:50:35 -06001/*
2 * Copyright 2020 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include <emscripten.h>
9#include <emscripten/bind.h>
Chris Dalton8ce842d2020-04-01 14:46:16 -060010#include "include/core/SkCanvas.h"
Chris Daltone6778f32020-05-27 14:59:16 -060011#include "include/core/SkSurface.h"
12#include "include/gpu/GrContext.h"
Chris Daltonf3242c42020-05-27 17:31:12 -060013#include "tools/viewer/SKPSlide.h"
Chris Dalton2b598902020-03-25 10:50:35 -060014#include "tools/viewer/SampleSlide.h"
Chris Dalton3e7d5112020-05-28 14:04:53 -060015#include "tools/viewer/SvgSlide.h"
Chris Daltone6778f32020-05-27 14:59:16 -060016#include <GLES3/gl3.h>
Chris Dalton2b598902020-03-25 10:50:35 -060017#include <string>
18
19using namespace emscripten;
20
Chris Daltone6778f32020-05-27 14:59:16 -060021sk_sp<Slide> MakeSlide(std::string name) {
22 if (name == "WavyPathText") {
23 extern Sample* MakeWavyPathTextSample();
24 return sk_make_sp<SampleSlide>(MakeWavyPathTextSample);
25 }
26 return nullptr;
27}
28
Chris Daltonf3242c42020-05-27 17:31:12 -060029sk_sp<Slide> MakeSkpSlide(std::string name, std::string skpData) {
30 auto stream = std::make_unique<SkMemoryStream>(skpData.data(), skpData.size(),
31 /*copyData=*/true);
32 return sk_make_sp<SKPSlide>(SkString(name.c_str()), std::move(stream));
33}
34
Chris Dalton3e7d5112020-05-28 14:04:53 -060035sk_sp<Slide> MakeSvgSlide(std::string name, std::string svgText) {
36 auto stream = std::make_unique<SkMemoryStream>(svgText.data(), svgText.size(),
37 /*copyData=*/true);
38 return sk_make_sp<SvgSlide>(SkString(name.c_str()), std::move(stream));
39}
40
Chris Daltone6778f32020-05-27 14:59:16 -060041static void delete_wrapped_framebuffer(SkSurface::ReleaseContext context) {
42 GLuint framebuffer = (GLuint)context;
43 glDeleteFramebuffers(1, &framebuffer);
44}
45
46sk_sp<SkSurface> MakeOffscreenFramebuffer(sk_sp<GrContext> grContext, int width, int height,
47 int sampleCnt) {
48 GLuint colorBuffer;
49 glGenRenderbuffers(1, &colorBuffer);
50 glBindRenderbuffer(GL_RENDERBUFFER, colorBuffer);
51 glRenderbufferStorageMultisample(GL_RENDERBUFFER, sampleCnt, GL_RGBA8, width, height);
52
53 GLuint stencilBuffer;
54 glGenRenderbuffers(1, &stencilBuffer);
55 glBindRenderbuffer(GL_RENDERBUFFER, stencilBuffer);
56 glRenderbufferStorageMultisample(GL_RENDERBUFFER, sampleCnt, GL_STENCIL_INDEX8, width, height);
57
58 GLuint framebuffer;
59 glGenFramebuffers(1, &framebuffer);
60 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
61 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
62 colorBuffer);
63 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
64 stencilBuffer);
65
66 // Unbind "framebuffer" before orphaning its renderbuffers. (Otherwise they are spec'd to be
67 // detached from the currently bound framebuffer.)
68 glBindFramebuffer(GL_FRAMEBUFFER, 0);
69 glDeleteRenderbuffers(1, &colorBuffer);
70 glDeleteRenderbuffers(1, &stencilBuffer);
71
72 grContext->resetContext(kRenderTarget_GrGLBackendState);
73
74 GrGLFramebufferInfo glInfo;
75 glInfo.fFBOID = framebuffer;
76 glInfo.fFormat = GL_RGBA8;
77 GrBackendRenderTarget backendRenderTarget(width, height, sampleCnt, 8, glInfo);
78 return SkSurface::MakeFromBackendRenderTarget(grContext.get(), backendRenderTarget,
79 kBottomLeft_GrSurfaceOrigin,
80 SkColorType::kRGBA_8888_SkColorType, nullptr,
81 nullptr, &delete_wrapped_framebuffer,
82 (SkSurface::ReleaseContext)framebuffer);
83}
84
85enum class GLFilter {
86 kNearest = GL_NEAREST,
87 kLinear = GL_LINEAR
88};
89
90void BlitOffscreenFramebuffer(sk_sp<SkSurface> surface, int srcX0, int srcY0, int srcX1, int srcY1,
91 int dstX0, int dstY0, int dstX1, int dstY1, GLFilter filter) {
92 surface->flush(SkSurface::BackendSurfaceAccess::kPresent, GrFlushInfo());
93 GrGLFramebufferInfo glInfo;
94 auto backendRT = surface->getBackendRenderTarget(SkSurface::kFlushRead_BackendHandleAccess);
95 backendRT.getGLFramebufferInfo(&glInfo);
96 glBindFramebuffer(GL_READ_FRAMEBUFFER, glInfo.fFBOID);
97 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
98 glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, GL_COLOR_BUFFER_BIT,
99 (GLenum)filter);
100 surface->getContext()->resetContext(kRenderTarget_GrGLBackendState);
101}
102
Chris Dalton2b598902020-03-25 10:50:35 -0600103EMSCRIPTEN_BINDINGS(Viewer) {
Chris Daltone6778f32020-05-27 14:59:16 -0600104 function("MakeSlide", &MakeSlide);
Chris Daltonf3242c42020-05-27 17:31:12 -0600105 function("MakeSkpSlide", &MakeSkpSlide);
Chris Dalton3e7d5112020-05-28 14:04:53 -0600106 function("MakeSvgSlide", &MakeSvgSlide);
Chris Daltone6778f32020-05-27 14:59:16 -0600107 function("MakeOffscreenFramebuffer", &MakeOffscreenFramebuffer);
108 function("BlitOffscreenFramebuffer", &BlitOffscreenFramebuffer);
Chris Dalton2b598902020-03-25 10:50:35 -0600109 class_<Slide>("Slide")
110 .smart_ptr<sk_sp<Slide>>("sk_sp<Slide>")
111 .function("load", &Slide::load)
112 .function("animate", &Slide::animate)
113 .function("draw", optional_override([](Slide& self, SkCanvas& canvas) {
114 self.draw(&canvas);
115 }));
Chris Daltone6778f32020-05-27 14:59:16 -0600116 enum_<GLFilter>("GLFilter")
117 .value("Nearest", GLFilter::kNearest)
118 .value("Linear", GLFilter::kLinear);
Chris Dalton2b598902020-03-25 10:50:35 -0600119}