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 32 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrWrappedMipMappedTest, reporter, ctxInfo) { 33 GrContext* context = ctxInfo.grContext(); 34 if (!context->priv().caps()->mipMapSupport()) { 35 return; 36 } 37 GrGpu* gpu = context->priv().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(context); 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. 101 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrBackendTextureImageMipMappedTest, reporter, ctxInfo) { 102 GrContext* context = ctxInfo.grContext(); 103 if (!context->priv().caps()->mipMapSupport()) { 104 return; 105 } 106 GrGpu* gpu = context->priv().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->priv().resourceProvider()); 158 } else if (!genProxy->isInstantiated()) { 159 genProxy->instantiate(context->priv().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. 223 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrImageSnapshotMipMappedTest, reporter, ctxInfo) { 224 GrContext* context = ctxInfo.grContext(); 225 if (!context->priv().caps()->mipMapSupport()) { 226 return; 227 } 228 229 auto resourceProvider = context->priv().resourceProvider(); 230 GrGpu* gpu = context->priv().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. 288 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(Gr1x1TextureMipMappedTest, reporter, ctxInfo) { 289 GrContext* context = ctxInfo.grContext(); 290 if (!context->priv().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