• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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