Coverage Report

Created: 2024-05-20 07:14

/src/skia/tools/GpuToolUtils.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2023 Google LLC
3
 *
4
 * Use of this source code is governed by a BSD-style license that can be
5
 * found in the LICENSE file.
6
 */
7
8
#include "tools/GpuToolUtils.h"
9
10
#include "include/core/SkCanvas.h"
11
#include "include/core/SkImage.h"
12
13
#if defined(SK_GANESH)
14
#include "include/gpu/GrDirectContext.h"
15
#include "include/gpu/GrRecordingContext.h"
16
#include "include/gpu/ganesh/SkImageGanesh.h"
17
#include "src/gpu/ganesh/GrCaps.h"
18
#include "src/gpu/ganesh/GrDirectContextPriv.h"
19
#endif
20
21
#if defined(SK_GRAPHITE)
22
#include "include/core/SkTiledImageUtils.h"
23
#include "include/gpu/graphite/Image.h"
24
#include "include/gpu/graphite/ImageProvider.h"
25
#include "include/gpu/graphite/Recorder.h"
26
#include "src/core/SkLRUCache.h"
27
#endif
28
29
30
namespace ToolUtils {
31
32
0
sk_sp<SkImage> MakeTextureImage(SkCanvas* canvas, sk_sp<SkImage> orig) {
33
0
    if (!orig) {
34
0
        return nullptr;
35
0
    }
36
37
0
#if defined(SK_GANESH)
38
0
    if (canvas->recordingContext() && canvas->recordingContext()->asDirectContext()) {
39
0
        GrDirectContext* dContext = canvas->recordingContext()->asDirectContext();
40
0
        const GrCaps* caps = dContext->priv().caps();
41
42
0
        if (orig->width() >= caps->maxTextureSize() || orig->height() >= caps->maxTextureSize()) {
43
            // Ganesh is able to tile large SkImage draws. Always forcing SkImages to be uploaded
44
            // prevents this feature from being tested by our tools. For now, leave excessively
45
            // large SkImages as bitmaps.
46
0
            return orig;
47
0
        }
48
49
0
        return SkImages::TextureFromImage(dContext, orig);
50
0
    }
51
0
#endif
52
0
#if defined(SK_GRAPHITE)
53
0
    if (canvas->recorder()) {
54
0
        return SkImages::TextureFromImage(canvas->recorder(), orig, {false});
55
0
    }
56
0
#endif
57
0
    return orig;
58
0
}
59
60
#if defined(SK_GRAPHITE)
61
62
// Currently, we give each new Recorder its own ImageProvider. This means we don't have to deal
63
// w/ any threading issues.
64
// TODO: We should probably have this class generate and report some cache stats
65
// TODO: Hook up to listener system?
66
// TODO: add testing of a single ImageProvider passed to multiple recorders
67
class TestingImageProvider : public skgpu::graphite::ImageProvider {
68
public:
69
0
    TestingImageProvider() : fCache(kDefaultNumCachedImages) {}
70
0
    ~TestingImageProvider() override {}
71
72
    sk_sp<SkImage> findOrCreate(skgpu::graphite::Recorder* recorder,
73
                                const SkImage* image,
74
0
                                SkImage::RequiredProperties requiredProps) override {
75
0
        if (!requiredProps.fMipmapped) {
76
            // If no mipmaps are required, check to see if we have a mipmapped version anyway -
77
            // since it can be used in that case.
78
            // TODO: we could get fancy and, if ever a mipmapped key eclipsed a non-mipmapped
79
            // key, we could remove the hidden non-mipmapped key/image from the cache.
80
0
            ImageKey mipMappedKey(image, /* mipmapped= */ true);
81
0
            auto result = fCache.find(mipMappedKey);
82
0
            if (result) {
83
0
                return *result;
84
0
            }
85
0
        }
86
87
0
        ImageKey key(image, requiredProps.fMipmapped);
88
89
0
        auto result = fCache.find(key);
90
0
        if (result) {
91
0
            return *result;
92
0
        }
93
94
0
        sk_sp<SkImage> newImage = SkImages::TextureFromImage(recorder, image, requiredProps);
95
0
        if (!newImage) {
96
0
            return nullptr;
97
0
        }
98
99
0
        result = fCache.insert(key, std::move(newImage));
100
0
        SkASSERT(result);
101
102
0
        return *result;
103
0
    }
Unexecuted instantiation: ToolUtils::TestingImageProvider::findOrCreate(skgpu::graphite::Recorder*, SkImage const*, SkImage::RequiredProperties)
Unexecuted instantiation: ToolUtils::TestingImageProvider::findOrCreate(skgpu::graphite::Recorder*, SkImage const*, SkImage::RequiredProperties)
104
105
private:
106
    static constexpr int kDefaultNumCachedImages = 256;
107
108
    class ImageKey {
109
    public:
110
0
        ImageKey(const SkImage* image, bool mipmapped) {
111
0
            uint32_t flags = mipmapped ? 0x1 : 0x0;
112
0
            SkTiledImageUtils::GetImageKeyValues(image, &fValues[1]);
113
0
            fValues[kNumValues-1] = flags;
114
0
            fValues[0] = SkChecksum::Hash32(&fValues[1], (kNumValues-1) * sizeof(uint32_t));
115
0
        }
116
117
0
        uint32_t hash() const { return fValues[0]; }
118
119
0
        bool operator==(const ImageKey& other) const {
120
0
            for (int i = 0; i < kNumValues; ++i) {
121
0
                if (fValues[i] != other.fValues[i]) {
122
0
                    return false;
123
0
                }
124
0
            }
125
126
0
            return true;
127
0
        }
128
0
        bool operator!=(const ImageKey& other) const { return !(*this == other); }
129
130
    private:
131
        static const int kNumValues = SkTiledImageUtils::kNumImageKeyValues + 2;
132
133
        uint32_t fValues[kNumValues];
134
    };
135
136
    struct ImageHash {
137
0
        size_t operator()(const ImageKey& key) const { return key.hash(); }
138
    };
139
140
    SkLRUCache<ImageKey, sk_sp<SkImage>, ImageHash> fCache;
141
};
142
143
0
skgpu::graphite::RecorderOptions CreateTestingRecorderOptions() {
144
0
    skgpu::graphite::RecorderOptions options;
145
146
0
    options.fImageProvider.reset(new TestingImageProvider);
147
148
0
    return options;
149
0
}
150
151
#endif // SK_GRAPHITE
152
153
}  // namespace ToolUtils