Add helper functions make_shader(), make_skimage/skcanvas_for_docimage()

These functions can be used to create a new Skia shader from SkSL
code, and a new SkImage/SkCanvas to modify a doc::Image*
This commit is contained in:
David Capello 2024-03-11 10:34:05 -03:00
parent 50d4f9d802
commit b8514ad1c6
4 changed files with 127 additions and 48 deletions

View File

@ -699,6 +699,7 @@ add_library(app-lib
util/range_utils.cpp
util/readable_time.cpp
util/resize_image.cpp
util/shader_helpers.cpp
util/tile_flags_utils.cpp
util/tileset_utils.cpp
util/wrap_point.cpp

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2022-2023 Igara Studio S.A.
// Copyright (C) 2022-2024 Igara Studio S.A.
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
@ -87,19 +87,9 @@ ShaderRenderer::ShaderRenderer()
m_properties.renderBgOnScreen = true;
m_properties.requiresRgbaBackbuffer = true;
auto makeShader = [](const char* code) {
auto result = SkRuntimeEffect::MakeForShader(SkString(code));
if (!result.errorText.isEmpty()) {
LOG(ERROR, "Shader error: %s\n", result.errorText.c_str());
std::printf("Shader error: %s\n", result.errorText.c_str());
throw std::runtime_error("Cannot compile shaders for ShaderRenderer");
}
return result;
};
m_bgEffect = makeShader(kBgShaderCode).effect;
m_indexedEffect = makeShader(kIndexedShaderCode).effect;
m_grayscaleEffect = makeShader(kGrayscaleShaderCode).effect;
m_bgEffect = make_shader(kBgShaderCode);
m_indexedEffect = make_shader(kIndexedShaderCode);
m_grayscaleEffect = make_shader(kGrayscaleShaderCode);
}
ShaderRenderer::~ShaderRenderer() = default;
@ -416,21 +406,11 @@ void ShaderRenderer::drawImage(SkCanvas* canvas,
const int opacity,
const doc::BlendMode blendMode)
{
auto skData = SkData::MakeWithoutCopy(
(const void*)srcImage->getPixelAddress(0, 0),
srcImage->rowBytes() * srcImage->height());
auto skImg = make_skimage_for_docimage(srcImage);
switch (srcImage->colorMode()) {
case doc::ColorMode::RGB: {
auto skImg = SkImage::MakeRasterData(
SkImageInfo::Make(srcImage->width(),
srcImage->height(),
kRGBA_8888_SkColorType,
kUnpremul_SkAlphaType),
skData,
srcImage->rowBytes());
SkPaint p;
p.setAlpha(opacity);
p.setBlendMode(to_skia(blendMode));
@ -443,15 +423,6 @@ void ShaderRenderer::drawImage(SkCanvas* canvas,
}
case doc::ColorMode::GRAYSCALE: {
// We use kR8G8_unorm_SkColorType to access gray and alpha
auto skImg = SkImage::MakeRasterData(
SkImageInfo::Make(srcImage->width(),
srcImage->height(),
kR8G8_unorm_SkColorType,
kOpaque_SkAlphaType),
skData,
srcImage->rowBytes());
SkRuntimeShaderBuilder builder(m_grayscaleEffect);
builder.child("iImg") = skImg->makeRawShader(SkSamplingOptions(SkFilterMode::kNearest));
@ -471,15 +442,6 @@ void ShaderRenderer::drawImage(SkCanvas* canvas,
}
case doc::ColorMode::INDEXED: {
// We use kAlpha_8_SkColorType to access to the index value through the alpha channel
auto skImg = SkImage::MakeRasterData(
SkImageInfo::Make(srcImage->width(),
srcImage->height(),
kAlpha_8_SkColorType,
kUnpremul_SkAlphaType),
skData,
srcImage->rowBytes());
// Use the palette data as an "width x height" image where
// width=number of palette colors, and height=1
const size_t palSize = sizeof(color_t) * m_palette.size();

View File

@ -0,0 +1,94 @@
// Aseprite
// Copyright (C) 2024 Igara Studio S.A.
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#if SK_ENABLE_SKSL
#include "app/util/shader_helpers.h"
#include "base/exception.h"
#include "doc/image.h"
#include "fmt/format.h"
#include "include/effects/SkRuntimeEffect.h"
namespace app {
sk_sp<SkRuntimeEffect> make_shader(const char* code)
{
auto result = SkRuntimeEffect::MakeForShader(SkString(code));
if (!result.errorText.isEmpty()) {
std::string error = fmt::format("Error compiling shader.\nError: {}\n",
result.errorText.c_str());
LOG(ERROR, error.c_str());
std::printf("%s", error.c_str());
throw base::Exception(error);
}
return result.effect;
}
SkImageInfo get_skimageinfo_for_docimage(const doc::Image* img)
{
switch (img->colorMode()) {
case doc::ColorMode::RGB:
return SkImageInfo::Make(img->width(),
img->height(),
kRGBA_8888_SkColorType,
kUnpremul_SkAlphaType);
case doc::ColorMode::GRAYSCALE:
// We use kR8G8_unorm_SkColorType to access gray and alpha
return SkImageInfo::Make(img->width(),
img->height(),
kR8G8_unorm_SkColorType,
kOpaque_SkAlphaType);
case doc::ColorMode::INDEXED: {
// We use kAlpha_8_SkColorType to access to the index value through the alpha channel
return SkImageInfo::Make(img->width(),
img->height(),
kAlpha_8_SkColorType,
kUnpremul_SkAlphaType);
}
}
return SkImageInfo();
}
sk_sp<SkImage> make_skimage_for_docimage(const doc::Image* img)
{
switch (img->colorMode()) {
case doc::ColorMode::RGB:
case doc::ColorMode::GRAYSCALE:
case doc::ColorMode::INDEXED: {
auto skData = SkData::MakeWithoutCopy(
(const void*)img->getPixelAddress(0, 0),
img->rowBytes() * img->height());
return SkImage::MakeRasterData(
get_skimageinfo_for_docimage(img),
skData,
img->rowBytes());
}
}
return nullptr;
}
std::unique_ptr<SkCanvas> make_skcanvas_for_docimage(const doc::Image* img)
{
return SkCanvas::MakeRasterDirect(
get_skimageinfo_for_docimage(img),
(void*)img->getPixelAddress(0, 0),
img->rowBytes());
}
} // namespace app
#endif // SK_ENABLE_SKSL

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2022 Igara Studio S.A.
// Copyright (C) 2022-2024 Igara Studio S.A.
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
@ -8,18 +8,32 @@
#define APP_UTIL_SHADER_HELPERS_H_INCLUDED
#pragma once
#if SK_ENABLE_SKSL
#if LAF_SKIA
#include "app/color.h"
#include "gfx/color.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkImage.h"
#include "include/core/SkM44.h"
#include "include/core/SkRefCnt.h"
// To include kRGB_to_HSL_sksl and kHSL_to_RGB_sksl
#include "src/core/SkRuntimeEffectPriv.h"
#if SK_ENABLE_SKSL
#include "include/effects/SkRuntimeEffect.h"
// To include kRGB_to_HSL_sksl and kHSL_to_RGB_sksl
#include "src/core/SkRuntimeEffectPriv.h"
#endif
#include <memory>
namespace doc {
class Image;
}
namespace app {
#if SK_ENABLE_SKSL
// rgb_to_hsl() and hsv_to_hsl() functions by Sam Hocevar licensed
// under WTFPL (https://en.wikipedia.org/wiki/WTFPL)
// Source:
@ -74,8 +88,16 @@ inline SkV4 appColorHsl_to_SkV4(const app::Color& color) {
float(color.getAlpha() / 255.0)};
}
sk_sp<SkRuntimeEffect> make_shader(const char* code);
#endif // SK_ENABLE_SKSL
SkImageInfo get_skimageinfo_for_docimage(const doc::Image* img);
sk_sp<SkImage> make_skimage_for_docimage(const doc::Image* img);
std::unique_ptr<SkCanvas> make_skcanvas_for_docimage(const doc::Image* img);
} // namespace app
#endif
#endif // LAF_SKIA
#endif