Use manual mipmaps to improve image draw performance

This commit is contained in:
Yousef Khadadeh 2026-02-16 18:19:17 +03:00
parent ddface1de6
commit 9216be3b7c
2 changed files with 33 additions and 3 deletions

View file

@ -11,6 +11,13 @@
#include "../MainProgram.hpp"
#include <Helpers/Logger.hpp>
#ifdef USE_SKIA_BACKEND_GRAPHITE
#include <include/gpu/graphite/Surface.h>
#elif USE_SKIA_BACKEND_GANESH
#include <include/gpu/ganesh/GrDirectContext.h>
#include <include/gpu/ganesh/SkSurfaceGanesh.h>
#endif
std::array<const SkCodecs::Decoder, 7> decoders = {
SkBmpDecoder::Decoder(),
SkGifDecoder::Decoder(),
@ -34,7 +41,7 @@ void ImageResourceDisplay::load_thread() {
frameTime = frameInfo.fDuration;
auto decodeResult = codec->getImage(imageInfo, &imageOptions);
if(std::get<1>(decodeResult) == SkCodec::Result::kSuccess)
frames[i] = {std::get<0>(decodeResult)->withDefaultMipmaps(), frameTime};
frames[i] = {std::get<0>(decodeResult), frameTime};
else {
Logger::get().log("WORLDFATAL", "Could not decode image, got error code " + std::to_string(std::get<1>(decodeResult)) + ". Image has dimensions " + std::to_string(imageInfo.width()) + " " + std::to_string(imageInfo.height()));
break;
@ -107,8 +114,30 @@ bool ImageResourceDisplay::load(ResourceManager& rMan, const std::string& fileNa
void ImageResourceDisplay::draw(SkCanvas* canvas, const DrawData& drawData, const SkRect& imRect) {
if(loadedFrames == 0)
canvas->drawRect(imRect, SkPaint({0.5f, 0.5f, 0.5f, 0.5f}));
else
canvas->drawImageRect(frames[frameIndex].data, imRect, {SkFilterMode::kLinear, SkMipmapMode::kLinear});
else {
SkRect imRectPixelSize = canvas->getLocalToDeviceAs3x3().mapRect(imRect);
float imWidth = std::max(imRectPixelSize.width(), 32.0f);
unsigned divisionLevel = imageInfo.width() / imWidth;
auto& frame = frames[frameIndex];
if(divisionLevel <= 1)
canvas->drawImageRect(frame.data, imRect, {SkFilterMode::kLinear, SkMipmapMode::kNone});
else {
unsigned mipmapLevel = std::log2(divisionLevel);
auto mipmapIt = frame.mipmapLevels.find(mipmapLevel);
if(mipmapIt == frame.mipmapLevels.end()) {
unsigned divideResolutionBy = std::exp2(mipmapLevel);
SkISize mipmapResolution(imageInfo.width() / divideResolutionBy, imageInfo.height() / divideResolutionBy);
SkImageInfo mipmapImgInfo = imageInfo.makeDimensions(mipmapResolution);
sk_sp<SkImage> mipmapImage = frame.data->makeScaled(mipmapImgInfo, SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNone));
frame.mipmapLevels.emplace(mipmapLevel, mipmapImage);
canvas->drawImageRect(mipmapImage, imRect, {SkFilterMode::kLinear, SkMipmapMode::kNone});
}
else
canvas->drawImageRect(mipmapIt->second, imRect, {SkFilterMode::kLinear, SkMipmapMode::kNone});
}
}
}
Vector2f ImageResourceDisplay::get_dimensions() const {

View file

@ -19,6 +19,7 @@ class ImageResourceDisplay : public ResourceDisplay {
struct FrameData {
sk_sp<SkImage> data;
float duration;
std::unordered_map<unsigned, sk_sp<SkImage>> mipmapLevels;
};
std::vector<FrameData> frames;