blob: c9f43f89296cca5a4104958c473fcdca43734edf [file] [log] [blame]
Greg Daniel177e6952017-10-12 12:27:11 -04001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "include/core/SkTypes.h"
Greg Daniel177e6952017-10-12 12:27:11 -04009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/core/SkCanvas.h"
11#include "include/core/SkPoint.h"
12#include "include/core/SkSurface.h"
13#include "include/gpu/GrBackendSurface.h"
14#include "include/gpu/GrContext.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050015#include "src/gpu/GrBackendTextureImageGenerator.h"
16#include "src/gpu/GrContextPriv.h"
Chris Dalton3d770272019-08-14 09:24:37 -060017#include "src/gpu/GrDrawingManager.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050018#include "src/gpu/GrGpu.h"
Greg Daniel47c20e82020-01-21 14:29:57 -050019#include "src/gpu/GrRecordingContextPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050020#include "src/gpu/GrRenderTargetContext.h"
21#include "src/gpu/GrSemaphore.h"
22#include "src/gpu/GrSurfaceProxyPriv.h"
23#include "src/gpu/GrTexturePriv.h"
Greg Danielf91aeb22019-06-18 09:58:02 -040024#include "src/gpu/GrTextureProxy.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050025#include "src/gpu/SkGpuDevice.h"
26#include "src/image/SkImage_Base.h"
27#include "src/image/SkSurface_Gpu.h"
28#include "tests/Test.h"
Greg Daniel177e6952017-10-12 12:27:11 -040029
Greg Daniel45d63032017-10-30 13:41:26 -040030static constexpr int kSize = 8;
31
Greg Daniel177e6952017-10-12 12:27:11 -040032// Test that the correct mip map states are on the GrTextures when wrapping GrBackendTextures in
33// SkImages and SkSurfaces
34DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrWrappedMipMappedTest, reporter, ctxInfo) {
35 GrContext* context = ctxInfo.grContext();
Robert Phillips9da87e02019-02-04 13:26:26 -050036 if (!context->priv().caps()->mipMapSupport()) {
Greg Daniel261b8aa2017-10-23 09:37:36 -040037 return;
38 }
Robert Phillipsf35fd8d2018-01-22 10:48:15 -050039
Greg Daniel177e6952017-10-12 12:27:11 -040040 for (auto mipMapped : {GrMipMapped::kNo, GrMipMapped::kYes}) {
Robert Phillips9dbcdcc2019-05-13 10:40:06 -040041 for (auto renderable : {GrRenderable::kNo, GrRenderable::kYes}) {
Robert Phillips9b16f812019-05-17 10:01:21 -040042 // createBackendTexture currently doesn't support uploading data to mip maps
Greg Daniel177e6952017-10-12 12:27:11 -040043 // so we don't send any. However, we pretend there is data for the checks below which is
44 // fine since we are never actually using these textures for any work on the gpu.
Robert Phillips4bdd36f2019-06-04 11:03:06 -040045 GrBackendTexture backendTex = context->createBackendTexture(
Robert Phillips80626792019-06-04 07:16:10 -040046 kSize, kSize, kRGBA_8888_SkColorType,
Robert Phillipsda2e67a2019-07-01 15:04:06 -040047 SkColors::kTransparent, mipMapped, renderable, GrProtected::kNo);
Greg Daniel177e6952017-10-12 12:27:11 -040048
Robert Phillipse0070c02017-11-13 12:47:24 -050049 sk_sp<GrTextureProxy> proxy;
Greg Daniel177e6952017-10-12 12:27:11 -040050 sk_sp<SkImage> image;
Robert Phillips9dbcdcc2019-05-13 10:40:06 -040051 if (GrRenderable::kYes == renderable) {
Greg Daniel177e6952017-10-12 12:27:11 -040052 sk_sp<SkSurface> surface = SkSurface::MakeFromBackendTexture(
53 context,
54 backendTex,
55 kTopLeft_GrSurfaceOrigin,
56 0,
Greg Danielfaa095e2017-12-19 13:15:02 -050057 kRGBA_8888_SkColorType,
Greg Daniel177e6952017-10-12 12:27:11 -040058 nullptr,
59 nullptr);
60
61 SkGpuDevice* device = ((SkSurface_Gpu*)surface.get())->getDevice();
Robert Phillipse0070c02017-11-13 12:47:24 -050062 proxy = device->accessRenderTargetContext()->asTextureProxyRef();
Greg Daniel177e6952017-10-12 12:27:11 -040063 } else {
64 image = SkImage::MakeFromTexture(context, backendTex,
65 kTopLeft_GrSurfaceOrigin,
Greg Danielf5d87582017-12-18 14:48:15 -050066 kRGBA_8888_SkColorType,
67 kPremul_SkAlphaType, nullptr,
68 nullptr, nullptr);
Greg Danielfebdedf2020-02-05 17:06:27 -050069 const GrSurfaceProxyView* view = as_IB(image)->view(context);
70 REPORTER_ASSERT(reporter, view);
71 if (!view) {
72 context->deleteBackendTexture(backendTex);
73 return;
74 }
75 proxy = view->asTextureProxyRef();
Greg Daniel177e6952017-10-12 12:27:11 -040076 }
77 REPORTER_ASSERT(reporter, proxy);
78 if (!proxy) {
Robert Phillips5c7a25b2019-05-20 08:38:07 -040079 context->deleteBackendTexture(backendTex);
Greg Daniel177e6952017-10-12 12:27:11 -040080 return;
81 }
82
Brian Salomonfd98c2c2018-07-31 17:25:29 -040083 REPORTER_ASSERT(reporter, proxy->isInstantiated());
Greg Daniel177e6952017-10-12 12:27:11 -040084
Brian Salomonfd98c2c2018-07-31 17:25:29 -040085 GrTexture* texture = proxy->peekTexture();
Greg Daniel177e6952017-10-12 12:27:11 -040086 REPORTER_ASSERT(reporter, texture);
87 if (!texture) {
Robert Phillips5c7a25b2019-05-20 08:38:07 -040088 context->deleteBackendTexture(backendTex);
Greg Daniel177e6952017-10-12 12:27:11 -040089 return;
90 }
91
92 if (GrMipMapped::kYes == mipMapped) {
Greg Daniele252f082017-10-23 16:05:23 -040093 REPORTER_ASSERT(reporter, GrMipMapped::kYes == texture->texturePriv().mipMapped());
Robert Phillips9dbcdcc2019-05-13 10:40:06 -040094 if (GrRenderable::kYes == renderable) {
Greg Daniel177e6952017-10-12 12:27:11 -040095 REPORTER_ASSERT(reporter, texture->texturePriv().mipMapsAreDirty());
96 } else {
97 REPORTER_ASSERT(reporter, !texture->texturePriv().mipMapsAreDirty());
98 }
99 } else {
Greg Daniele252f082017-10-23 16:05:23 -0400100 REPORTER_ASSERT(reporter, GrMipMapped::kNo == texture->texturePriv().mipMapped());
Greg Daniel177e6952017-10-12 12:27:11 -0400101 }
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400102 context->deleteBackendTexture(backendTex);
Greg Daniel177e6952017-10-12 12:27:11 -0400103 }
104 }
105}
106
Greg Daniel261b8aa2017-10-23 09:37:36 -0400107// Test that we correctly copy or don't copy GrBackendTextures in the GrBackendTextureImageGenerator
108// based on if we will use mips in the draw and the mip status of the GrBackendTexture.
109DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrBackendTextureImageMipMappedTest, reporter, ctxInfo) {
Greg Daniel261b8aa2017-10-23 09:37:36 -0400110 GrContext* context = ctxInfo.grContext();
Robert Phillips9da87e02019-02-04 13:26:26 -0500111 if (!context->priv().caps()->mipMapSupport()) {
Greg Daniel261b8aa2017-10-23 09:37:36 -0400112 return;
113 }
Robert Phillipsf35fd8d2018-01-22 10:48:15 -0500114
Brian Salomonecbb0fb2020-02-28 18:07:32 -0500115 for (auto betMipMapped : {GrMipMapped::kNo, GrMipMapped::kYes}) {
116 for (auto requestMipMapped : {GrMipMapped::kNo, GrMipMapped::kYes}) {
Robert Phillips4bdd36f2019-06-04 11:03:06 -0400117 GrBackendTexture backendTex = context->createBackendTexture(
Brian Salomonecbb0fb2020-02-28 18:07:32 -0500118 kSize, kSize, kRGBA_8888_SkColorType, SkColors::kTransparent, betMipMapped,
119 GrRenderable::kNo, GrProtected::kNo);
Greg Daniel261b8aa2017-10-23 09:37:36 -0400120
Greg Daniel261b8aa2017-10-23 09:37:36 -0400121 sk_sp<SkImage> image = SkImage::MakeFromTexture(context, backendTex,
122 kTopLeft_GrSurfaceOrigin,
Greg Danielf5d87582017-12-18 14:48:15 -0500123 kRGBA_8888_SkColorType,
124 kPremul_SkAlphaType, nullptr,
125 nullptr, nullptr);
Greg Daniel261b8aa2017-10-23 09:37:36 -0400126
127 GrTextureProxy* proxy = as_IB(image)->peekProxy();
128 REPORTER_ASSERT(reporter, proxy);
129 if (!proxy) {
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400130 context->deleteBackendTexture(backendTex);
Greg Daniel261b8aa2017-10-23 09:37:36 -0400131 return;
132 }
133
Brian Salomonfd98c2c2018-07-31 17:25:29 -0400134 REPORTER_ASSERT(reporter, proxy->isInstantiated());
Greg Daniel261b8aa2017-10-23 09:37:36 -0400135
Brian Salomonfd98c2c2018-07-31 17:25:29 -0400136 sk_sp<GrTexture> texture = sk_ref_sp(proxy->peekTexture());
Greg Daniel261b8aa2017-10-23 09:37:36 -0400137 REPORTER_ASSERT(reporter, texture);
138 if (!texture) {
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400139 context->deleteBackendTexture(backendTex);
Greg Daniel261b8aa2017-10-23 09:37:36 -0400140 return;
141 }
142
143 std::unique_ptr<SkImageGenerator> imageGen = GrBackendTextureImageGenerator::Make(
Brian Osman052ef692018-03-27 09:56:31 -0400144 texture, kTopLeft_GrSurfaceOrigin, nullptr, kRGBA_8888_SkColorType,
145 kPremul_SkAlphaType, nullptr);
Greg Daniel261b8aa2017-10-23 09:37:36 -0400146 REPORTER_ASSERT(reporter, imageGen);
147 if (!imageGen) {
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400148 context->deleteBackendTexture(backendTex);
Greg Daniel261b8aa2017-10-23 09:37:36 -0400149 return;
150 }
151
152 SkIPoint origin = SkIPoint::Make(0,0);
Greg Daniel261b8aa2017-10-23 09:37:36 -0400153 SkImageInfo imageInfo = SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType,
154 kPremul_SkAlphaType);
Brian Salomonbc074a62020-03-18 10:06:13 -0400155 GrSurfaceProxyView genView = imageGen->generateTexture(
156 context, imageInfo, origin, requestMipMapped, GrImageTexGenPolicy::kDraw);
Greg Danielcc104db2020-02-03 14:17:08 -0500157 GrSurfaceProxy* genProxy = genView.proxy();
Greg Daniel261b8aa2017-10-23 09:37:36 -0400158
159 REPORTER_ASSERT(reporter, genProxy);
160 if (!genProxy) {
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400161 context->deleteBackendTexture(backendTex);
Greg Daniel261b8aa2017-10-23 09:37:36 -0400162 return;
163 }
164
Brian Salomonbeb7f522019-08-30 16:19:42 -0400165 if (genProxy->isLazy()) {
Robert Phillips9da87e02019-02-04 13:26:26 -0500166 genProxy->priv().doLazyInstantiation(context->priv().resourceProvider());
Brian Salomonfd98c2c2018-07-31 17:25:29 -0400167 } else if (!genProxy->isInstantiated()) {
Robert Phillips9da87e02019-02-04 13:26:26 -0500168 genProxy->instantiate(context->priv().resourceProvider());
Greg Daniele728f672018-01-17 10:52:04 -0500169 }
170
Brian Salomonfd98c2c2018-07-31 17:25:29 -0400171 REPORTER_ASSERT(reporter, genProxy->isInstantiated());
172 if (!genProxy->isInstantiated()) {
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400173 context->deleteBackendTexture(backendTex);
Greg Danielbddcc952018-01-24 13:22:24 -0500174 return;
175 }
Greg Daniel261b8aa2017-10-23 09:37:36 -0400176
Brian Salomonfd98c2c2018-07-31 17:25:29 -0400177 GrTexture* genTexture = genProxy->peekTexture();
Greg Daniel261b8aa2017-10-23 09:37:36 -0400178 REPORTER_ASSERT(reporter, genTexture);
179 if (!genTexture) {
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400180 context->deleteBackendTexture(backendTex);
Greg Daniel261b8aa2017-10-23 09:37:36 -0400181 return;
182 }
183
Robert Phillipsb67821d2017-12-13 15:00:45 -0500184 GrBackendTexture genBackendTex = genTexture->getBackendTexture();
Greg Daniel261b8aa2017-10-23 09:37:36 -0400185
Greg Danielbdf12ad2018-10-12 09:31:11 -0400186 if (GrBackendApi::kOpenGL == genBackendTex.backend()) {
Greg Daniel52e16d92018-04-10 09:34:07 -0400187 GrGLTextureInfo genTexInfo;
188 GrGLTextureInfo origTexInfo;
189 if (genBackendTex.getGLTextureInfo(&genTexInfo) &&
190 backendTex.getGLTextureInfo(&origTexInfo)) {
Brian Salomonecbb0fb2020-02-28 18:07:32 -0500191 if (requestMipMapped == GrMipMapped::kYes && betMipMapped == GrMipMapped::kNo) {
Greg Daniel52e16d92018-04-10 09:34:07 -0400192 // We did a copy so the texture IDs should be different
193 REPORTER_ASSERT(reporter, origTexInfo.fID != genTexInfo.fID);
194 } else {
195 REPORTER_ASSERT(reporter, origTexInfo.fID == genTexInfo.fID);
196 }
Greg Daniel261b8aa2017-10-23 09:37:36 -0400197 } else {
Greg Daniel52e16d92018-04-10 09:34:07 -0400198 ERRORF(reporter, "Failed to get GrGLTextureInfo");
Greg Daniel261b8aa2017-10-23 09:37:36 -0400199 }
Greg Daniel261b8aa2017-10-23 09:37:36 -0400200#ifdef SK_VULKAN
Greg Danielbdf12ad2018-10-12 09:31:11 -0400201 } else if (GrBackendApi::kVulkan == genBackendTex.backend()) {
Greg Daniel52e16d92018-04-10 09:34:07 -0400202 GrVkImageInfo genImageInfo;
203 GrVkImageInfo origImageInfo;
204 if (genBackendTex.getVkImageInfo(&genImageInfo) &&
205 backendTex.getVkImageInfo(&origImageInfo)) {
Brian Salomonecbb0fb2020-02-28 18:07:32 -0500206 if (requestMipMapped == GrMipMapped::kYes && betMipMapped == GrMipMapped::kNo) {
Greg Daniel52e16d92018-04-10 09:34:07 -0400207 // We did a copy so the texture IDs should be different
208 REPORTER_ASSERT(reporter, origImageInfo.fImage != genImageInfo.fImage);
209 } else {
210 REPORTER_ASSERT(reporter, origImageInfo.fImage == genImageInfo.fImage);
211 }
Greg Daniel261b8aa2017-10-23 09:37:36 -0400212 } else {
Greg Daniel52e16d92018-04-10 09:34:07 -0400213 ERRORF(reporter, "Failed to get GrVkImageInfo");
Greg Daniel261b8aa2017-10-23 09:37:36 -0400214 }
215#endif
Jim Van Verth9896a0d2019-04-10 15:11:12 -0400216#ifdef SK_METAL
217 } else if (GrBackendApi::kMetal == genBackendTex.backend()) {
218 GrMtlTextureInfo genImageInfo;
219 GrMtlTextureInfo origImageInfo;
220 if (genBackendTex.getMtlTextureInfo(&genImageInfo) &&
221 backendTex.getMtlTextureInfo(&origImageInfo)) {
Brian Salomonecbb0fb2020-02-28 18:07:32 -0500222 if (requestMipMapped == GrMipMapped::kYes && betMipMapped == GrMipMapped::kNo) {
Jim Van Verth9896a0d2019-04-10 15:11:12 -0400223 // We did a copy so the texture IDs should be different
224 REPORTER_ASSERT(reporter, origImageInfo.fTexture != genImageInfo.fTexture);
225 } else {
226 REPORTER_ASSERT(reporter, origImageInfo.fTexture == genImageInfo.fTexture);
227 }
228 } else {
229 ERRORF(reporter, "Failed to get GrMtlTextureInfo");
230 }
231#endif
Greg Daniel261b8aa2017-10-23 09:37:36 -0400232 } else {
233 REPORTER_ASSERT(reporter, false);
234 }
235
236 // Must make sure the uses of the backend texture have finished (we possibly have a
Greg Daniel26b50a42018-03-08 09:49:58 -0500237 // queued up copy) before we delete the backend texture.
238 context->flush();
Greg Daniel261b8aa2017-10-23 09:37:36 -0400239
Robert Phillips9b16f812019-05-17 10:01:21 -0400240 context->priv().getGpu()->testingOnly_flushGpuAndSync();
241
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400242 context->deleteBackendTexture(backendTex);
Greg Daniel261b8aa2017-10-23 09:37:36 -0400243 }
244 }
245}
246
Greg Daniel45d63032017-10-30 13:41:26 -0400247// Test that when we call makeImageSnapshot on an SkSurface we retains the same mip status as the
248// resource we took the snapshot of.
249DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrImageSnapshotMipMappedTest, reporter, ctxInfo) {
250 GrContext* context = ctxInfo.grContext();
Robert Phillips9da87e02019-02-04 13:26:26 -0500251 if (!context->priv().caps()->mipMapSupport()) {
Greg Daniel45d63032017-10-30 13:41:26 -0400252 return;
253 }
254
Robert Phillips9da87e02019-02-04 13:26:26 -0500255 auto resourceProvider = context->priv().resourceProvider();
Robert Phillips6be756b2018-01-16 15:07:54 -0500256
Greg Daniel45d63032017-10-30 13:41:26 -0400257 for (auto willUseMips : {false, true}) {
258 for (auto isWrapped : {false, true}) {
259 GrMipMapped mipMapped = willUseMips ? GrMipMapped::kYes : GrMipMapped::kNo;
260 sk_sp<SkSurface> surface;
Robert Phillips4bdd36f2019-06-04 11:03:06 -0400261 GrBackendTexture backendTex = context->createBackendTexture(
Robert Phillips80626792019-06-04 07:16:10 -0400262 kSize, kSize, kRGBA_8888_SkColorType,
Robert Phillipsda2e67a2019-07-01 15:04:06 -0400263 SkColors::kTransparent, mipMapped, GrRenderable::kYes, GrProtected::kNo);
Greg Daniel45d63032017-10-30 13:41:26 -0400264 if (isWrapped) {
Greg Daniel45d63032017-10-30 13:41:26 -0400265 surface = SkSurface::MakeFromBackendTexture(context,
266 backendTex,
267 kTopLeft_GrSurfaceOrigin,
268 0,
Greg Danielfaa095e2017-12-19 13:15:02 -0500269 kRGBA_8888_SkColorType,
Greg Daniel45d63032017-10-30 13:41:26 -0400270 nullptr,
271 nullptr);
272 } else {
273 SkImageInfo info = SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType,
274 kPremul_SkAlphaType);
275 surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, info, 0,
276 kTopLeft_GrSurfaceOrigin, nullptr,
277 willUseMips);
278 }
279 REPORTER_ASSERT(reporter, surface);
280 if (!surface) {
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400281 context->deleteBackendTexture(backendTex);
Greg Daniel45d63032017-10-30 13:41:26 -0400282 }
283 SkGpuDevice* device = ((SkSurface_Gpu*)surface.get())->getDevice();
284 GrTextureProxy* texProxy = device->accessRenderTargetContext()->asTextureProxy();
285 REPORTER_ASSERT(reporter, mipMapped == texProxy->mipMapped());
286
Robert Phillips6be756b2018-01-16 15:07:54 -0500287 texProxy->instantiate(resourceProvider);
Brian Salomonfd98c2c2018-07-31 17:25:29 -0400288 GrTexture* texture = texProxy->peekTexture();
Greg Daniel45d63032017-10-30 13:41:26 -0400289 REPORTER_ASSERT(reporter, mipMapped == texture->texturePriv().mipMapped());
290
291 sk_sp<SkImage> image = surface->makeImageSnapshot();
292 REPORTER_ASSERT(reporter, image);
293 if (!image) {
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400294 context->deleteBackendTexture(backendTex);
Greg Daniel45d63032017-10-30 13:41:26 -0400295 }
296 texProxy = as_IB(image)->peekProxy();
297 REPORTER_ASSERT(reporter, mipMapped == texProxy->mipMapped());
298
Robert Phillips6be756b2018-01-16 15:07:54 -0500299 texProxy->instantiate(resourceProvider);
Brian Salomonfd98c2c2018-07-31 17:25:29 -0400300 texture = texProxy->peekTexture();
Greg Daniel45d63032017-10-30 13:41:26 -0400301 REPORTER_ASSERT(reporter, mipMapped == texture->texturePriv().mipMapped());
302
303 // Must flush the context to make sure all the cmds (copies, etc.) from above are sent
304 // to the gpu before we delete the backendHandle.
305 context->flush();
Robert Phillips9b16f812019-05-17 10:01:21 -0400306 context->priv().getGpu()->testingOnly_flushGpuAndSync();
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400307 context->deleteBackendTexture(backendTex);
Greg Daniel45d63032017-10-30 13:41:26 -0400308 }
309 }
310}
Greg Daniel8e9b4c42018-07-20 10:30:48 -0400311
312// Test that we don't create a mip mapped texture if the size is 1x1 even if the filter mode is set
313// to use mips. This test passes by not crashing or hitting asserts in code.
314DEF_GPUTEST_FOR_RENDERING_CONTEXTS(Gr1x1TextureMipMappedTest, reporter, ctxInfo) {
315 GrContext* context = ctxInfo.grContext();
Robert Phillips9da87e02019-02-04 13:26:26 -0500316 if (!context->priv().caps()->mipMapSupport()) {
Greg Daniel8e9b4c42018-07-20 10:30:48 -0400317 return;
318 }
319
320 // Make surface to draw into
321 SkImageInfo info = SkImageInfo::MakeN32(16, 16, kPremul_SkAlphaType);
322 sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info);
323
324 // Make 1x1 raster bitmap
325 SkBitmap bmp;
326 bmp.allocN32Pixels(1, 1);
327 SkPMColor* pixel = reinterpret_cast<SkPMColor*>(bmp.getPixels());
328 *pixel = 0;
329
330 sk_sp<SkImage> bmpImage = SkImage::MakeFromBitmap(bmp);
331
332 // Make sure we scale so we don't optimize out the use of mips.
333 surface->getCanvas()->scale(0.5f, 0.5f);
334
335 SkPaint paint;
336 // This should upload the image to a non mipped GrTextureProxy.
337 surface->getCanvas()->drawImage(bmpImage, 0, 0, &paint);
338 surface->flush();
339
340 // Now set the filter quality to high so we use mip maps. We should find the non mipped texture
341 // in the cache for the SkImage. Since the texture is 1x1 we should just use that texture
342 // instead of trying to do a copy to a mipped texture.
343 paint.setFilterQuality(kHigh_SkFilterQuality);
344 surface->getCanvas()->drawImage(bmpImage, 0, 0, &paint);
345 surface->flush();
346}
347
Greg Daniel40903af2020-01-30 14:55:05 -0500348// Create a new render target and draw 'mipmapView' into it using the provided 'filter'.
Brian Salomonbf6b9792019-08-21 09:38:10 -0400349static std::unique_ptr<GrRenderTargetContext> draw_mipmap_into_new_render_target(
Greg Danielba0ff782020-01-07 15:42:57 -0500350 GrRecordingContext* context, GrProxyProvider* proxyProvider, GrColorType colorType,
Greg Daniel40903af2020-01-30 14:55:05 -0500351 SkAlphaType alphaType, GrSurfaceProxyView mipmapView, GrSamplerState::Filter filter) {
Chris Dalton3d770272019-08-14 09:24:37 -0600352 sk_sp<GrSurfaceProxy> renderTarget = proxyProvider->createProxy(
Brian Salomondf1bd6d2020-03-26 20:37:01 -0400353 mipmapView.proxy()->backendFormat(), {1, 1}, GrRenderable::kYes, 1, GrMipMapped::kNo,
354 SkBackingFit::kApprox, SkBudgeted::kYes, GrProtected::kNo);
Greg Danielba0ff782020-01-07 15:42:57 -0500355
356 auto rtc = GrRenderTargetContext::Make(
357 context, colorType, nullptr, std::move(renderTarget), kTopLeft_GrSurfaceOrigin,
358 nullptr);
359
Greg Daniel40903af2020-01-30 14:55:05 -0500360 rtc->drawTexture(GrNoClip(), std::move(mipmapView), alphaType, filter, SkBlendMode::kSrcOver,
Greg Danielc594e622019-10-15 14:01:49 -0400361 {1,1,1,1}, SkRect::MakeWH(4, 4), SkRect::MakeWH(1,1), GrAA::kYes,
Brian Salomonfc118442019-11-22 19:09:27 -0500362 GrQuadAAFlags::kAll, SkCanvas::kFast_SrcRectConstraint, SkMatrix::I(),
363 nullptr);
Chris Dalton3d770272019-08-14 09:24:37 -0600364 return rtc;
365}
366
Greg Danielf41b2bd2019-08-22 16:19:24 -0400367// Test that two opsTasks using the same mipmaps both depend on the same GrTextureResolveRenderTask.
Chris Dalton30eea6c2019-08-21 10:22:50 -0600368DEF_GPUTEST(GrManyDependentsMipMappedTest, reporter, /* options */) {
369 using CanClearFullscreen = GrRenderTargetContext::CanClearFullscreen;
370 using Enable = GrContextOptions::Enable;
371 using Filter = GrSamplerState::Filter;
372
373 for (auto enableSortingAndReduction : {Enable::kYes, Enable::kNo}) {
374 GrMockOptions mockOptions;
375 mockOptions.fMipMapSupport = true;
376 GrContextOptions ctxOptions;
Greg Daniel93138742019-08-22 17:15:39 -0400377 ctxOptions.fReduceOpsTaskSplitting = enableSortingAndReduction;
Chris Dalton30eea6c2019-08-21 10:22:50 -0600378 sk_sp<GrContext> context = GrContext::MakeMock(&mockOptions, ctxOptions);
379 if (!context) {
Greg Danielf41b2bd2019-08-22 16:19:24 -0400380 ERRORF(reporter, "could not create mock context with fReduceOpsTaskSplitting %s.",
Chris Dalton30eea6c2019-08-21 10:22:50 -0600381 (Enable::kYes == enableSortingAndReduction) ? "enabled" : "disabled");
382 continue;
383 }
384
385 SkASSERT(context->priv().caps()->mipMapSupport());
386
387 GrBackendFormat format = context->defaultBackendFormat(
388 kRGBA_8888_SkColorType, GrRenderable::kYes);
Chris Dalton30eea6c2019-08-21 10:22:50 -0600389 GrColorType colorType = GrColorType::kRGBA_8888;
Brian Salomonfc118442019-11-22 19:09:27 -0500390 SkAlphaType alphaType = kPremul_SkAlphaType;
Chris Dalton30eea6c2019-08-21 10:22:50 -0600391
Chris Dalton30eea6c2019-08-21 10:22:50 -0600392 GrProxyProvider* proxyProvider = context->priv().proxyProvider();
393
394 // Create a mipmapped render target.
Greg Daniel47c20e82020-01-21 14:29:57 -0500395
Brian Salomonbeb7f522019-08-30 16:19:42 -0400396 sk_sp<GrTextureProxy> mipmapProxy = proxyProvider->createProxy(
Brian Salomondf1bd6d2020-03-26 20:37:01 -0400397 format, {4, 4}, GrRenderable::kYes, 1, GrMipMapped::kYes, SkBackingFit::kExact,
398 SkBudgeted::kYes, GrProtected::kNo);
Chris Dalton30eea6c2019-08-21 10:22:50 -0600399
Chris Daltonaa3cbb82019-08-21 00:01:21 -0600400 // Mark the mipmaps clean to ensure things still work properly when they won't be marked
401 // dirty again until GrRenderTask::makeClosed().
402 mipmapProxy->markMipMapsClean();
403
Greg Danielba0ff782020-01-07 15:42:57 -0500404 auto mipmapRTC = GrRenderTargetContext::Make(
405 context.get(), colorType, nullptr, mipmapProxy, kTopLeft_GrSurfaceOrigin, nullptr);
406
Chris Dalton30eea6c2019-08-21 10:22:50 -0600407 mipmapRTC->clear(nullptr, {.1f,.2f,.3f,.4f}, CanClearFullscreen::kYes);
Chris Dalton30eea6c2019-08-21 10:22:50 -0600408 REPORTER_ASSERT(reporter, mipmapProxy->getLastRenderTask());
Greg Danielf41b2bd2019-08-22 16:19:24 -0400409 // mipmapProxy's last render task should now just be the opsTask containing the clear.
Chris Dalton30eea6c2019-08-21 10:22:50 -0600410 REPORTER_ASSERT(reporter,
Greg Danielf41b2bd2019-08-22 16:19:24 -0400411 mipmapRTC->testingOnly_PeekLastOpsTask() == mipmapProxy->getLastRenderTask());
Chris Dalton30eea6c2019-08-21 10:22:50 -0600412
Chris Daltonaa3cbb82019-08-21 00:01:21 -0600413 // Mipmaps don't get marked dirty until makeClosed().
414 REPORTER_ASSERT(reporter, !mipmapProxy->mipMapsAreDirty());
415
Brian Salomondf1bd6d2020-03-26 20:37:01 -0400416 GrSwizzle swizzle = context->priv().caps()->getReadSwizzle(format, colorType);
Greg Daniel40903af2020-01-30 14:55:05 -0500417 GrSurfaceProxyView mipmapView(mipmapProxy, kTopLeft_GrSurfaceOrigin, swizzle);
418
Chris Dalton30eea6c2019-08-21 10:22:50 -0600419 // Draw the dirty mipmap texture into a render target.
Greg Danielba0ff782020-01-07 15:42:57 -0500420 auto rtc1 = draw_mipmap_into_new_render_target(context.get(), proxyProvider, colorType,
Greg Daniel40903af2020-01-30 14:55:05 -0500421 alphaType, mipmapView, Filter::kMipMap);
Chris Dalton30eea6c2019-08-21 10:22:50 -0600422
Chris Daltonaa3cbb82019-08-21 00:01:21 -0600423 // Mipmaps should have gotten marked dirty during makeClosed, then marked clean again as
424 // soon as a GrTextureResolveRenderTask was inserted. The way we know they were resolved is
Greg Danielf41b2bd2019-08-22 16:19:24 -0400425 // if mipmapProxy->getLastRenderTask() has switched from the opsTask that drew to it, to the
Chris Daltonaa3cbb82019-08-21 00:01:21 -0600426 // task that resolved its mips.
Chris Dalton30eea6c2019-08-21 10:22:50 -0600427 GrRenderTask* initialMipmapRegenTask = mipmapProxy->getLastRenderTask();
428 REPORTER_ASSERT(reporter, initialMipmapRegenTask);
429 REPORTER_ASSERT(reporter,
Greg Danielf41b2bd2019-08-22 16:19:24 -0400430 initialMipmapRegenTask != mipmapRTC->testingOnly_PeekLastOpsTask());
Chris Dalton30eea6c2019-08-21 10:22:50 -0600431 REPORTER_ASSERT(reporter, !mipmapProxy->mipMapsAreDirty());
Chris Dalton30eea6c2019-08-21 10:22:50 -0600432
433 // Draw the now-clean mipmap texture into a second target.
Greg Danielba0ff782020-01-07 15:42:57 -0500434 auto rtc2 = draw_mipmap_into_new_render_target(context.get(), proxyProvider, colorType,
Greg Daniel40903af2020-01-30 14:55:05 -0500435 alphaType, mipmapView, Filter::kMipMap);
Chris Dalton30eea6c2019-08-21 10:22:50 -0600436
437 // Make sure the mipmap texture still has the same regen task.
438 REPORTER_ASSERT(reporter, mipmapProxy->getLastRenderTask() == initialMipmapRegenTask);
Chris Dalton30eea6c2019-08-21 10:22:50 -0600439 SkASSERT(!mipmapProxy->mipMapsAreDirty());
440
441 // Reset everything so we can go again, this time with the first draw not mipmapped.
442 context->flush();
443
Chris Daltone2a903e2019-09-18 13:41:50 -0600444 // Mip regen tasks don't get added as dependencies until makeClosed().
445 REPORTER_ASSERT(reporter,
446 rtc1->testingOnly_PeekLastOpsTask()->dependsOn(initialMipmapRegenTask));
447 REPORTER_ASSERT(reporter,
448 rtc2->testingOnly_PeekLastOpsTask()->dependsOn(initialMipmapRegenTask));
449
Chris Dalton30eea6c2019-08-21 10:22:50 -0600450 // Render something to dirty the mips.
451 mipmapRTC->clear(nullptr, {.1f,.2f,.3f,.4f}, CanClearFullscreen::kYes);
Chris Dalton30eea6c2019-08-21 10:22:50 -0600452 REPORTER_ASSERT(reporter, mipmapProxy->getLastRenderTask());
Greg Danielf41b2bd2019-08-22 16:19:24 -0400453 // mipmapProxy's last render task should now just be the opsTask containing the clear.
Chris Dalton30eea6c2019-08-21 10:22:50 -0600454 REPORTER_ASSERT(reporter,
Greg Danielf41b2bd2019-08-22 16:19:24 -0400455 mipmapRTC->testingOnly_PeekLastOpsTask() == mipmapProxy->getLastRenderTask());
Chris Dalton30eea6c2019-08-21 10:22:50 -0600456
Chris Daltonaa3cbb82019-08-21 00:01:21 -0600457 // Mipmaps don't get marked dirty until makeClosed().
458 REPORTER_ASSERT(reporter, !mipmapProxy->mipMapsAreDirty());
459
Chris Dalton30eea6c2019-08-21 10:22:50 -0600460 // Draw the dirty mipmap texture into a render target, but don't do mipmap filtering.
Greg Danielba0ff782020-01-07 15:42:57 -0500461 rtc1 = draw_mipmap_into_new_render_target(context.get(), proxyProvider, colorType,
Greg Daniel40903af2020-01-30 14:55:05 -0500462 alphaType, mipmapView, Filter::kBilerp);
Chris Dalton30eea6c2019-08-21 10:22:50 -0600463
Chris Daltonaa3cbb82019-08-21 00:01:21 -0600464 // Mipmaps should have gotten marked dirty during makeClosed() when adding the dependency.
465 // Since the last draw did not use mips, they will not have been regenerated and should
466 // therefore still be dirty.
Chris Dalton30eea6c2019-08-21 10:22:50 -0600467 REPORTER_ASSERT(reporter, mipmapProxy->mipMapsAreDirty());
Chris Daltonaa3cbb82019-08-21 00:01:21 -0600468
469 // Since mips weren't regenerated, the last render task shouldn't have changed.
Chris Dalton30eea6c2019-08-21 10:22:50 -0600470 REPORTER_ASSERT(reporter,
Greg Danielf41b2bd2019-08-22 16:19:24 -0400471 mipmapRTC->testingOnly_PeekLastOpsTask() == mipmapProxy->getLastRenderTask());
Chris Dalton30eea6c2019-08-21 10:22:50 -0600472
Chris Daltonaa3cbb82019-08-21 00:01:21 -0600473 // Draw the stil-dirty mipmap texture into a second target with mipmap filtering.
Greg Danielba0ff782020-01-07 15:42:57 -0500474 rtc2 = draw_mipmap_into_new_render_target(context.get(), proxyProvider, colorType,
Greg Daniel40903af2020-01-30 14:55:05 -0500475 alphaType, std::move(mipmapView),
476 Filter::kMipMap);
Chris Dalton30eea6c2019-08-21 10:22:50 -0600477
Chris Daltonaa3cbb82019-08-21 00:01:21 -0600478 // Make sure the mipmap texture now has a new last render task that regenerates the mips,
479 // and that the mipmaps are now clean.
Chris Daltone2a903e2019-09-18 13:41:50 -0600480 auto mipRegenTask2 = mipmapProxy->getLastRenderTask();
481 REPORTER_ASSERT(reporter, mipRegenTask2);
Chris Dalton30eea6c2019-08-21 10:22:50 -0600482 REPORTER_ASSERT(reporter,
Chris Daltone2a903e2019-09-18 13:41:50 -0600483 mipmapRTC->testingOnly_PeekLastOpsTask() != mipRegenTask2);
Chris Dalton30eea6c2019-08-21 10:22:50 -0600484 SkASSERT(!mipmapProxy->mipMapsAreDirty());
Chris Daltone2a903e2019-09-18 13:41:50 -0600485
486 // Mip regen tasks don't get added as dependencies until makeClosed().
487 context->flush();
488 REPORTER_ASSERT(reporter, rtc2->testingOnly_PeekLastOpsTask()->dependsOn(mipRegenTask2));
Chris Dalton3d770272019-08-14 09:24:37 -0600489 }
Chris Dalton3d770272019-08-14 09:24:37 -0600490}