1 /*
2 * Copyright 2017 Google Inc.
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 "SkTypes.h"
9
10 #include "GrBackendSurface.h"
11 #include "GrBackendTextureImageGenerator.h"
12 #include "GrContext.h"
13 #include "GrContextPriv.h"
14 #include "GrGpu.h"
15 #include "GrRenderTargetContext.h"
16 #include "GrSemaphore.h"
17 #include "GrSurfaceProxyPriv.h"
18 #include "GrTexturePriv.h"
19 #include "GrTextureProxy.h"
20 #include "SkCanvas.h"
21 #include "SkImage_Base.h"
22 #include "SkGpuDevice.h"
23 #include "SkPoint.h"
24 #include "SkSurface.h"
25 #include "SkSurface_Gpu.h"
26 #include "Test.h"
27
28 static constexpr int kSize = 8;
29
30 // Test that the correct mip map states are on the GrTextures when wrapping GrBackendTextures in
31 // SkImages and SkSurfaces
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrWrappedMipMappedTest,reporter,ctxInfo)32 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrWrappedMipMappedTest, reporter, ctxInfo) {
33 GrContext* context = ctxInfo.grContext();
34 if (!context->contextPriv().caps()->mipMapSupport()) {
35 return;
36 }
37 GrGpu* gpu = context->contextPriv().getGpu();
38
39 for (auto mipMapped : {GrMipMapped::kNo, GrMipMapped::kYes}) {
40 for (auto isRT : {false, true}) {
41 // CreateTestingOnlyBackendTexture currently doesn't support uploading data to mip maps
42 // so we don't send any. However, we pretend there is data for the checks below which is
43 // fine since we are never actually using these textures for any work on the gpu.
44 GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture(
45 nullptr, kSize, kSize, GrColorType::kRGBA_8888, isRT, mipMapped);
46
47 sk_sp<GrTextureProxy> proxy;
48 sk_sp<SkImage> image;
49 if (isRT) {
50 sk_sp<SkSurface> surface = SkSurface::MakeFromBackendTexture(
51 context,
52 backendTex,
53 kTopLeft_GrSurfaceOrigin,
54 0,
55 kRGBA_8888_SkColorType,
56 nullptr,
57 nullptr);
58
59 SkGpuDevice* device = ((SkSurface_Gpu*)surface.get())->getDevice();
60 proxy = device->accessRenderTargetContext()->asTextureProxyRef();
61 } else {
62 image = SkImage::MakeFromTexture(context, backendTex,
63 kTopLeft_GrSurfaceOrigin,
64 kRGBA_8888_SkColorType,
65 kPremul_SkAlphaType, nullptr,
66 nullptr, nullptr);
67 proxy = as_IB(image)->asTextureProxyRef();
68 }
69 REPORTER_ASSERT(reporter, proxy);
70 if (!proxy) {
71 gpu->deleteTestingOnlyBackendTexture(backendTex);
72 return;
73 }
74
75 REPORTER_ASSERT(reporter, proxy->isInstantiated());
76
77 GrTexture* texture = proxy->peekTexture();
78 REPORTER_ASSERT(reporter, texture);
79 if (!texture) {
80 gpu->deleteTestingOnlyBackendTexture(backendTex);
81 return;
82 }
83
84 if (GrMipMapped::kYes == mipMapped) {
85 REPORTER_ASSERT(reporter, GrMipMapped::kYes == texture->texturePriv().mipMapped());
86 if (isRT) {
87 REPORTER_ASSERT(reporter, texture->texturePriv().mipMapsAreDirty());
88 } else {
89 REPORTER_ASSERT(reporter, !texture->texturePriv().mipMapsAreDirty());
90 }
91 } else {
92 REPORTER_ASSERT(reporter, GrMipMapped::kNo == texture->texturePriv().mipMapped());
93 }
94 gpu->deleteTestingOnlyBackendTexture(backendTex);
95 }
96 }
97 }
98
99 // Test that we correctly copy or don't copy GrBackendTextures in the GrBackendTextureImageGenerator
100 // based on if we will use mips in the draw and the mip status of the GrBackendTexture.
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrBackendTextureImageMipMappedTest,reporter,ctxInfo)101 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrBackendTextureImageMipMappedTest, reporter, ctxInfo) {
102 GrContext* context = ctxInfo.grContext();
103 if (!context->contextPriv().caps()->mipMapSupport()) {
104 return;
105 }
106 GrGpu* gpu = context->contextPriv().getGpu();
107
108 for (auto mipMapped : {GrMipMapped::kNo, GrMipMapped::kYes}) {
109 for (auto willUseMips : {false, true}) {
110 GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture(
111 nullptr, kSize, kSize, GrColorType::kRGBA_8888, false, mipMapped);
112
113 sk_sp<SkImage> image = SkImage::MakeFromTexture(context, backendTex,
114 kTopLeft_GrSurfaceOrigin,
115 kRGBA_8888_SkColorType,
116 kPremul_SkAlphaType, nullptr,
117 nullptr, nullptr);
118
119 GrTextureProxy* proxy = as_IB(image)->peekProxy();
120 REPORTER_ASSERT(reporter, proxy);
121 if (!proxy) {
122 gpu->deleteTestingOnlyBackendTexture(backendTex);
123 return;
124 }
125
126 REPORTER_ASSERT(reporter, proxy->isInstantiated());
127
128 sk_sp<GrTexture> texture = sk_ref_sp(proxy->peekTexture());
129 REPORTER_ASSERT(reporter, texture);
130 if (!texture) {
131 gpu->deleteTestingOnlyBackendTexture(backendTex);
132 return;
133 }
134
135 std::unique_ptr<SkImageGenerator> imageGen = GrBackendTextureImageGenerator::Make(
136 texture, kTopLeft_GrSurfaceOrigin, nullptr, kRGBA_8888_SkColorType,
137 kPremul_SkAlphaType, nullptr);
138 REPORTER_ASSERT(reporter, imageGen);
139 if (!imageGen) {
140 gpu->deleteTestingOnlyBackendTexture(backendTex);
141 return;
142 }
143
144 SkIPoint origin = SkIPoint::Make(0,0);
145 SkImageInfo imageInfo = SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType,
146 kPremul_SkAlphaType);
147 sk_sp<GrTextureProxy> genProxy = imageGen->generateTexture(context, imageInfo,
148 origin, willUseMips);
149
150 REPORTER_ASSERT(reporter, genProxy);
151 if (!genProxy) {
152 gpu->deleteTestingOnlyBackendTexture(backendTex);
153 return;
154 }
155
156 if (GrSurfaceProxy::LazyState::kNot != genProxy->lazyInstantiationState()) {
157 genProxy->priv().doLazyInstantiation(context->contextPriv().resourceProvider());
158 } else if (!genProxy->isInstantiated()) {
159 genProxy->instantiate(context->contextPriv().resourceProvider());
160 }
161
162 REPORTER_ASSERT(reporter, genProxy->isInstantiated());
163 if (!genProxy->isInstantiated()) {
164 gpu->deleteTestingOnlyBackendTexture(backendTex);
165 return;
166 }
167
168 GrTexture* genTexture = genProxy->peekTexture();
169 REPORTER_ASSERT(reporter, genTexture);
170 if (!genTexture) {
171 gpu->deleteTestingOnlyBackendTexture(backendTex);
172 return;
173 }
174
175 GrBackendTexture genBackendTex = genTexture->getBackendTexture();
176
177 if (GrBackendApi::kOpenGL == genBackendTex.backend()) {
178 GrGLTextureInfo genTexInfo;
179 GrGLTextureInfo origTexInfo;
180 if (genBackendTex.getGLTextureInfo(&genTexInfo) &&
181 backendTex.getGLTextureInfo(&origTexInfo)) {
182 if (willUseMips && GrMipMapped::kNo == mipMapped) {
183 // We did a copy so the texture IDs should be different
184 REPORTER_ASSERT(reporter, origTexInfo.fID != genTexInfo.fID);
185 } else {
186 REPORTER_ASSERT(reporter, origTexInfo.fID == genTexInfo.fID);
187 }
188 } else {
189 ERRORF(reporter, "Failed to get GrGLTextureInfo");
190 }
191 #ifdef SK_VULKAN
192 } else if (GrBackendApi::kVulkan == genBackendTex.backend()) {
193 GrVkImageInfo genImageInfo;
194 GrVkImageInfo origImageInfo;
195 if (genBackendTex.getVkImageInfo(&genImageInfo) &&
196 backendTex.getVkImageInfo(&origImageInfo)) {
197 if (willUseMips && GrMipMapped::kNo == mipMapped) {
198 // We did a copy so the texture IDs should be different
199 REPORTER_ASSERT(reporter, origImageInfo.fImage != genImageInfo.fImage);
200 } else {
201 REPORTER_ASSERT(reporter, origImageInfo.fImage == genImageInfo.fImage);
202 }
203 } else {
204 ERRORF(reporter, "Failed to get GrVkImageInfo");
205 }
206 #endif
207 } else {
208 REPORTER_ASSERT(reporter, false);
209 }
210
211 // Must make sure the uses of the backend texture have finished (we possibly have a
212 // queued up copy) before we delete the backend texture.
213 context->flush();
214 gpu->testingOnly_flushGpuAndSync();
215
216 gpu->deleteTestingOnlyBackendTexture(backendTex);
217 }
218 }
219 }
220
221 // Test that when we call makeImageSnapshot on an SkSurface we retains the same mip status as the
222 // resource we took the snapshot of.
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrImageSnapshotMipMappedTest,reporter,ctxInfo)223 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrImageSnapshotMipMappedTest, reporter, ctxInfo) {
224 GrContext* context = ctxInfo.grContext();
225 if (!context->contextPriv().caps()->mipMapSupport()) {
226 return;
227 }
228
229 auto resourceProvider = context->contextPriv().resourceProvider();
230 GrGpu* gpu = context->contextPriv().getGpu();
231
232 for (auto willUseMips : {false, true}) {
233 for (auto isWrapped : {false, true}) {
234 GrMipMapped mipMapped = willUseMips ? GrMipMapped::kYes : GrMipMapped::kNo;
235 sk_sp<SkSurface> surface;
236 GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture(
237 nullptr, kSize, kSize, GrColorType::kRGBA_8888, true, mipMapped);
238 if (isWrapped) {
239 surface = SkSurface::MakeFromBackendTexture(context,
240 backendTex,
241 kTopLeft_GrSurfaceOrigin,
242 0,
243 kRGBA_8888_SkColorType,
244 nullptr,
245 nullptr);
246 } else {
247 SkImageInfo info = SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType,
248 kPremul_SkAlphaType);
249 surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, info, 0,
250 kTopLeft_GrSurfaceOrigin, nullptr,
251 willUseMips);
252 }
253 REPORTER_ASSERT(reporter, surface);
254 if (!surface) {
255 gpu->deleteTestingOnlyBackendTexture(backendTex);
256 }
257 SkGpuDevice* device = ((SkSurface_Gpu*)surface.get())->getDevice();
258 GrTextureProxy* texProxy = device->accessRenderTargetContext()->asTextureProxy();
259 REPORTER_ASSERT(reporter, mipMapped == texProxy->mipMapped());
260
261 texProxy->instantiate(resourceProvider);
262 GrTexture* texture = texProxy->peekTexture();
263 REPORTER_ASSERT(reporter, mipMapped == texture->texturePriv().mipMapped());
264
265 sk_sp<SkImage> image = surface->makeImageSnapshot();
266 REPORTER_ASSERT(reporter, image);
267 if (!image) {
268 gpu->deleteTestingOnlyBackendTexture(backendTex);
269 }
270 texProxy = as_IB(image)->peekProxy();
271 REPORTER_ASSERT(reporter, mipMapped == texProxy->mipMapped());
272
273 texProxy->instantiate(resourceProvider);
274 texture = texProxy->peekTexture();
275 REPORTER_ASSERT(reporter, mipMapped == texture->texturePriv().mipMapped());
276
277 // Must flush the context to make sure all the cmds (copies, etc.) from above are sent
278 // to the gpu before we delete the backendHandle.
279 context->flush();
280 gpu->testingOnly_flushGpuAndSync();
281 gpu->deleteTestingOnlyBackendTexture(backendTex);
282 }
283 }
284 }
285
286 // Test that we don't create a mip mapped texture if the size is 1x1 even if the filter mode is set
287 // to use mips. This test passes by not crashing or hitting asserts in code.
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(Gr1x1TextureMipMappedTest,reporter,ctxInfo)288 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(Gr1x1TextureMipMappedTest, reporter, ctxInfo) {
289 GrContext* context = ctxInfo.grContext();
290 if (!context->contextPriv().caps()->mipMapSupport()) {
291 return;
292 }
293
294 // Make surface to draw into
295 SkImageInfo info = SkImageInfo::MakeN32(16, 16, kPremul_SkAlphaType);
296 sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info);
297
298 // Make 1x1 raster bitmap
299 SkBitmap bmp;
300 bmp.allocN32Pixels(1, 1);
301 SkPMColor* pixel = reinterpret_cast<SkPMColor*>(bmp.getPixels());
302 *pixel = 0;
303
304 sk_sp<SkImage> bmpImage = SkImage::MakeFromBitmap(bmp);
305
306 // Make sure we scale so we don't optimize out the use of mips.
307 surface->getCanvas()->scale(0.5f, 0.5f);
308
309 SkPaint paint;
310 // This should upload the image to a non mipped GrTextureProxy.
311 surface->getCanvas()->drawImage(bmpImage, 0, 0, &paint);
312 surface->flush();
313
314 // Now set the filter quality to high so we use mip maps. We should find the non mipped texture
315 // in the cache for the SkImage. Since the texture is 1x1 we should just use that texture
316 // instead of trying to do a copy to a mipped texture.
317 paint.setFilterQuality(kHigh_SkFilterQuality);
318 surface->getCanvas()->drawImage(bmpImage, 0, 0, &paint);
319 surface->flush();
320 }
321
322