blob: d74ea1eb091bd04320565849edfe174664243c71 [file]
/*
* Copyright 2026 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "bench/Benchmark.h"
#include "include/core/SkString.h"
#include "include/private/SkAlign.h"
#include "src/core/SkRasterPipeline.h"
#include "src/core/SkRasterPipelineOpContexts.h"
#include "src/core/SkRasterPipelineOpList.h"
#include <memory>
template <typename T>
static T* allocate_and_align(std::unique_ptr<char[]>& storage, size_t sizeInBytes) {
// Align to 64 bytes (critical for AVX-512 in SkRasterPipeline).
// The initial allocation might not be 64-byte aligned, so we allocate extra padding
// and find the next address in our buffer that is a multiple of 64.
storage.reset(new char[sizeInBytes + 64]);
return reinterpret_cast<T*>(
SkAlignTo(reinterpret_cast<uintptr_t>(storage.get()), (uintptr_t)64));
}
class SkRPDivBench : public Benchmark {
public:
enum class Type { kInt, kUint };
SkRPDivBench(Type type, int slots) : fType(type), fSlots(slots) {
fName.printf("skrp_div_%s_%d", fType == Type::kInt ? "int" : "uint", fSlots);
fData = allocate_and_align<int32_t>(fStorage, 1024 * sizeof(int32_t));
// Initialize the data we are dividing by so it's non-zero (avoiding any special casing).
for (int i = 0; i < 1024; i++) {
fData[i] = i + 1;
}
}
protected:
const char* onGetName() override { return fName.c_str(); }
bool isSuitableFor(Backend backend) override { return backend == Backend::kNonRendering; }
void onDraw(int loops, SkCanvas*) override {
SkArenaAlloc alloc(1024);
SkRasterPipeline p(&alloc);
SkRasterPipelineOp op;
if (fType == Type::kInt) {
switch (fSlots) {
case 1: op = SkRasterPipelineOp::div_int; break;
case 4: op = SkRasterPipelineOp::div_4_ints; break;
default: SkUNREACHABLE;
}
} else {
switch (fSlots) {
case 1: op = SkRasterPipelineOp::div_uint; break;
case 4: op = SkRasterPipelineOp::div_4_uints; break;
default: SkUNREACHABLE;
}
}
p.append(op, fData);
for (int i = 0; i < loops; i++) {
p.run(0, 0, 128, 1);
}
}
private:
Type fType;
int fSlots;
SkString fName;
std::unique_ptr<char[]> fStorage;
int32_t* fData = nullptr;
};
class SkRPGatherBench : public Benchmark {
public:
enum class Format { k8888, k565, kRG88 };
SkRPGatherBench(Format format) : fFormat(format) {
switch (fFormat) {
case Format::k8888: fName.printf("skrp_gather_8888"); break;
case Format::k565: fName.printf("skrp_gather_565"); break;
case Format::kRG88: fName.printf("skrp_gather_rg88"); break;
}
// Allocate and initialize pixels
fPixels.reset(new uint32_t[128 * 128]);
for (int i = 0; i < 128 * 128; i++) {
fPixels[i] = 0xFFFFFFFF;
}
fCtx = allocate_and_align<SkRasterPipelineContexts::GatherCtx>(
fStorage, sizeof(SkRasterPipelineContexts::GatherCtx));
fCtx->pixels = fPixels.get();
fCtx->stride = 128;
fCtx->width = 128.0f;
fCtx->height = 128.0f;
fCtx->roundDownAtInteger = false;
}
protected:
const char* onGetName() override { return fName.c_str(); }
bool isSuitableFor(Backend backend) override { return backend == Backend::kNonRendering; }
void onDraw(int loops, SkCanvas*) override {
SkArenaAlloc alloc(1024);
SkRasterPipeline p(&alloc);
p.append(SkRasterPipelineOp::seed_shader);
SkRasterPipelineOp op;
switch (fFormat) {
case Format::k8888: op = SkRasterPipelineOp::gather_8888; break;
case Format::k565: op = SkRasterPipelineOp::gather_565; break;
case Format::kRG88: op = SkRasterPipelineOp::gather_rg88; break;
}
p.append(op, fCtx);
for (int i = 0; i < loops; i++) {
p.run(0, 0, 128, 1);
}
}
private:
Format fFormat;
SkString fName;
std::unique_ptr<uint32_t[]> fPixels;
std::unique_ptr<char[]> fStorage;
SkRasterPipelineContexts::GatherCtx* fCtx = nullptr;
};
DEF_BENCH(return new SkRPDivBench(SkRPDivBench::Type::kInt, 1);)
DEF_BENCH(return new SkRPDivBench(SkRPDivBench::Type::kInt, 4);)
DEF_BENCH(return new SkRPDivBench(SkRPDivBench::Type::kUint, 1);)
DEF_BENCH(return new SkRPDivBench(SkRPDivBench::Type::kUint, 4);)
DEF_BENCH(return new SkRPGatherBench(SkRPGatherBench::Format::k8888);)
DEF_BENCH(return new SkRPGatherBench(SkRPGatherBench::Format::k565);)
DEF_BENCH(return new SkRPGatherBench(SkRPGatherBench::Format::kRG88);)