blob: 82dcd8089094322810fd43823f070cb6ca23c69a [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"
Robert Phillips6d344c32020-07-06 10:56:46 -040014#include "include/gpu/GrDirectContext.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050015#include "src/gpu/GrBackendTextureImageGenerator.h"
Robert Phillips16bf7d32020-07-07 10:20:27 -040016#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"
Robert Phillipse19babf2020-04-06 13:57:30 -040019#include "src/gpu/GrProxyProvider.h"
Greg Daniel47c20e82020-01-21 14:29:57 -050020#include "src/gpu/GrRecordingContextPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050021#include "src/gpu/GrRenderTargetContext.h"
22#include "src/gpu/GrSemaphore.h"
23#include "src/gpu/GrSurfaceProxyPriv.h"
24#include "src/gpu/GrTexturePriv.h"
Greg Danielf91aeb22019-06-18 09:58:02 -040025#include "src/gpu/GrTextureProxy.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050026#include "src/gpu/SkGpuDevice.h"
27#include "src/image/SkImage_Base.h"
28#include "src/image/SkSurface_Gpu.h"
29#include "tests/Test.h"
Greg Danielc1ad77c2020-05-06 11:40:03 -040030#include "tests/TestUtils.h"
Greg Daniel177e6952017-10-12 12:27:11 -040031
Greg Daniel45d63032017-10-30 13:41:26 -040032static constexpr int kSize = 8;
33
Greg Daniel177e6952017-10-12 12:27:11 -040034// Test that the correct mip map states are on the GrTextures when wrapping GrBackendTextures in
35// SkImages and SkSurfaces
36DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrWrappedMipMappedTest, reporter, ctxInfo) {
Robert Phillips6d344c32020-07-06 10:56:46 -040037 auto context = ctxInfo.directContext();
Robert Phillips9da87e02019-02-04 13:26:26 -050038 if (!context->priv().caps()->mipMapSupport()) {
Greg Daniel261b8aa2017-10-23 09:37:36 -040039 return;
40 }
Robert Phillipsf35fd8d2018-01-22 10:48:15 -050041
Brian Salomon7e67dca2020-07-21 09:27:25 -040042 for (auto mipMapped : {GrMipmapped::kNo, GrMipmapped::kYes}) {
Robert Phillips9dbcdcc2019-05-13 10:40:06 -040043 for (auto renderable : {GrRenderable::kNo, GrRenderable::kYes}) {
Robert Phillips9b16f812019-05-17 10:01:21 -040044 // createBackendTexture currently doesn't support uploading data to mip maps
Greg Daniel177e6952017-10-12 12:27:11 -040045 // so we don't send any. However, we pretend there is data for the checks below which is
46 // fine since we are never actually using these textures for any work on the gpu.
Greg Danielc1ad77c2020-05-06 11:40:03 -040047 GrBackendTexture backendTex;
48 CreateBackendTexture(context, &backendTex, kSize, kSize, kRGBA_8888_SkColorType,
49 SkColors::kTransparent, mipMapped, renderable);
Greg Daniel177e6952017-10-12 12:27:11 -040050
Robert Phillipse0070c02017-11-13 12:47:24 -050051 sk_sp<GrTextureProxy> proxy;
Greg Daniel177e6952017-10-12 12:27:11 -040052 sk_sp<SkImage> image;
Robert Phillips9dbcdcc2019-05-13 10:40:06 -040053 if (GrRenderable::kYes == renderable) {
Greg Daniel177e6952017-10-12 12:27:11 -040054 sk_sp<SkSurface> surface = SkSurface::MakeFromBackendTexture(
55 context,
56 backendTex,
57 kTopLeft_GrSurfaceOrigin,
58 0,
Greg Danielfaa095e2017-12-19 13:15:02 -050059 kRGBA_8888_SkColorType,
Greg Daniel177e6952017-10-12 12:27:11 -040060 nullptr,
61 nullptr);
62
63 SkGpuDevice* device = ((SkSurface_Gpu*)surface.get())->getDevice();
Robert Phillipse0070c02017-11-13 12:47:24 -050064 proxy = device->accessRenderTargetContext()->asTextureProxyRef();
Greg Daniel177e6952017-10-12 12:27:11 -040065 } else {
66 image = SkImage::MakeFromTexture(context, backendTex,
67 kTopLeft_GrSurfaceOrigin,
Greg Danielf5d87582017-12-18 14:48:15 -050068 kRGBA_8888_SkColorType,
69 kPremul_SkAlphaType, nullptr,
70 nullptr, nullptr);
Greg Danielfebdedf2020-02-05 17:06:27 -050071 const GrSurfaceProxyView* view = as_IB(image)->view(context);
72 REPORTER_ASSERT(reporter, view);
73 if (!view) {
74 context->deleteBackendTexture(backendTex);
75 return;
76 }
77 proxy = view->asTextureProxyRef();
Greg Daniel177e6952017-10-12 12:27:11 -040078 }
79 REPORTER_ASSERT(reporter, proxy);
80 if (!proxy) {
Robert Phillips5c7a25b2019-05-20 08:38:07 -040081 context->deleteBackendTexture(backendTex);
Greg Daniel177e6952017-10-12 12:27:11 -040082 return;
83 }
84
Brian Salomonfd98c2c2018-07-31 17:25:29 -040085 REPORTER_ASSERT(reporter, proxy->isInstantiated());
Greg Daniel177e6952017-10-12 12:27:11 -040086
Brian Salomonfd98c2c2018-07-31 17:25:29 -040087 GrTexture* texture = proxy->peekTexture();
Greg Daniel177e6952017-10-12 12:27:11 -040088 REPORTER_ASSERT(reporter, texture);
89 if (!texture) {
Robert Phillips5c7a25b2019-05-20 08:38:07 -040090 context->deleteBackendTexture(backendTex);
Greg Daniel177e6952017-10-12 12:27:11 -040091 return;
92 }
93
Brian Salomon7e67dca2020-07-21 09:27:25 -040094 if (GrMipmapped::kYes == mipMapped) {
95 REPORTER_ASSERT(reporter, GrMipmapped::kYes == texture->texturePriv().mipMapped());
Robert Phillips9dbcdcc2019-05-13 10:40:06 -040096 if (GrRenderable::kYes == renderable) {
Greg Daniel177e6952017-10-12 12:27:11 -040097 REPORTER_ASSERT(reporter, texture->texturePriv().mipMapsAreDirty());
98 } else {
99 REPORTER_ASSERT(reporter, !texture->texturePriv().mipMapsAreDirty());
100 }
101 } else {
Brian Salomon7e67dca2020-07-21 09:27:25 -0400102 REPORTER_ASSERT(reporter, GrMipmapped::kNo == texture->texturePriv().mipMapped());
Greg Daniel177e6952017-10-12 12:27:11 -0400103 }
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400104 context->deleteBackendTexture(backendTex);
Greg Daniel177e6952017-10-12 12:27:11 -0400105 }
106 }
107}
108
Greg Daniel261b8aa2017-10-23 09:37:36 -0400109// Test that we correctly copy or don't copy GrBackendTextures in the GrBackendTextureImageGenerator
110// based on if we will use mips in the draw and the mip status of the GrBackendTexture.
111DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrBackendTextureImageMipMappedTest, reporter, ctxInfo) {
Robert Phillips6d344c32020-07-06 10:56:46 -0400112 auto context = ctxInfo.directContext();
Robert Phillips9da87e02019-02-04 13:26:26 -0500113 if (!context->priv().caps()->mipMapSupport()) {
Greg Daniel261b8aa2017-10-23 09:37:36 -0400114 return;
115 }
Robert Phillipsf35fd8d2018-01-22 10:48:15 -0500116
Brian Salomon7e67dca2020-07-21 09:27:25 -0400117 for (auto betMipMapped : {GrMipmapped::kNo, GrMipmapped::kYes}) {
118 for (auto requestMipMapped : {GrMipmapped::kNo, GrMipmapped::kYes}) {
Greg Danielc1ad77c2020-05-06 11:40:03 -0400119 GrBackendTexture backendTex;
120 CreateBackendTexture(context, &backendTex, kSize, kSize, kRGBA_8888_SkColorType,
121 SkColors::kTransparent, betMipMapped, GrRenderable::kNo);
Greg Daniel261b8aa2017-10-23 09:37:36 -0400122
Greg Daniel261b8aa2017-10-23 09:37:36 -0400123 sk_sp<SkImage> image = SkImage::MakeFromTexture(context, backendTex,
124 kTopLeft_GrSurfaceOrigin,
Greg Danielf5d87582017-12-18 14:48:15 -0500125 kRGBA_8888_SkColorType,
126 kPremul_SkAlphaType, nullptr,
127 nullptr, nullptr);
Greg Daniel261b8aa2017-10-23 09:37:36 -0400128
129 GrTextureProxy* proxy = as_IB(image)->peekProxy();
130 REPORTER_ASSERT(reporter, proxy);
131 if (!proxy) {
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400132 context->deleteBackendTexture(backendTex);
Greg Daniel261b8aa2017-10-23 09:37:36 -0400133 return;
134 }
135
Brian Salomonfd98c2c2018-07-31 17:25:29 -0400136 REPORTER_ASSERT(reporter, proxy->isInstantiated());
Greg Daniel261b8aa2017-10-23 09:37:36 -0400137
Brian Salomonfd98c2c2018-07-31 17:25:29 -0400138 sk_sp<GrTexture> texture = sk_ref_sp(proxy->peekTexture());
Greg Daniel261b8aa2017-10-23 09:37:36 -0400139 REPORTER_ASSERT(reporter, texture);
140 if (!texture) {
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400141 context->deleteBackendTexture(backendTex);
Greg Daniel261b8aa2017-10-23 09:37:36 -0400142 return;
143 }
144
145 std::unique_ptr<SkImageGenerator> imageGen = GrBackendTextureImageGenerator::Make(
Brian Osman052ef692018-03-27 09:56:31 -0400146 texture, kTopLeft_GrSurfaceOrigin, nullptr, kRGBA_8888_SkColorType,
147 kPremul_SkAlphaType, nullptr);
Greg Daniel261b8aa2017-10-23 09:37:36 -0400148 REPORTER_ASSERT(reporter, imageGen);
149 if (!imageGen) {
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400150 context->deleteBackendTexture(backendTex);
Greg Daniel261b8aa2017-10-23 09:37:36 -0400151 return;
152 }
153
154 SkIPoint origin = SkIPoint::Make(0,0);
Greg Daniel261b8aa2017-10-23 09:37:36 -0400155 SkImageInfo imageInfo = SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType,
156 kPremul_SkAlphaType);
Brian Salomonbc074a62020-03-18 10:06:13 -0400157 GrSurfaceProxyView genView = imageGen->generateTexture(
158 context, imageInfo, origin, requestMipMapped, GrImageTexGenPolicy::kDraw);
Greg Danielcc104db2020-02-03 14:17:08 -0500159 GrSurfaceProxy* genProxy = genView.proxy();
Greg Daniel261b8aa2017-10-23 09:37:36 -0400160
161 REPORTER_ASSERT(reporter, genProxy);
162 if (!genProxy) {
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400163 context->deleteBackendTexture(backendTex);
Greg Daniel261b8aa2017-10-23 09:37:36 -0400164 return;
165 }
166
Brian Salomonbeb7f522019-08-30 16:19:42 -0400167 if (genProxy->isLazy()) {
Robert Phillips9da87e02019-02-04 13:26:26 -0500168 genProxy->priv().doLazyInstantiation(context->priv().resourceProvider());
Brian Salomonfd98c2c2018-07-31 17:25:29 -0400169 } else if (!genProxy->isInstantiated()) {
Robert Phillips9da87e02019-02-04 13:26:26 -0500170 genProxy->instantiate(context->priv().resourceProvider());
Greg Daniele728f672018-01-17 10:52:04 -0500171 }
172
Brian Salomonfd98c2c2018-07-31 17:25:29 -0400173 REPORTER_ASSERT(reporter, genProxy->isInstantiated());
174 if (!genProxy->isInstantiated()) {
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400175 context->deleteBackendTexture(backendTex);
Greg Danielbddcc952018-01-24 13:22:24 -0500176 return;
177 }
Greg Daniel261b8aa2017-10-23 09:37:36 -0400178
Brian Salomonfd98c2c2018-07-31 17:25:29 -0400179 GrTexture* genTexture = genProxy->peekTexture();
Greg Daniel261b8aa2017-10-23 09:37:36 -0400180 REPORTER_ASSERT(reporter, genTexture);
181 if (!genTexture) {
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400182 context->deleteBackendTexture(backendTex);
Greg Daniel261b8aa2017-10-23 09:37:36 -0400183 return;
184 }
185
Robert Phillipsb67821d2017-12-13 15:00:45 -0500186 GrBackendTexture genBackendTex = genTexture->getBackendTexture();
Greg Daniel261b8aa2017-10-23 09:37:36 -0400187
Greg Danielbdf12ad2018-10-12 09:31:11 -0400188 if (GrBackendApi::kOpenGL == genBackendTex.backend()) {
Greg Daniel52e16d92018-04-10 09:34:07 -0400189 GrGLTextureInfo genTexInfo;
190 GrGLTextureInfo origTexInfo;
191 if (genBackendTex.getGLTextureInfo(&genTexInfo) &&
192 backendTex.getGLTextureInfo(&origTexInfo)) {
Brian Salomon7e67dca2020-07-21 09:27:25 -0400193 if (requestMipMapped == GrMipmapped::kYes && betMipMapped == GrMipmapped::kNo) {
Greg Daniel52e16d92018-04-10 09:34:07 -0400194 // We did a copy so the texture IDs should be different
195 REPORTER_ASSERT(reporter, origTexInfo.fID != genTexInfo.fID);
196 } else {
197 REPORTER_ASSERT(reporter, origTexInfo.fID == genTexInfo.fID);
198 }
Greg Daniel261b8aa2017-10-23 09:37:36 -0400199 } else {
Greg Daniel52e16d92018-04-10 09:34:07 -0400200 ERRORF(reporter, "Failed to get GrGLTextureInfo");
Greg Daniel261b8aa2017-10-23 09:37:36 -0400201 }
Greg Daniel261b8aa2017-10-23 09:37:36 -0400202#ifdef SK_VULKAN
Greg Danielbdf12ad2018-10-12 09:31:11 -0400203 } else if (GrBackendApi::kVulkan == genBackendTex.backend()) {
Greg Daniel52e16d92018-04-10 09:34:07 -0400204 GrVkImageInfo genImageInfo;
205 GrVkImageInfo origImageInfo;
206 if (genBackendTex.getVkImageInfo(&genImageInfo) &&
207 backendTex.getVkImageInfo(&origImageInfo)) {
Brian Salomon7e67dca2020-07-21 09:27:25 -0400208 if (requestMipMapped == GrMipmapped::kYes && betMipMapped == GrMipmapped::kNo) {
Greg Daniel52e16d92018-04-10 09:34:07 -0400209 // We did a copy so the texture IDs should be different
210 REPORTER_ASSERT(reporter, origImageInfo.fImage != genImageInfo.fImage);
211 } else {
212 REPORTER_ASSERT(reporter, origImageInfo.fImage == genImageInfo.fImage);
213 }
Greg Daniel261b8aa2017-10-23 09:37:36 -0400214 } else {
Greg Daniel52e16d92018-04-10 09:34:07 -0400215 ERRORF(reporter, "Failed to get GrVkImageInfo");
Greg Daniel261b8aa2017-10-23 09:37:36 -0400216 }
217#endif
Jim Van Verth9896a0d2019-04-10 15:11:12 -0400218#ifdef SK_METAL
219 } else if (GrBackendApi::kMetal == genBackendTex.backend()) {
220 GrMtlTextureInfo genImageInfo;
221 GrMtlTextureInfo origImageInfo;
222 if (genBackendTex.getMtlTextureInfo(&genImageInfo) &&
223 backendTex.getMtlTextureInfo(&origImageInfo)) {
Brian Salomon7e67dca2020-07-21 09:27:25 -0400224 if (requestMipMapped == GrMipmapped::kYes && betMipMapped == GrMipmapped::kNo) {
Jim Van Verth9896a0d2019-04-10 15:11:12 -0400225 // We did a copy so the texture IDs should be different
226 REPORTER_ASSERT(reporter, origImageInfo.fTexture != genImageInfo.fTexture);
227 } else {
228 REPORTER_ASSERT(reporter, origImageInfo.fTexture == genImageInfo.fTexture);
229 }
230 } else {
231 ERRORF(reporter, "Failed to get GrMtlTextureInfo");
232 }
233#endif
Greg Daniel261b8aa2017-10-23 09:37:36 -0400234 } else {
235 REPORTER_ASSERT(reporter, false);
236 }
237
238 // Must make sure the uses of the backend texture have finished (we possibly have a
Greg Daniel26b50a42018-03-08 09:49:58 -0500239 // queued up copy) before we delete the backend texture.
Greg Daniel0a2464f2020-05-14 15:45:44 -0400240 context->flushAndSubmit();
Greg Daniel261b8aa2017-10-23 09:37:36 -0400241
Robert Phillips9b16f812019-05-17 10:01:21 -0400242 context->priv().getGpu()->testingOnly_flushGpuAndSync();
243
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400244 context->deleteBackendTexture(backendTex);
Greg Daniel261b8aa2017-10-23 09:37:36 -0400245 }
246 }
247}
248
Greg Daniel45d63032017-10-30 13:41:26 -0400249// Test that when we call makeImageSnapshot on an SkSurface we retains the same mip status as the
250// resource we took the snapshot of.
251DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrImageSnapshotMipMappedTest, reporter, ctxInfo) {
Robert Phillips6d344c32020-07-06 10:56:46 -0400252 auto context = ctxInfo.directContext();
Robert Phillips9da87e02019-02-04 13:26:26 -0500253 if (!context->priv().caps()->mipMapSupport()) {
Greg Daniel45d63032017-10-30 13:41:26 -0400254 return;
255 }
256
Robert Phillips9da87e02019-02-04 13:26:26 -0500257 auto resourceProvider = context->priv().resourceProvider();
Robert Phillips6be756b2018-01-16 15:07:54 -0500258
Greg Daniel45d63032017-10-30 13:41:26 -0400259 for (auto willUseMips : {false, true}) {
260 for (auto isWrapped : {false, true}) {
Brian Salomon7e67dca2020-07-21 09:27:25 -0400261 GrMipmapped mipMapped = willUseMips ? GrMipmapped::kYes : GrMipmapped::kNo;
Greg Daniel45d63032017-10-30 13:41:26 -0400262 sk_sp<SkSurface> surface;
Greg Danielc1ad77c2020-05-06 11:40:03 -0400263 GrBackendTexture backendTex;
264 CreateBackendTexture(context, &backendTex, kSize, kSize, kRGBA_8888_SkColorType,
265 SkColors::kTransparent, mipMapped, GrRenderable::kYes);
Greg Daniel45d63032017-10-30 13:41:26 -0400266 if (isWrapped) {
Greg Daniel45d63032017-10-30 13:41:26 -0400267 surface = SkSurface::MakeFromBackendTexture(context,
268 backendTex,
269 kTopLeft_GrSurfaceOrigin,
270 0,
Greg Danielfaa095e2017-12-19 13:15:02 -0500271 kRGBA_8888_SkColorType,
Greg Daniel45d63032017-10-30 13:41:26 -0400272 nullptr,
273 nullptr);
274 } else {
275 SkImageInfo info = SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType,
276 kPremul_SkAlphaType);
277 surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, info, 0,
278 kTopLeft_GrSurfaceOrigin, nullptr,
279 willUseMips);
280 }
281 REPORTER_ASSERT(reporter, surface);
282 if (!surface) {
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400283 context->deleteBackendTexture(backendTex);
Greg Daniel45d63032017-10-30 13:41:26 -0400284 }
285 SkGpuDevice* device = ((SkSurface_Gpu*)surface.get())->getDevice();
286 GrTextureProxy* texProxy = device->accessRenderTargetContext()->asTextureProxy();
287 REPORTER_ASSERT(reporter, mipMapped == texProxy->mipMapped());
288
Robert Phillips6be756b2018-01-16 15:07:54 -0500289 texProxy->instantiate(resourceProvider);
Brian Salomonfd98c2c2018-07-31 17:25:29 -0400290 GrTexture* texture = texProxy->peekTexture();
Greg Daniel45d63032017-10-30 13:41:26 -0400291 REPORTER_ASSERT(reporter, mipMapped == texture->texturePriv().mipMapped());
292
293 sk_sp<SkImage> image = surface->makeImageSnapshot();
294 REPORTER_ASSERT(reporter, image);
295 if (!image) {
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400296 context->deleteBackendTexture(backendTex);
Greg Daniel45d63032017-10-30 13:41:26 -0400297 }
298 texProxy = as_IB(image)->peekProxy();
299 REPORTER_ASSERT(reporter, mipMapped == texProxy->mipMapped());
300
Robert Phillips6be756b2018-01-16 15:07:54 -0500301 texProxy->instantiate(resourceProvider);
Brian Salomonfd98c2c2018-07-31 17:25:29 -0400302 texture = texProxy->peekTexture();
Greg Daniel45d63032017-10-30 13:41:26 -0400303 REPORTER_ASSERT(reporter, mipMapped == texture->texturePriv().mipMapped());
304
305 // Must flush the context to make sure all the cmds (copies, etc.) from above are sent
306 // to the gpu before we delete the backendHandle.
Greg Daniel0a2464f2020-05-14 15:45:44 -0400307 context->flushAndSubmit();
Robert Phillips9b16f812019-05-17 10:01:21 -0400308 context->priv().getGpu()->testingOnly_flushGpuAndSync();
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400309 context->deleteBackendTexture(backendTex);
Greg Daniel45d63032017-10-30 13:41:26 -0400310 }
311 }
312}
Greg Daniel8e9b4c42018-07-20 10:30:48 -0400313
314// Test that we don't create a mip mapped texture if the size is 1x1 even if the filter mode is set
315// to use mips. This test passes by not crashing or hitting asserts in code.
316DEF_GPUTEST_FOR_RENDERING_CONTEXTS(Gr1x1TextureMipMappedTest, reporter, ctxInfo) {
Robert Phillips6d344c32020-07-06 10:56:46 -0400317 auto context = ctxInfo.directContext();
Robert Phillips9da87e02019-02-04 13:26:26 -0500318 if (!context->priv().caps()->mipMapSupport()) {
Greg Daniel8e9b4c42018-07-20 10:30:48 -0400319 return;
320 }
321
322 // Make surface to draw into
323 SkImageInfo info = SkImageInfo::MakeN32(16, 16, kPremul_SkAlphaType);
324 sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info);
325
326 // Make 1x1 raster bitmap
327 SkBitmap bmp;
328 bmp.allocN32Pixels(1, 1);
329 SkPMColor* pixel = reinterpret_cast<SkPMColor*>(bmp.getPixels());
330 *pixel = 0;
331
332 sk_sp<SkImage> bmpImage = SkImage::MakeFromBitmap(bmp);
333
334 // Make sure we scale so we don't optimize out the use of mips.
335 surface->getCanvas()->scale(0.5f, 0.5f);
336
337 SkPaint paint;
338 // This should upload the image to a non mipped GrTextureProxy.
339 surface->getCanvas()->drawImage(bmpImage, 0, 0, &paint);
Greg Daniel0a2464f2020-05-14 15:45:44 -0400340 surface->flushAndSubmit();
Greg Daniel8e9b4c42018-07-20 10:30:48 -0400341
342 // Now set the filter quality to high so we use mip maps. We should find the non mipped texture
343 // in the cache for the SkImage. Since the texture is 1x1 we should just use that texture
344 // instead of trying to do a copy to a mipped texture.
345 paint.setFilterQuality(kHigh_SkFilterQuality);
346 surface->getCanvas()->drawImage(bmpImage, 0, 0, &paint);
Greg Daniel0a2464f2020-05-14 15:45:44 -0400347 surface->flushAndSubmit();
Greg Daniel8e9b4c42018-07-20 10:30:48 -0400348}
349
Greg Daniel40903af2020-01-30 14:55:05 -0500350// Create a new render target and draw 'mipmapView' into it using the provided 'filter'.
Brian Salomonbf6b9792019-08-21 09:38:10 -0400351static std::unique_ptr<GrRenderTargetContext> draw_mipmap_into_new_render_target(
Greg Danielba0ff782020-01-07 15:42:57 -0500352 GrRecordingContext* context, GrProxyProvider* proxyProvider, GrColorType colorType,
Greg Daniel40903af2020-01-30 14:55:05 -0500353 SkAlphaType alphaType, GrSurfaceProxyView mipmapView, GrSamplerState::Filter filter) {
Chris Dalton3d770272019-08-14 09:24:37 -0600354 sk_sp<GrSurfaceProxy> renderTarget = proxyProvider->createProxy(
Brian Salomon7e67dca2020-07-21 09:27:25 -0400355 mipmapView.proxy()->backendFormat(), {1, 1}, GrRenderable::kYes, 1, GrMipmapped::kNo,
Brian Salomondf1bd6d2020-03-26 20:37:01 -0400356 SkBackingFit::kApprox, SkBudgeted::kYes, GrProtected::kNo);
Greg Danielba0ff782020-01-07 15:42:57 -0500357
358 auto rtc = GrRenderTargetContext::Make(
359 context, colorType, nullptr, std::move(renderTarget), kTopLeft_GrSurfaceOrigin,
360 nullptr);
361
Michael Ludwig7c12e282020-05-29 09:54:07 -0400362 rtc->drawTexture(nullptr, std::move(mipmapView), alphaType, filter, SkBlendMode::kSrcOver,
Greg Danielc594e622019-10-15 14:01:49 -0400363 {1,1,1,1}, SkRect::MakeWH(4, 4), SkRect::MakeWH(1,1), GrAA::kYes,
Brian Salomonfc118442019-11-22 19:09:27 -0500364 GrQuadAAFlags::kAll, SkCanvas::kFast_SrcRectConstraint, SkMatrix::I(),
365 nullptr);
Chris Dalton3d770272019-08-14 09:24:37 -0600366 return rtc;
367}
368
Greg Danielf41b2bd2019-08-22 16:19:24 -0400369// Test that two opsTasks using the same mipmaps both depend on the same GrTextureResolveRenderTask.
Chris Dalton30eea6c2019-08-21 10:22:50 -0600370DEF_GPUTEST(GrManyDependentsMipMappedTest, reporter, /* options */) {
Chris Dalton30eea6c2019-08-21 10:22:50 -0600371 using Enable = GrContextOptions::Enable;
372 using Filter = GrSamplerState::Filter;
373
374 for (auto enableSortingAndReduction : {Enable::kYes, Enable::kNo}) {
375 GrMockOptions mockOptions;
376 mockOptions.fMipMapSupport = true;
377 GrContextOptions ctxOptions;
Greg Daniel93138742019-08-22 17:15:39 -0400378 ctxOptions.fReduceOpsTaskSplitting = enableSortingAndReduction;
Robert Phillipsf4f80112020-07-13 16:13:31 -0400379 sk_sp<GrDirectContext> context = GrDirectContext::MakeMock(&mockOptions, ctxOptions);
Adlai Hollerd71b7b02020-06-08 15:55:00 -0400380 GrDrawingManager* drawingManager = context->priv().drawingManager();
Chris Dalton30eea6c2019-08-21 10:22:50 -0600381 if (!context) {
Greg Danielf41b2bd2019-08-22 16:19:24 -0400382 ERRORF(reporter, "could not create mock context with fReduceOpsTaskSplitting %s.",
Chris Dalton30eea6c2019-08-21 10:22:50 -0600383 (Enable::kYes == enableSortingAndReduction) ? "enabled" : "disabled");
384 continue;
385 }
386
387 SkASSERT(context->priv().caps()->mipMapSupport());
388
389 GrBackendFormat format = context->defaultBackendFormat(
390 kRGBA_8888_SkColorType, GrRenderable::kYes);
Chris Dalton30eea6c2019-08-21 10:22:50 -0600391 GrColorType colorType = GrColorType::kRGBA_8888;
Brian Salomonfc118442019-11-22 19:09:27 -0500392 SkAlphaType alphaType = kPremul_SkAlphaType;
Chris Dalton30eea6c2019-08-21 10:22:50 -0600393
Chris Dalton30eea6c2019-08-21 10:22:50 -0600394 GrProxyProvider* proxyProvider = context->priv().proxyProvider();
395
396 // Create a mipmapped render target.
Greg Daniel47c20e82020-01-21 14:29:57 -0500397
Brian Salomonbeb7f522019-08-30 16:19:42 -0400398 sk_sp<GrTextureProxy> mipmapProxy = proxyProvider->createProxy(
Brian Salomon7e67dca2020-07-21 09:27:25 -0400399 format, {4, 4}, GrRenderable::kYes, 1, GrMipmapped::kYes, SkBackingFit::kExact,
Brian Salomondf1bd6d2020-03-26 20:37:01 -0400400 SkBudgeted::kYes, GrProtected::kNo);
Chris Dalton30eea6c2019-08-21 10:22:50 -0600401
Chris Daltonaa3cbb82019-08-21 00:01:21 -0600402 // Mark the mipmaps clean to ensure things still work properly when they won't be marked
403 // dirty again until GrRenderTask::makeClosed().
404 mipmapProxy->markMipMapsClean();
405
Greg Danielba0ff782020-01-07 15:42:57 -0500406 auto mipmapRTC = GrRenderTargetContext::Make(
407 context.get(), colorType, nullptr, mipmapProxy, kTopLeft_GrSurfaceOrigin, nullptr);
408
Michael Ludwig81d41722020-05-26 16:57:38 -0400409 mipmapRTC->clear({.1f,.2f,.3f,.4f});
Adlai Hollerd71b7b02020-06-08 15:55:00 -0400410 REPORTER_ASSERT(reporter, drawingManager->getLastRenderTask(mipmapProxy.get()));
Greg Danielf41b2bd2019-08-22 16:19:24 -0400411 // mipmapProxy's last render task should now just be the opsTask containing the clear.
Chris Dalton30eea6c2019-08-21 10:22:50 -0600412 REPORTER_ASSERT(reporter,
Adlai Hollerd71b7b02020-06-08 15:55:00 -0400413 mipmapRTC->testingOnly_PeekLastOpsTask() ==
414 drawingManager->getLastRenderTask(mipmapProxy.get()));
Chris Dalton30eea6c2019-08-21 10:22:50 -0600415
Chris Daltonaa3cbb82019-08-21 00:01:21 -0600416 // Mipmaps don't get marked dirty until makeClosed().
417 REPORTER_ASSERT(reporter, !mipmapProxy->mipMapsAreDirty());
418
Brian Salomondf1bd6d2020-03-26 20:37:01 -0400419 GrSwizzle swizzle = context->priv().caps()->getReadSwizzle(format, colorType);
Greg Daniel40903af2020-01-30 14:55:05 -0500420 GrSurfaceProxyView mipmapView(mipmapProxy, kTopLeft_GrSurfaceOrigin, swizzle);
421
Chris Dalton30eea6c2019-08-21 10:22:50 -0600422 // Draw the dirty mipmap texture into a render target.
Greg Danielba0ff782020-01-07 15:42:57 -0500423 auto rtc1 = draw_mipmap_into_new_render_target(context.get(), proxyProvider, colorType,
Greg Daniel40903af2020-01-30 14:55:05 -0500424 alphaType, mipmapView, Filter::kMipMap);
Brian Salomon3b8486a2020-04-21 12:43:26 -0400425 auto rtc1Task = sk_ref_sp(rtc1->testingOnly_PeekLastOpsTask());
Chris Dalton30eea6c2019-08-21 10:22:50 -0600426
Chris Daltonaa3cbb82019-08-21 00:01:21 -0600427 // Mipmaps should have gotten marked dirty during makeClosed, then marked clean again as
428 // soon as a GrTextureResolveRenderTask was inserted. The way we know they were resolved is
Greg Danielf41b2bd2019-08-22 16:19:24 -0400429 // if mipmapProxy->getLastRenderTask() has switched from the opsTask that drew to it, to the
Chris Daltonaa3cbb82019-08-21 00:01:21 -0600430 // task that resolved its mips.
Adlai Hollerd71b7b02020-06-08 15:55:00 -0400431 GrRenderTask* initialMipmapRegenTask = drawingManager->getLastRenderTask(mipmapProxy.get());
Chris Dalton30eea6c2019-08-21 10:22:50 -0600432 REPORTER_ASSERT(reporter, initialMipmapRegenTask);
433 REPORTER_ASSERT(reporter,
Greg Danielf41b2bd2019-08-22 16:19:24 -0400434 initialMipmapRegenTask != mipmapRTC->testingOnly_PeekLastOpsTask());
Chris Dalton30eea6c2019-08-21 10:22:50 -0600435 REPORTER_ASSERT(reporter, !mipmapProxy->mipMapsAreDirty());
Chris Dalton30eea6c2019-08-21 10:22:50 -0600436
437 // Draw the now-clean mipmap texture into a second target.
Greg Danielba0ff782020-01-07 15:42:57 -0500438 auto rtc2 = draw_mipmap_into_new_render_target(context.get(), proxyProvider, colorType,
Greg Daniel40903af2020-01-30 14:55:05 -0500439 alphaType, mipmapView, Filter::kMipMap);
Brian Salomon3b8486a2020-04-21 12:43:26 -0400440 auto rtc2Task = sk_ref_sp(rtc2->testingOnly_PeekLastOpsTask());
Chris Dalton30eea6c2019-08-21 10:22:50 -0600441
442 // Make sure the mipmap texture still has the same regen task.
Adlai Hollerd71b7b02020-06-08 15:55:00 -0400443 REPORTER_ASSERT(reporter,
444 drawingManager->getLastRenderTask(mipmapProxy.get()) == initialMipmapRegenTask);
Chris Dalton30eea6c2019-08-21 10:22:50 -0600445 SkASSERT(!mipmapProxy->mipMapsAreDirty());
446
447 // Reset everything so we can go again, this time with the first draw not mipmapped.
Greg Daniel0a2464f2020-05-14 15:45:44 -0400448 context->flushAndSubmit();
Chris Dalton30eea6c2019-08-21 10:22:50 -0600449
Chris Daltone2a903e2019-09-18 13:41:50 -0600450 // Mip regen tasks don't get added as dependencies until makeClosed().
Brian Salomon3b8486a2020-04-21 12:43:26 -0400451 REPORTER_ASSERT(reporter, rtc1Task->dependsOn(initialMipmapRegenTask));
452 REPORTER_ASSERT(reporter, rtc2Task->dependsOn(initialMipmapRegenTask));
Chris Daltone2a903e2019-09-18 13:41:50 -0600453
Chris Dalton30eea6c2019-08-21 10:22:50 -0600454 // Render something to dirty the mips.
Michael Ludwig81d41722020-05-26 16:57:38 -0400455 mipmapRTC->clear({.1f,.2f,.3f,.4f});
Brian Salomon3b8486a2020-04-21 12:43:26 -0400456 auto mipmapRTCTask = sk_ref_sp(mipmapRTC->testingOnly_PeekLastOpsTask());
457 REPORTER_ASSERT(reporter, mipmapRTCTask);
458
Greg Danielf41b2bd2019-08-22 16:19:24 -0400459 // mipmapProxy's last render task should now just be the opsTask containing the clear.
Adlai Hollerd71b7b02020-06-08 15:55:00 -0400460 REPORTER_ASSERT(reporter,
461 mipmapRTCTask.get() == drawingManager->getLastRenderTask(mipmapProxy.get()));
Chris Dalton30eea6c2019-08-21 10:22:50 -0600462
Chris Daltonaa3cbb82019-08-21 00:01:21 -0600463 // Mipmaps don't get marked dirty until makeClosed().
464 REPORTER_ASSERT(reporter, !mipmapProxy->mipMapsAreDirty());
465
Chris Dalton30eea6c2019-08-21 10:22:50 -0600466 // Draw the dirty mipmap texture into a render target, but don't do mipmap filtering.
Greg Danielba0ff782020-01-07 15:42:57 -0500467 rtc1 = draw_mipmap_into_new_render_target(context.get(), proxyProvider, colorType,
Brian Salomona3b02f52020-07-15 16:02:01 -0400468 alphaType, mipmapView, Filter::kLinear);
Chris Dalton30eea6c2019-08-21 10:22:50 -0600469
Chris Daltonaa3cbb82019-08-21 00:01:21 -0600470 // Mipmaps should have gotten marked dirty during makeClosed() when adding the dependency.
471 // Since the last draw did not use mips, they will not have been regenerated and should
472 // therefore still be dirty.
Chris Dalton30eea6c2019-08-21 10:22:50 -0600473 REPORTER_ASSERT(reporter, mipmapProxy->mipMapsAreDirty());
Chris Daltonaa3cbb82019-08-21 00:01:21 -0600474
475 // Since mips weren't regenerated, the last render task shouldn't have changed.
Adlai Hollerd71b7b02020-06-08 15:55:00 -0400476 REPORTER_ASSERT(reporter,
477 mipmapRTCTask.get() == drawingManager->getLastRenderTask(mipmapProxy.get()));
Chris Dalton30eea6c2019-08-21 10:22:50 -0600478
Chris Daltonaa3cbb82019-08-21 00:01:21 -0600479 // Draw the stil-dirty mipmap texture into a second target with mipmap filtering.
Greg Danielba0ff782020-01-07 15:42:57 -0500480 rtc2 = draw_mipmap_into_new_render_target(context.get(), proxyProvider, colorType,
Greg Daniel40903af2020-01-30 14:55:05 -0500481 alphaType, std::move(mipmapView),
482 Filter::kMipMap);
Brian Salomon3b8486a2020-04-21 12:43:26 -0400483 rtc2Task = sk_ref_sp(rtc2->testingOnly_PeekLastOpsTask());
Chris Dalton30eea6c2019-08-21 10:22:50 -0600484
Chris Daltonaa3cbb82019-08-21 00:01:21 -0600485 // Make sure the mipmap texture now has a new last render task that regenerates the mips,
486 // and that the mipmaps are now clean.
Adlai Hollerd71b7b02020-06-08 15:55:00 -0400487 auto mipRegenTask2 = drawingManager->getLastRenderTask(mipmapProxy.get());
Chris Daltone2a903e2019-09-18 13:41:50 -0600488 REPORTER_ASSERT(reporter, mipRegenTask2);
Brian Salomon3b8486a2020-04-21 12:43:26 -0400489 REPORTER_ASSERT(reporter, mipmapRTCTask.get() != mipRegenTask2);
Chris Dalton30eea6c2019-08-21 10:22:50 -0600490 SkASSERT(!mipmapProxy->mipMapsAreDirty());
Chris Daltone2a903e2019-09-18 13:41:50 -0600491
492 // Mip regen tasks don't get added as dependencies until makeClosed().
Greg Daniel0a2464f2020-05-14 15:45:44 -0400493 context->flushAndSubmit();
Brian Salomon3b8486a2020-04-21 12:43:26 -0400494 REPORTER_ASSERT(reporter, rtc2Task->dependsOn(mipRegenTask2));
Chris Dalton3d770272019-08-14 09:24:37 -0600495 }
Chris Dalton3d770272019-08-14 09:24:37 -0600496}