skia2/tools/viewer/MSKPSlide.cpp
Brian Salomon 8e880af78e Choose background color and whether to draw mskp bounds in viewer
Default the background color to transparent black, which is correct for
mskps captures from Android framework.

Bug: skia:11900
Change-Id: I97cab04993c0f85259e831f3d0c44f9b962365af
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/403077
Reviewed-by: Nathaniel Nifong <nifong@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
2021-04-30 19:33:49 +00:00

147 lines
5.0 KiB
C++

/*
* Copyright 2021 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "tools/viewer/MSKPSlide.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkStream.h"
#include "include/private/SkTPin.h"
#include "src/core/SkOSFile.h"
#include "imgui.h"
MSKPSlide::MSKPSlide(const SkString& name, const SkString& path)
: MSKPSlide(name, SkStream::MakeFromFile(path.c_str())) {}
MSKPSlide::MSKPSlide(const SkString& name, std::unique_ptr<SkStreamSeekable> stream)
: fStream(std::move(stream)) {
fName = name;
}
SkISize MSKPSlide::getDimensions() const {
return fPlayer ? fPlayer->maxDimensions() : SkISize{0, 0};
}
void MSKPSlide::draw(SkCanvas* canvas) {
if (!fPlayer) {
ImGui::Text("Could not read mskp file %s.\n", fName.c_str());
return;
}
ImGui::Begin("MSKP");
ImGui::BeginGroup();
// Play/Pause button
if (ImGui::Button(fPaused ? "Play " : "Pause")) {
fPaused = !fPaused;
if (fPaused) {
// This will ensure that when playback is unpaused we start on the current frame.
fLastFrameTime = -1;
}
}
// Control the frame rate of MSKP playback
ImGui::Text("FPS: "); ImGui::SameLine();
ImGui::RadioButton( "1", &fFPS, 1); ImGui::SameLine();
ImGui::RadioButton( "15", &fFPS, 15); ImGui::SameLine();
ImGui::RadioButton( "30", &fFPS, 30); ImGui::SameLine();
ImGui::RadioButton( "60", &fFPS, 60); ImGui::SameLine();
ImGui::RadioButton("120", &fFPS, 120); ImGui::SameLine();
ImGui::RadioButton("1:1", &fFPS, -1); // Draw one MSKP frame for each real viewer frame.
if (fFPS < 0) {
// Like above, will cause onAnimate() to resume at current frame when FPS is changed
// back to another frame rate.
fLastFrameTime = -1;
}
// Frame control. Slider and +/- buttons. Ctrl-Click slider to type frame number.
ImGui::Text("Frame:");
ImGui::SameLine();
ImGui::PushButtonRepeat(true); // Enable click-and-hold for frame arrows.
if (ImGui::ArrowButton("-mksp_frame", ImGuiDir_Left)) {
fFrame = (fFrame + fPlayer->numFrames() - 1)%fPlayer->numFrames();
}
ImGui::SameLine();
if (ImGui::SliderInt("##msk_frameslider", &fFrame, 0, fPlayer->numFrames()-1, "% 3d")) {
fFrame = SkTPin(fFrame, 0, fPlayer->numFrames() - 1);
}
ImGui::SameLine();
if (ImGui::ArrowButton("+mskp_frame", ImGuiDir_Right)) {
fFrame = (fFrame + 1)%fPlayer->numFrames();
}
ImGui::PopButtonRepeat();
ImGui::EndGroup();
ImGui::BeginGroup();
ImGui::Checkbox("Show Frame Bounds", &fShowFrameBounds);
ImGui::SetNextItemWidth(200);
ImGui::ColorPicker4("background", fBackgroundColor, ImGuiColorEditFlags_AlphaBar);
// ImGui lets user enter out of range values by typing.
for (float& component : fBackgroundColor) {
component = SkTPin(component, 0.f, 1.f);
}
ImGui::EndGroup();
ImGui::End();
auto bounds = SkIRect::MakeSize(fPlayer->frameDimensions(fFrame));
if (fShowFrameBounds) {
SkPaint boundsPaint;
boundsPaint.setStyle(SkPaint::kStroke_Style);
boundsPaint.setColor(SK_ColorRED);
boundsPaint.setStrokeWidth(0.f);
boundsPaint.setAntiAlias(true);
// Outset so that at default scale we draw at pixel centers of the rows/cols surrounding the
// bounds.
canvas->drawRect(SkRect::Make(bounds).makeOutset(0.5f, 0.5f), boundsPaint);
}
canvas->save();
canvas->clipIRect(bounds);
canvas->clear(SkColor4f{fBackgroundColor[0],
fBackgroundColor[1],
fBackgroundColor[2],
fBackgroundColor[3]});
fPlayer->playFrame(canvas, fFrame);
canvas->restore();
}
bool MSKPSlide::animate(double nanos) {
if (!fPlayer || fPaused) {
return false;
}
if (fLastFrameTime < 0) {
// We're coming off being paused or switching from 1:1 mode to steady FPS. Advance 1 frame
// and reset the frame time to start accumulating time from now.
fFrame = (fFrame + 1)%fPlayer->numFrames();
fLastFrameTime = nanos;
return this->fPlayer->numFrames() > 1;
}
if (fFPS < 0) {
// 1:1 mode. Always draw the next frame on each animation cycle.
fFrame = (fFrame + 1)%fPlayer->numFrames();
return this->fPlayer->numFrames() > 1;
}
double elapsed = nanos - fLastFrameTime;
double frameTime = 1E9/fFPS;
int framesToAdvance = elapsed/frameTime;
fFrame = (fFrame + framesToAdvance)%fPlayer->numFrames();
// Instead of just adding elapsed, note the time when this frame should have begun.
fLastFrameTime += framesToAdvance*frameTime;
return framesToAdvance%fPlayer->numFrames() != 0;
}
void MSKPSlide::load(SkScalar, SkScalar) {
if (!fStream) {
return;
}
fStream->rewind();
fPlayer = MSKPPlayer::Make(fStream.get());
}
void MSKPSlide::unload() { fPlayer.reset(); }
void MSKPSlide::gpuTeardown() { fPlayer->resetLayers(); }