blob: 7783099109b406eb33a75400e0911f476fc08e2c [file] [log] [blame] [edit]
/*
* Copyright 2025 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "include/core/SkBitmap.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkImage.h"
#include "include/core/SkImageInfo.h"
#include "include/core/SkMatrix.h"
#include "include/core/SkPaint.h"
#include "include/effects/SkGradientShader.h"
#include "include/private/base/SkAssert.h"
#include "src/base/SkArenaAlloc.h"
#include "src/core/SkBlitter.h"
#include "src/core/SkCoreBlitters.h"
#include "src/core/SkRasterPipelineOpList.h"
#include "src/core/SkRasterPipelineVizualizer.h"
#include "tools/viewer/ClickHandlerSlide.h"
#include "tools/viewer/Slide.h"
#include <vector>
static constexpr float kPanelSize = 100.f;
static constexpr float kPadding = 10.f;
static constexpr float kBorder = 2.f;
static constexpr float kHandleRadius = 3.f;
static SkBitmap make_panel() {
SkBitmap panel;
panel.setInfo(SkImageInfo::Make(kPanelSize, kPanelSize,
kRGBA_8888_SkColorType, kOpaque_SkAlphaType));
panel.allocPixels();
panel.eraseColor(SK_ColorBLACK);
return panel;
}
class RPVizSlide : public ClickHandlerSlide {
public:
RPVizSlide() { fName = "RasterPipelineViz"; }
void draw(SkCanvas* canvas) override {
canvas->clear(SK_ColorWHITE);
SkPaint paint;
paint.setColor(SK_ColorRED);
// paint.setMaskFilter(SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, 1.0));
SkColor colors[] = {
SkColorSetRGB(0xE4, 0x03, 0x03), // Red
SkColorSetRGB(0xFF, 0x8C, 0x00), // Orange
SkColorSetRGB(0xFF, 0xED, 0x00), // Yellow
SkColorSetRGB(0x00, 0x80, 0x26), // Green
SkColorSetRGB(0x00, 0x4D, 0xFF), // Blue
SkColorSetRGB(0x75, 0x07, 0x87) // Violet
};
SkPoint points[] = {
{fStartDX, fStartDY},
{fEndX, fEndY},
};
auto shader = SkGradientShader::MakeLinear(
points, colors, nullptr, std::size(colors), SkTileMode::kClamp);
paint.setShader(shader);
paint.setBlendMode(SkBlendMode::kSrc);
SkBitmap dst;
dst.setInfo(SkImageInfo::Make(
kPanelSize, kPanelSize, kRGBA_8888_SkColorType, kOpaque_SkAlphaType));
dst.allocPixels();
dst.eraseColor(SK_ColorBLACK);
// Suggested flow for customizing this (or making your own)
// 1) Create a shader of interest and put it into a paint.
// 2) Use SkRasterPipelineVisualizer::DebugStageBuilder to create an *empty* list of stages.
// 3) Call SkRasterPipelineVisualizer::CreateBlitter and check stdout for a dump
// of the stages (and it will assert).
// 4) With SkRasterPipeline_opts.h as a reference, add one or more entries for each stage
// to pick out the "interesting" lanes.
// 5) Re-compile and run. Modify stages to taste.
SkRasterPipelineVisualizer::DebugStageBuilder stageBuilder;
stageBuilder
.add(make_panel(), SkRasterPipelineOp::debug_x,
make_panel(), SkRasterPipelineOp::debug_y)
.add(make_panel(), SkRasterPipelineOp::debug_x)
.add(make_panel(), SkRasterPipelineOp::debug_x)
.add(make_panel(), SkRasterPipelineOp::debug_r_255,
make_panel(), SkRasterPipelineOp::debug_g_255,
make_panel(), SkRasterPipelineOp::debug_b_255,
make_panel(), SkRasterPipelineOp::debug_a_255);
std::vector<SkRasterPipelineVisualizer::DebugStage> stages = stageBuilder.build();
static constexpr size_t kStackMemory = 1024; // arbitrary
SkSTArenaAlloc<kStackMemory> alloc;
auto blitter = SkRasterPipelineVisualizer::CreateBlitter(
dst.pixmap(), stages, paint, SkMatrix::I(), &alloc, nullptr, {});
blitter->blitRect(0, 0, kPanelSize, kPanelSize);
SkPaint panelBackdrop;
panelBackdrop.setColor(SK_ColorGRAY);
panelBackdrop.setStyle(SkPaint::Style::kFill_Style);
for (size_t row = 0; row < stages.size(); row++) {
for (size_t col = 0; col < stages[row].panels.size(); col++) {
float x = (kPanelSize + kPadding) * col + kPadding;
float y = (kPanelSize + kPadding) * row + kPadding;
canvas->drawRect(SkRect::MakeXYWH(x - kBorder,
y - kBorder,
kPanelSize + 2 * kBorder,
kPanelSize + 2 * kBorder),
panelBackdrop);
auto panelImg = SkImages::RasterFromBitmap(stages[row].panels[col]);
canvas->drawImage(panelImg, x, y);
}
}
// Draw the output
auto dstImg = SkImages::RasterFromBitmap(dst);
fOutputCornerX = kPadding;
fOutputCornerY = (kPanelSize + kPadding) * stages.size() + kPadding;
canvas->drawImage(dstImg, fOutputCornerX, fOutputCornerY);
// Draw the handles
SkPaint handlePaint;
handlePaint.setAntiAlias(true);
handlePaint.setStrokeWidth(2);
handlePaint.setStyle(SkPaint::Style::kStroke_Style);
canvas->drawCircle(
fOutputCornerX + fStartDX, fOutputCornerY + fStartDY, kHandleRadius, handlePaint);
canvas->drawCircle(
fOutputCornerX + fEndX, fOutputCornerY + fEndY, kHandleRadius, handlePaint);
}
private:
class Click : public ClickHandlerSlide::Click {
public:
Click(float* x, float* y) : fX(x), fY(y) {}
void doClick(RPVizSlide* that) {
float newX = SkTPin(fCurr.fX - that->fOutputCornerX, 0.f, kPanelSize);
float newY = SkTPin(fCurr.fY - that->fOutputCornerY, 0.f, kPanelSize);
*fX = newX;
*fY = newY;
}
private:
float* fX;
float* fY;
};
Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey) override {
SkPoint start{fOutputCornerX + fStartDX, fOutputCornerY + fStartDY};
SkPoint end{fOutputCornerX + fEndX, fOutputCornerY + fEndY};
SkPoint click{x, y};
if (SkPoint::Distance(start, click) < SkPoint::Distance(end, click)) {
return new Click(&fStartDX, &fStartDY);
}
return new Click(&fEndX, &fEndY);
}
bool onClick(ClickHandlerSlide::Click* click) override {
Click* myClick = (Click*)click;
myClick->doClick(this);
return true;
}
float fOutputCornerX = 0.f;
float fOutputCornerY = 0.f;
float fStartDX = 5.f;
float fStartDY = 5.f;
float fEndX = 95.f;
float fEndY = 95.f;
};
DEF_SLIDE(return new RPVizSlide();)