blob: cf394f5178ce77e0d8f7bb7c573af84b41b325f3 [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 Dalton0d0758e2020-05-29 10:51:08 -060013#include "tools/skui/InputState.h"
14#include "tools/skui/ModifierKey.h"
Chris Daltonf3242c42020-05-27 17:31:12 -060015#include "tools/viewer/SKPSlide.h"
Chris Dalton2b598902020-03-25 10:50:35 -060016#include "tools/viewer/SampleSlide.h"
Chris Dalton3e7d5112020-05-28 14:04:53 -060017#include "tools/viewer/SvgSlide.h"
Chris Daltone6778f32020-05-27 14:59:16 -060018#include <GLES3/gl3.h>
Chris Dalton2b598902020-03-25 10:50:35 -060019#include <string>
20
21using namespace emscripten;
22
Chris Dalton0d0758e2020-05-29 10:51:08 -060023static sk_sp<Slide> MakeSlide(std::string name) {
Chris Daltona3908ef2020-05-29 02:10:37 -060024 if (name == "PathText") {
25 extern Sample* MakePathTextSample();
26 return sk_make_sp<SampleSlide>(MakePathTextSample);
Chris Daltone6778f32020-05-27 14:59:16 -060027 }
Chris Dalton0d0758e2020-05-29 10:51:08 -060028 if (name == "TessellatedWedge") {
29 extern Sample* MakeTessellatedWedgeSample();
30 return sk_make_sp<SampleSlide>(MakeTessellatedWedgeSample);
31 }
Chris Daltone6778f32020-05-27 14:59:16 -060032 return nullptr;
33}
34
Chris Dalton0d0758e2020-05-29 10:51:08 -060035static sk_sp<Slide> MakeSkpSlide(std::string name, std::string skpData) {
Chris Daltonf3242c42020-05-27 17:31:12 -060036 auto stream = std::make_unique<SkMemoryStream>(skpData.data(), skpData.size(),
37 /*copyData=*/true);
38 return sk_make_sp<SKPSlide>(SkString(name.c_str()), std::move(stream));
39}
40
Chris Dalton0d0758e2020-05-29 10:51:08 -060041static sk_sp<Slide> MakeSvgSlide(std::string name, std::string svgText) {
Chris Dalton3e7d5112020-05-28 14:04:53 -060042 auto stream = std::make_unique<SkMemoryStream>(svgText.data(), svgText.size(),
43 /*copyData=*/true);
44 return sk_make_sp<SvgSlide>(SkString(name.c_str()), std::move(stream));
45}
46
Chris Daltone6778f32020-05-27 14:59:16 -060047static void delete_wrapped_framebuffer(SkSurface::ReleaseContext context) {
48 GLuint framebuffer = (GLuint)context;
49 glDeleteFramebuffers(1, &framebuffer);
50}
51
Chris Dalton0d0758e2020-05-29 10:51:08 -060052static sk_sp<SkSurface> MakeOffscreenFramebuffer(sk_sp<GrContext> grContext, int width, int height,
53 int sampleCnt) {
Chris Daltone6778f32020-05-27 14:59:16 -060054 GLuint colorBuffer;
55 glGenRenderbuffers(1, &colorBuffer);
56 glBindRenderbuffer(GL_RENDERBUFFER, colorBuffer);
57 glRenderbufferStorageMultisample(GL_RENDERBUFFER, sampleCnt, GL_RGBA8, width, height);
58
59 GLuint stencilBuffer;
60 glGenRenderbuffers(1, &stencilBuffer);
61 glBindRenderbuffer(GL_RENDERBUFFER, stencilBuffer);
62 glRenderbufferStorageMultisample(GL_RENDERBUFFER, sampleCnt, GL_STENCIL_INDEX8, width, height);
63
64 GLuint framebuffer;
65 glGenFramebuffers(1, &framebuffer);
66 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
67 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
68 colorBuffer);
69 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
70 stencilBuffer);
71
72 // Unbind "framebuffer" before orphaning its renderbuffers. (Otherwise they are spec'd to be
73 // detached from the currently bound framebuffer.)
74 glBindFramebuffer(GL_FRAMEBUFFER, 0);
75 glDeleteRenderbuffers(1, &colorBuffer);
76 glDeleteRenderbuffers(1, &stencilBuffer);
77
78 grContext->resetContext(kRenderTarget_GrGLBackendState);
79
80 GrGLFramebufferInfo glInfo;
81 glInfo.fFBOID = framebuffer;
82 glInfo.fFormat = GL_RGBA8;
83 GrBackendRenderTarget backendRenderTarget(width, height, sampleCnt, 8, glInfo);
84 return SkSurface::MakeFromBackendRenderTarget(grContext.get(), backendRenderTarget,
85 kBottomLeft_GrSurfaceOrigin,
86 SkColorType::kRGBA_8888_SkColorType, nullptr,
87 nullptr, &delete_wrapped_framebuffer,
88 (SkSurface::ReleaseContext)framebuffer);
89}
90
91enum class GLFilter {
92 kNearest = GL_NEAREST,
93 kLinear = GL_LINEAR
94};
95
Chris Dalton0d0758e2020-05-29 10:51:08 -060096static void BlitOffscreenFramebuffer(sk_sp<SkSurface> surface, int srcX0, int srcY0, int srcX1, int
97 srcY1, int dstX0, int dstY0, int dstX1, int dstY1,
98 GLFilter filter) {
Chris Daltone6778f32020-05-27 14:59:16 -060099 surface->flush(SkSurface::BackendSurfaceAccess::kPresent, GrFlushInfo());
100 GrGLFramebufferInfo glInfo;
101 auto backendRT = surface->getBackendRenderTarget(SkSurface::kFlushRead_BackendHandleAccess);
102 backendRT.getGLFramebufferInfo(&glInfo);
103 glBindFramebuffer(GL_READ_FRAMEBUFFER, glInfo.fFBOID);
104 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
105 glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, GL_COLOR_BUFFER_BIT,
106 (GLenum)filter);
107 surface->getContext()->resetContext(kRenderTarget_GrGLBackendState);
108}
109
Chris Dalton2b598902020-03-25 10:50:35 -0600110EMSCRIPTEN_BINDINGS(Viewer) {
Chris Daltone6778f32020-05-27 14:59:16 -0600111 function("MakeSlide", &MakeSlide);
Chris Daltonf3242c42020-05-27 17:31:12 -0600112 function("MakeSkpSlide", &MakeSkpSlide);
Chris Dalton3e7d5112020-05-28 14:04:53 -0600113 function("MakeSvgSlide", &MakeSvgSlide);
Chris Daltone6778f32020-05-27 14:59:16 -0600114 function("MakeOffscreenFramebuffer", &MakeOffscreenFramebuffer);
115 function("BlitOffscreenFramebuffer", &BlitOffscreenFramebuffer);
Chris Dalton2b598902020-03-25 10:50:35 -0600116 class_<Slide>("Slide")
117 .smart_ptr<sk_sp<Slide>>("sk_sp<Slide>")
118 .function("load", &Slide::load)
119 .function("animate", &Slide::animate)
120 .function("draw", optional_override([](Slide& self, SkCanvas& canvas) {
121 self.draw(&canvas);
Chris Dalton0d0758e2020-05-29 10:51:08 -0600122 }))
123 .function("onChar", &Slide::onChar)
124 .function("onMouse", &Slide::onMouse);
Chris Daltone6778f32020-05-27 14:59:16 -0600125 enum_<GLFilter>("GLFilter")
126 .value("Nearest", GLFilter::kNearest)
127 .value("Linear", GLFilter::kLinear);
Chris Dalton0d0758e2020-05-29 10:51:08 -0600128 enum_<skui::InputState>("InputState")
129 .value("Down", skui::InputState::kDown)
130 .value("Up", skui::InputState::kUp)
131 .value("Move", skui::InputState::kMove)
132 .value("Right", skui::InputState::kRight)
133 .value("Left", skui::InputState::kLeft);
134 enum_<skui::ModifierKey>("ModifierKey")
135 .value("None", skui::ModifierKey::kNone)
136 .value("Shift", skui::ModifierKey::kShift)
137 .value("Control", skui::ModifierKey::kControl)
138 .value("Option", skui::ModifierKey::kOption)
139 .value("Command", skui::ModifierKey::kCommand)
140 .value("FirstPress", skui::ModifierKey::kFirstPress);
Chris Dalton2b598902020-03-25 10:50:35 -0600141}