1 /*
2 * Copyright 2022 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 "src/gpu/graphite/TextureUtils.h"
9
10 #include "include/core/SkBitmap.h"
11 #include "src/core/SkMipmap.h"
12
13 #include "include/gpu/graphite/Context.h"
14 #include "include/gpu/graphite/GraphiteTypes.h"
15 #include "include/gpu/graphite/Recorder.h"
16 #include "include/gpu/graphite/Recording.h"
17 #include "src/gpu/graphite/Buffer.h"
18 #include "src/gpu/graphite/Caps.h"
19 #include "src/gpu/graphite/CommandBuffer.h"
20 #include "src/gpu/graphite/CopyTask.h"
21 #include "src/gpu/graphite/Image_Graphite.h"
22 #include "src/gpu/graphite/Log.h"
23 #include "src/gpu/graphite/RecorderPriv.h"
24 #include "src/gpu/graphite/ResourceProvider.h"
25 #include "src/gpu/graphite/SynchronizeToCpuTask.h"
26 #include "src/gpu/graphite/Texture.h"
27 #include "src/gpu/graphite/UploadTask.h"
28
29 namespace skgpu::graphite {
30
MakeBitmapProxyView(Recorder * recorder,const SkBitmap & bitmap,sk_sp<SkMipmap> mipmapsIn,Mipmapped mipmapped,skgpu::Budgeted budgeted)31 std::tuple<TextureProxyView, SkColorType> MakeBitmapProxyView(Recorder* recorder,
32 const SkBitmap& bitmap,
33 sk_sp<SkMipmap> mipmapsIn,
34 Mipmapped mipmapped,
35 skgpu::Budgeted budgeted) {
36 // Adjust params based on input and Caps
37 const skgpu::graphite::Caps* caps = recorder->priv().caps();
38 SkColorType ct = bitmap.info().colorType();
39
40 if (bitmap.dimensions().area() <= 1) {
41 mipmapped = Mipmapped::kNo;
42 }
43
44 auto textureInfo = caps->getDefaultSampledTextureInfo(ct, mipmapped, Protected::kNo,
45 Renderable::kNo);
46 if (!textureInfo.isValid()) {
47 ct = kRGBA_8888_SkColorType;
48 textureInfo = caps->getDefaultSampledTextureInfo(ct, mipmapped, Protected::kNo,
49 Renderable::kNo);
50 }
51 SkASSERT(textureInfo.isValid());
52
53 // Convert bitmap to texture colortype if necessary
54 SkBitmap bmpToUpload;
55 if (ct != bitmap.info().colorType()) {
56 if (!bmpToUpload.tryAllocPixels(bitmap.info().makeColorType(ct)) ||
57 !bitmap.readPixels(bmpToUpload.pixmap())) {
58 return {};
59 }
60 bmpToUpload.setImmutable();
61 } else {
62 bmpToUpload = bitmap;
63 }
64
65 if (!SkImageInfoIsValid(bmpToUpload.info())) {
66 return {};
67 }
68
69 int mipLevelCount = (mipmapped == Mipmapped::kYes) ?
70 SkMipmap::ComputeLevelCount(bitmap.width(), bitmap.height()) + 1 : 1;
71
72
73 // setup MipLevels
74 sk_sp<SkMipmap> mipmaps;
75 std::vector<MipLevel> texels;
76 if (mipLevelCount == 1) {
77 texels.resize(mipLevelCount);
78 texels[0].fPixels = bmpToUpload.getPixels();
79 texels[0].fRowBytes = bmpToUpload.rowBytes();
80 } else {
81 mipmaps = SkToBool(mipmapsIn) ? mipmapsIn
82 : sk_ref_sp(SkMipmap::Build(bmpToUpload.pixmap(), nullptr));
83 if (!mipmaps) {
84 return {};
85 }
86
87 SkASSERT(mipLevelCount == mipmaps->countLevels() + 1);
88 texels.resize(mipLevelCount);
89
90 texels[0].fPixels = bmpToUpload.getPixels();
91 texels[0].fRowBytes = bmpToUpload.rowBytes();
92
93 for (int i = 1; i < mipLevelCount; ++i) {
94 SkMipmap::Level generatedMipLevel;
95 mipmaps->getLevel(i - 1, &generatedMipLevel);
96 texels[i].fPixels = generatedMipLevel.fPixmap.addr();
97 texels[i].fRowBytes = generatedMipLevel.fPixmap.rowBytes();
98 SkASSERT(texels[i].fPixels);
99 SkASSERT(generatedMipLevel.fPixmap.colorType() == bmpToUpload.colorType());
100 }
101 }
102
103 // Create proxy
104 sk_sp<TextureProxy> proxy(new TextureProxy(bmpToUpload.dimensions(), textureInfo, budgeted));
105 if (!proxy) {
106 return {};
107 }
108 SkASSERT(caps->areColorTypeAndTextureInfoCompatible(ct, proxy->textureInfo()));
109 SkASSERT(mipmapped == Mipmapped::kNo || proxy->mipmapped() == Mipmapped::kYes);
110
111 // Src and dst colorInfo are the same
112 const SkColorInfo& colorInfo = bmpToUpload.info().colorInfo();
113 // Add UploadTask to Recorder
114 UploadInstance upload = UploadInstance::Make(
115 recorder, proxy, colorInfo, colorInfo, texels,
116 SkIRect::MakeSize(bmpToUpload.dimensions()), nullptr);
117 if (!upload.isValid()) {
118 SKGPU_LOG_E("MakeBitmapProxyView: Could not create UploadInstance");
119 return {};
120 }
121 recorder->priv().add(UploadTask::Make(std::move(upload)));
122
123 Swizzle swizzle = caps->getReadSwizzle(ct, textureInfo);
124 // If the color type is alpha-only, propagate the alpha value to the other channels.
125 if (colorInfo.colorType() == kAlpha_8_SkColorType) {
126 swizzle = Swizzle::Concat(swizzle, Swizzle("aaaa"));
127 }
128 return {{std::move(proxy), swizzle}, ct};
129 }
130
MakeFromBitmap(Recorder * recorder,const SkColorInfo & colorInfo,const SkBitmap & bitmap,sk_sp<SkMipmap> mipmaps,skgpu::Budgeted budgeted,SkImage::RequiredImageProperties requiredProps)131 sk_sp<SkImage> MakeFromBitmap(Recorder* recorder,
132 const SkColorInfo& colorInfo,
133 const SkBitmap& bitmap,
134 sk_sp<SkMipmap> mipmaps,
135 skgpu::Budgeted budgeted,
136 SkImage::RequiredImageProperties requiredProps) {
137 auto [ view, ct ] = MakeBitmapProxyView(recorder, bitmap, std::move(mipmaps),
138 requiredProps.fMipmapped, budgeted);
139 if (!view) {
140 return nullptr;
141 }
142
143 SkASSERT(requiredProps.fMipmapped == skgpu::Mipmapped::kNo ||
144 view.proxy()->mipmapped() == skgpu::Mipmapped::kYes);
145 return sk_make_sp<skgpu::graphite::Image>(std::move(view),
146 colorInfo.makeColorType(ct));
147 }
148
149 } // namespace skgpu::graphite
150