blob: 0268701d31338b793e4eccadf35f5fa5bea7b504 [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"
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 Daniel177e6952017-10-12 12:27:11 -040030
Greg Daniel45d63032017-10-30 13:41:26 -040031static constexpr int kSize = 8;
32
Greg Daniel177e6952017-10-12 12:27:11 -040033// Test that the correct mip map states are on the GrTextures when wrapping GrBackendTextures in
34// SkImages and SkSurfaces
35DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrWrappedMipMappedTest, reporter, ctxInfo) {
36 GrContext* context = ctxInfo.grContext();
Robert Phillips9da87e02019-02-04 13:26:26 -050037 if (!context->priv().caps()->mipMapSupport()) {
Greg Daniel261b8aa2017-10-23 09:37:36 -040038 return;
39 }
Robert Phillipsf35fd8d2018-01-22 10:48:15 -050040
Greg Daniel177e6952017-10-12 12:27:11 -040041 for (auto mipMapped : {GrMipMapped::kNo, GrMipMapped::kYes}) {
Robert Phillips9dbcdcc2019-05-13 10:40:06 -040042 for (auto renderable : {GrRenderable::kNo, GrRenderable::kYes}) {
Robert Phillips9b16f812019-05-17 10:01:21 -040043 // createBackendTexture currently doesn't support uploading data to mip maps
Greg Daniel177e6952017-10-12 12:27:11 -040044 // so we don't send any. However, we pretend there is data for the checks below which is
45 // fine since we are never actually using these textures for any work on the gpu.
Robert Phillips4bdd36f2019-06-04 11:03:06 -040046 GrBackendTexture backendTex = context->createBackendTexture(
Robert Phillips80626792019-06-04 07:16:10 -040047 kSize, kSize, kRGBA_8888_SkColorType,
Robert Phillipsda2e67a2019-07-01 15:04:06 -040048 SkColors::kTransparent, mipMapped, renderable, GrProtected::kNo);
Greg Daniel177e6952017-10-12 12:27:11 -040049
Robert Phillipse0070c02017-11-13 12:47:24 -050050 sk_sp<GrTextureProxy> proxy;
Greg Daniel177e6952017-10-12 12:27:11 -040051 sk_sp<SkImage> image;
Robert Phillips9dbcdcc2019-05-13 10:40:06 -040052 if (GrRenderable::kYes == renderable) {
Greg Daniel177e6952017-10-12 12:27:11 -040053 sk_sp<SkSurface> surface = SkSurface::MakeFromBackendTexture(
54 context,
55 backendTex,
56 kTopLeft_GrSurfaceOrigin,
57 0,
Greg Danielfaa095e2017-12-19 13:15:02 -050058 kRGBA_8888_SkColorType,
Greg Daniel177e6952017-10-12 12:27:11 -040059 nullptr,
60 nullptr);
61
62 SkGpuDevice* device = ((SkSurface_Gpu*)surface.get())->getDevice();
Robert Phillipse0070c02017-11-13 12:47:24 -050063 proxy = device->accessRenderTargetContext()->asTextureProxyRef();
Greg Daniel177e6952017-10-12 12:27:11 -040064 } else {
65 image = SkImage::MakeFromTexture(context, backendTex,
66 kTopLeft_GrSurfaceOrigin,
Greg Danielf5d87582017-12-18 14:48:15 -050067 kRGBA_8888_SkColorType,
68 kPremul_SkAlphaType, nullptr,
69 nullptr, nullptr);
Greg Danielfebdedf2020-02-05 17:06:27 -050070 const GrSurfaceProxyView* view = as_IB(image)->view(context);
71 REPORTER_ASSERT(reporter, view);
72 if (!view) {
73 context->deleteBackendTexture(backendTex);
74 return;
75 }
76 proxy = view->asTextureProxyRef();
Greg Daniel177e6952017-10-12 12:27:11 -040077 }
78 REPORTER_ASSERT(reporter, proxy);
79 if (!proxy) {
Robert Phillips5c7a25b2019-05-20 08:38:07 -040080 context->deleteBackendTexture(backendTex);
Greg Daniel177e6952017-10-12 12:27:11 -040081 return;
82 }
83
Brian Salomonfd98c2c2018-07-31 17:25:29 -040084 REPORTER_ASSERT(reporter, proxy->isInstantiated());
Greg Daniel177e6952017-10-12 12:27:11 -040085
Brian Salomonfd98c2c2018-07-31 17:25:29 -040086 GrTexture* texture = proxy->peekTexture();
Greg Daniel177e6952017-10-12 12:27:11 -040087 REPORTER_ASSERT(reporter, texture);
88 if (!texture) {
Robert Phillips5c7a25b2019-05-20 08:38:07 -040089 context->deleteBackendTexture(backendTex);
Greg Daniel177e6952017-10-12 12:27:11 -040090 return;
91 }
92
93 if (GrMipMapped::kYes == mipMapped) {
Greg Daniele252f082017-10-23 16:05:23 -040094 REPORTER_ASSERT(reporter, GrMipMapped::kYes == texture->texturePriv().mipMapped());
Robert Phillips9dbcdcc2019-05-13 10:40:06 -040095 if (GrRenderable::kYes == renderable) {
Greg Daniel177e6952017-10-12 12:27:11 -040096 REPORTER_ASSERT(reporter, texture->texturePriv().mipMapsAreDirty());
97 } else {
98 REPORTER_ASSERT(reporter, !texture->texturePriv().mipMapsAreDirty());
99 }
100 } else {
Greg Daniele252f082017-10-23 16:05:23 -0400101 REPORTER_ASSERT(reporter, GrMipMapped::kNo == texture->texturePriv().mipMapped());
Greg Daniel177e6952017-10-12 12:27:11 -0400102 }
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400103 context->deleteBackendTexture(backendTex);
Greg Daniel177e6952017-10-12 12:27:11 -0400104 }
105 }
106}
107
Greg Daniel261b8aa2017-10-23 09:37:36 -0400108// Test that we correctly copy or don't copy GrBackendTextures in the GrBackendTextureImageGenerator
109// based on if we will use mips in the draw and the mip status of the GrBackendTexture.
110DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrBackendTextureImageMipMappedTest, reporter, ctxInfo) {
Greg Daniel261b8aa2017-10-23 09:37:36 -0400111 GrContext* context = ctxInfo.grContext();
Robert Phillips9da87e02019-02-04 13:26:26 -0500112 if (!context->priv().caps()->mipMapSupport()) {
Greg Daniel261b8aa2017-10-23 09:37:36 -0400113 return;
114 }
Robert Phillipsf35fd8d2018-01-22 10:48:15 -0500115
Brian Salomonecbb0fb2020-02-28 18:07:32 -0500116 for (auto betMipMapped : {GrMipMapped::kNo, GrMipMapped::kYes}) {
117 for (auto requestMipMapped : {GrMipMapped::kNo, GrMipMapped::kYes}) {
Robert Phillips4bdd36f2019-06-04 11:03:06 -0400118 GrBackendTexture backendTex = context->createBackendTexture(
Brian Salomonecbb0fb2020-02-28 18:07:32 -0500119 kSize, kSize, kRGBA_8888_SkColorType, SkColors::kTransparent, betMipMapped,
120 GrRenderable::kNo, GrProtected::kNo);
Greg Daniel261b8aa2017-10-23 09:37:36 -0400121
Greg Daniel261b8aa2017-10-23 09:37:36 -0400122 sk_sp<SkImage> image = SkImage::MakeFromTexture(context, backendTex,
123 kTopLeft_GrSurfaceOrigin,
Greg Danielf5d87582017-12-18 14:48:15 -0500124 kRGBA_8888_SkColorType,
125 kPremul_SkAlphaType, nullptr,
126 nullptr, nullptr);
Greg Daniel261b8aa2017-10-23 09:37:36 -0400127
128 GrTextureProxy* proxy = as_IB(image)->peekProxy();
129 REPORTER_ASSERT(reporter, proxy);
130 if (!proxy) {
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400131 context->deleteBackendTexture(backendTex);
Greg Daniel261b8aa2017-10-23 09:37:36 -0400132 return;
133 }
134
Brian Salomonfd98c2c2018-07-31 17:25:29 -0400135 REPORTER_ASSERT(reporter, proxy->isInstantiated());
Greg Daniel261b8aa2017-10-23 09:37:36 -0400136
Brian Salomonfd98c2c2018-07-31 17:25:29 -0400137 sk_sp<GrTexture> texture = sk_ref_sp(proxy->peekTexture());
Greg Daniel261b8aa2017-10-23 09:37:36 -0400138 REPORTER_ASSERT(reporter, texture);
139 if (!texture) {
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400140 context->deleteBackendTexture(backendTex);
Greg Daniel261b8aa2017-10-23 09:37:36 -0400141 return;
142 }
143
144 std::unique_ptr<SkImageGenerator> imageGen = GrBackendTextureImageGenerator::Make(
Brian Osman052ef692018-03-27 09:56:31 -0400145 texture, kTopLeft_GrSurfaceOrigin, nullptr, kRGBA_8888_SkColorType,
146 kPremul_SkAlphaType, nullptr);
Greg Daniel261b8aa2017-10-23 09:37:36 -0400147 REPORTER_ASSERT(reporter, imageGen);
148 if (!imageGen) {
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400149 context->deleteBackendTexture(backendTex);
Greg Daniel261b8aa2017-10-23 09:37:36 -0400150 return;
151 }
152
153 SkIPoint origin = SkIPoint::Make(0,0);
Greg Daniel261b8aa2017-10-23 09:37:36 -0400154 SkImageInfo imageInfo = SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType,
155 kPremul_SkAlphaType);
Brian Salomonbc074a62020-03-18 10:06:13 -0400156 GrSurfaceProxyView genView = imageGen->generateTexture(
157 context, imageInfo, origin, requestMipMapped, GrImageTexGenPolicy::kDraw);
Greg Danielcc104db2020-02-03 14:17:08 -0500158 GrSurfaceProxy* genProxy = genView.proxy();
Greg Daniel261b8aa2017-10-23 09:37:36 -0400159
160 REPORTER_ASSERT(reporter, genProxy);
161 if (!genProxy) {
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400162 context->deleteBackendTexture(backendTex);
Greg Daniel261b8aa2017-10-23 09:37:36 -0400163 return;
164 }
165
Brian Salomonbeb7f522019-08-30 16:19:42 -0400166 if (genProxy->isLazy()) {
Robert Phillips9da87e02019-02-04 13:26:26 -0500167 genProxy->priv().doLazyInstantiation(context->priv().resourceProvider());
Brian Salomonfd98c2c2018-07-31 17:25:29 -0400168 } else if (!genProxy->isInstantiated()) {
Robert Phillips9da87e02019-02-04 13:26:26 -0500169 genProxy->instantiate(context->priv().resourceProvider());
Greg Daniele728f672018-01-17 10:52:04 -0500170 }
171
Brian Salomonfd98c2c2018-07-31 17:25:29 -0400172 REPORTER_ASSERT(reporter, genProxy->isInstantiated());
173 if (!genProxy->isInstantiated()) {
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400174 context->deleteBackendTexture(backendTex);
Greg Danielbddcc952018-01-24 13:22:24 -0500175 return;
176 }
Greg Daniel261b8aa2017-10-23 09:37:36 -0400177
Brian Salomonfd98c2c2018-07-31 17:25:29 -0400178 GrTexture* genTexture = genProxy->peekTexture();
Greg Daniel261b8aa2017-10-23 09:37:36 -0400179 REPORTER_ASSERT(reporter, genTexture);
180 if (!genTexture) {
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400181 context->deleteBackendTexture(backendTex);
Greg Daniel261b8aa2017-10-23 09:37:36 -0400182 return;
183 }
184
Robert Phillipsb67821d2017-12-13 15:00:45 -0500185 GrBackendTexture genBackendTex = genTexture->getBackendTexture();
Greg Daniel261b8aa2017-10-23 09:37:36 -0400186
Greg Danielbdf12ad2018-10-12 09:31:11 -0400187 if (GrBackendApi::kOpenGL == genBackendTex.backend()) {
Greg Daniel52e16d92018-04-10 09:34:07 -0400188 GrGLTextureInfo genTexInfo;
189 GrGLTextureInfo origTexInfo;
190 if (genBackendTex.getGLTextureInfo(&genTexInfo) &&
191 backendTex.getGLTextureInfo(&origTexInfo)) {
Brian Salomonecbb0fb2020-02-28 18:07:32 -0500192 if (requestMipMapped == GrMipMapped::kYes && betMipMapped == GrMipMapped::kNo) {
Greg Daniel52e16d92018-04-10 09:34:07 -0400193 // We did a copy so the texture IDs should be different
194 REPORTER_ASSERT(reporter, origTexInfo.fID != genTexInfo.fID);
195 } else {
196 REPORTER_ASSERT(reporter, origTexInfo.fID == genTexInfo.fID);
197 }
Greg Daniel261b8aa2017-10-23 09:37:36 -0400198 } else {
Greg Daniel52e16d92018-04-10 09:34:07 -0400199 ERRORF(reporter, "Failed to get GrGLTextureInfo");
Greg Daniel261b8aa2017-10-23 09:37:36 -0400200 }
Greg Daniel261b8aa2017-10-23 09:37:36 -0400201#ifdef SK_VULKAN
Greg Danielbdf12ad2018-10-12 09:31:11 -0400202 } else if (GrBackendApi::kVulkan == genBackendTex.backend()) {
Greg Daniel52e16d92018-04-10 09:34:07 -0400203 GrVkImageInfo genImageInfo;
204 GrVkImageInfo origImageInfo;
205 if (genBackendTex.getVkImageInfo(&genImageInfo) &&
206 backendTex.getVkImageInfo(&origImageInfo)) {
Brian Salomonecbb0fb2020-02-28 18:07:32 -0500207 if (requestMipMapped == GrMipMapped::kYes && betMipMapped == GrMipMapped::kNo) {
Greg Daniel52e16d92018-04-10 09:34:07 -0400208 // We did a copy so the texture IDs should be different
209 REPORTER_ASSERT(reporter, origImageInfo.fImage != genImageInfo.fImage);
210 } else {
211 REPORTER_ASSERT(reporter, origImageInfo.fImage == genImageInfo.fImage);
212 }
Greg Daniel261b8aa2017-10-23 09:37:36 -0400213 } else {
Greg Daniel52e16d92018-04-10 09:34:07 -0400214 ERRORF(reporter, "Failed to get GrVkImageInfo");
Greg Daniel261b8aa2017-10-23 09:37:36 -0400215 }
216#endif
Jim Van Verth9896a0d2019-04-10 15:11:12 -0400217#ifdef SK_METAL
218 } else if (GrBackendApi::kMetal == genBackendTex.backend()) {
219 GrMtlTextureInfo genImageInfo;
220 GrMtlTextureInfo origImageInfo;
221 if (genBackendTex.getMtlTextureInfo(&genImageInfo) &&
222 backendTex.getMtlTextureInfo(&origImageInfo)) {
Brian Salomonecbb0fb2020-02-28 18:07:32 -0500223 if (requestMipMapped == GrMipMapped::kYes && betMipMapped == GrMipMapped::kNo) {
Jim Van Verth9896a0d2019-04-10 15:11:12 -0400224 // We did a copy so the texture IDs should be different
225 REPORTER_ASSERT(reporter, origImageInfo.fTexture != genImageInfo.fTexture);
226 } else {
227 REPORTER_ASSERT(reporter, origImageInfo.fTexture == genImageInfo.fTexture);
228 }
229 } else {
230 ERRORF(reporter, "Failed to get GrMtlTextureInfo");
231 }
232#endif
Greg Daniel261b8aa2017-10-23 09:37:36 -0400233 } else {
234 REPORTER_ASSERT(reporter, false);
235 }
236
237 // Must make sure the uses of the backend texture have finished (we possibly have a
Greg Daniel26b50a42018-03-08 09:49:58 -0500238 // queued up copy) before we delete the backend texture.
239 context->flush();
Greg Daniel261b8aa2017-10-23 09:37:36 -0400240
Robert Phillips9b16f812019-05-17 10:01:21 -0400241 context->priv().getGpu()->testingOnly_flushGpuAndSync();
242
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400243 context->deleteBackendTexture(backendTex);
Greg Daniel261b8aa2017-10-23 09:37:36 -0400244 }
245 }
246}
247
Greg Daniel45d63032017-10-30 13:41:26 -0400248// Test that when we call makeImageSnapshot on an SkSurface we retains the same mip status as the
249// resource we took the snapshot of.
250DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrImageSnapshotMipMappedTest, reporter, ctxInfo) {
251 GrContext* context = ctxInfo.grContext();
Robert Phillips9da87e02019-02-04 13:26:26 -0500252 if (!context->priv().caps()->mipMapSupport()) {
Greg Daniel45d63032017-10-30 13:41:26 -0400253 return;
254 }
255
Robert Phillips9da87e02019-02-04 13:26:26 -0500256 auto resourceProvider = context->priv().resourceProvider();
Robert Phillips6be756b2018-01-16 15:07:54 -0500257
Greg Daniel45d63032017-10-30 13:41:26 -0400258 for (auto willUseMips : {false, true}) {
259 for (auto isWrapped : {false, true}) {
260 GrMipMapped mipMapped = willUseMips ? GrMipMapped::kYes : GrMipMapped::kNo;
261 sk_sp<SkSurface> surface;
Robert Phillips4bdd36f2019-06-04 11:03:06 -0400262 GrBackendTexture backendTex = context->createBackendTexture(
Robert Phillips80626792019-06-04 07:16:10 -0400263 kSize, kSize, kRGBA_8888_SkColorType,
Robert Phillipsda2e67a2019-07-01 15:04:06 -0400264 SkColors::kTransparent, mipMapped, GrRenderable::kYes, GrProtected::kNo);
Greg Daniel45d63032017-10-30 13:41:26 -0400265 if (isWrapped) {
Greg Daniel45d63032017-10-30 13:41:26 -0400266 surface = SkSurface::MakeFromBackendTexture(context,
267 backendTex,
268 kTopLeft_GrSurfaceOrigin,
269 0,
Greg Danielfaa095e2017-12-19 13:15:02 -0500270 kRGBA_8888_SkColorType,
Greg Daniel45d63032017-10-30 13:41:26 -0400271 nullptr,
272 nullptr);
273 } else {
274 SkImageInfo info = SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType,
275 kPremul_SkAlphaType);
276 surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, info, 0,
277 kTopLeft_GrSurfaceOrigin, nullptr,
278 willUseMips);
279 }
280 REPORTER_ASSERT(reporter, surface);
281 if (!surface) {
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400282 context->deleteBackendTexture(backendTex);
Greg Daniel45d63032017-10-30 13:41:26 -0400283 }
284 SkGpuDevice* device = ((SkSurface_Gpu*)surface.get())->getDevice();
285 GrTextureProxy* texProxy = device->accessRenderTargetContext()->asTextureProxy();
286 REPORTER_ASSERT(reporter, mipMapped == texProxy->mipMapped());
287
Robert Phillips6be756b2018-01-16 15:07:54 -0500288 texProxy->instantiate(resourceProvider);
Brian Salomonfd98c2c2018-07-31 17:25:29 -0400289 GrTexture* texture = texProxy->peekTexture();
Greg Daniel45d63032017-10-30 13:41:26 -0400290 REPORTER_ASSERT(reporter, mipMapped == texture->texturePriv().mipMapped());
291
292 sk_sp<SkImage> image = surface->makeImageSnapshot();
293 REPORTER_ASSERT(reporter, image);
294 if (!image) {
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400295 context->deleteBackendTexture(backendTex);
Greg Daniel45d63032017-10-30 13:41:26 -0400296 }
297 texProxy = as_IB(image)->peekProxy();
298 REPORTER_ASSERT(reporter, mipMapped == texProxy->mipMapped());
299
Robert Phillips6be756b2018-01-16 15:07:54 -0500300 texProxy->instantiate(resourceProvider);
Brian Salomonfd98c2c2018-07-31 17:25:29 -0400301 texture = texProxy->peekTexture();
Greg Daniel45d63032017-10-30 13:41:26 -0400302 REPORTER_ASSERT(reporter, mipMapped == texture->texturePriv().mipMapped());
303
304 // Must flush the context to make sure all the cmds (copies, etc.) from above are sent
305 // to the gpu before we delete the backendHandle.
306 context->flush();
Robert Phillips9b16f812019-05-17 10:01:21 -0400307 context->priv().getGpu()->testingOnly_flushGpuAndSync();
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400308 context->deleteBackendTexture(backendTex);
Greg Daniel45d63032017-10-30 13:41:26 -0400309 }
310 }
311}
Greg Daniel8e9b4c42018-07-20 10:30:48 -0400312
313// Test that we don't create a mip mapped texture if the size is 1x1 even if the filter mode is set
314// to use mips. This test passes by not crashing or hitting asserts in code.
315DEF_GPUTEST_FOR_RENDERING_CONTEXTS(Gr1x1TextureMipMappedTest, reporter, ctxInfo) {
316 GrContext* context = ctxInfo.grContext();
Robert Phillips9da87e02019-02-04 13:26:26 -0500317 if (!context->priv().caps()->mipMapSupport()) {
Greg Daniel8e9b4c42018-07-20 10:30:48 -0400318 return;
319 }
320
321 // Make surface to draw into
322 SkImageInfo info = SkImageInfo::MakeN32(16, 16, kPremul_SkAlphaType);
323 sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info);
324
325 // Make 1x1 raster bitmap
326 SkBitmap bmp;
327 bmp.allocN32Pixels(1, 1);
328 SkPMColor* pixel = reinterpret_cast<SkPMColor*>(bmp.getPixels());
329 *pixel = 0;
330
331 sk_sp<SkImage> bmpImage = SkImage::MakeFromBitmap(bmp);
332
333 // Make sure we scale so we don't optimize out the use of mips.
334 surface->getCanvas()->scale(0.5f, 0.5f);
335
336 SkPaint paint;
337 // This should upload the image to a non mipped GrTextureProxy.
338 surface->getCanvas()->drawImage(bmpImage, 0, 0, &paint);
339 surface->flush();
340
341 // Now set the filter quality to high so we use mip maps. We should find the non mipped texture
342 // in the cache for the SkImage. Since the texture is 1x1 we should just use that texture
343 // instead of trying to do a copy to a mipped texture.
344 paint.setFilterQuality(kHigh_SkFilterQuality);
345 surface->getCanvas()->drawImage(bmpImage, 0, 0, &paint);
346 surface->flush();
347}
348
Greg Daniel40903af2020-01-30 14:55:05 -0500349// Create a new render target and draw 'mipmapView' into it using the provided 'filter'.
Brian Salomonbf6b9792019-08-21 09:38:10 -0400350static std::unique_ptr<GrRenderTargetContext> draw_mipmap_into_new_render_target(
Greg Danielba0ff782020-01-07 15:42:57 -0500351 GrRecordingContext* context, GrProxyProvider* proxyProvider, GrColorType colorType,
Greg Daniel40903af2020-01-30 14:55:05 -0500352 SkAlphaType alphaType, GrSurfaceProxyView mipmapView, GrSamplerState::Filter filter) {
Chris Dalton3d770272019-08-14 09:24:37 -0600353 sk_sp<GrSurfaceProxy> renderTarget = proxyProvider->createProxy(
Brian Salomondf1bd6d2020-03-26 20:37:01 -0400354 mipmapView.proxy()->backendFormat(), {1, 1}, GrRenderable::kYes, 1, GrMipMapped::kNo,
355 SkBackingFit::kApprox, SkBudgeted::kYes, GrProtected::kNo);
Greg Danielba0ff782020-01-07 15:42:57 -0500356
357 auto rtc = GrRenderTargetContext::Make(
358 context, colorType, nullptr, std::move(renderTarget), kTopLeft_GrSurfaceOrigin,
359 nullptr);
360
Greg Daniel40903af2020-01-30 14:55:05 -0500361 rtc->drawTexture(GrNoClip(), std::move(mipmapView), alphaType, filter, SkBlendMode::kSrcOver,
Greg Danielc594e622019-10-15 14:01:49 -0400362 {1,1,1,1}, SkRect::MakeWH(4, 4), SkRect::MakeWH(1,1), GrAA::kYes,
Brian Salomonfc118442019-11-22 19:09:27 -0500363 GrQuadAAFlags::kAll, SkCanvas::kFast_SrcRectConstraint, SkMatrix::I(),
364 nullptr);
Chris Dalton3d770272019-08-14 09:24:37 -0600365 return rtc;
366}
367
Greg Danielf41b2bd2019-08-22 16:19:24 -0400368// Test that two opsTasks using the same mipmaps both depend on the same GrTextureResolveRenderTask.
Chris Dalton30eea6c2019-08-21 10:22:50 -0600369DEF_GPUTEST(GrManyDependentsMipMappedTest, reporter, /* options */) {
370 using CanClearFullscreen = GrRenderTargetContext::CanClearFullscreen;
371 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;
Chris Dalton30eea6c2019-08-21 10:22:50 -0600379 sk_sp<GrContext> context = GrContext::MakeMock(&mockOptions, ctxOptions);
380 if (!context) {
Greg Danielf41b2bd2019-08-22 16:19:24 -0400381 ERRORF(reporter, "could not create mock context with fReduceOpsTaskSplitting %s.",
Chris Dalton30eea6c2019-08-21 10:22:50 -0600382 (Enable::kYes == enableSortingAndReduction) ? "enabled" : "disabled");
383 continue;
384 }
385
386 SkASSERT(context->priv().caps()->mipMapSupport());
387
388 GrBackendFormat format = context->defaultBackendFormat(
389 kRGBA_8888_SkColorType, GrRenderable::kYes);
Chris Dalton30eea6c2019-08-21 10:22:50 -0600390 GrColorType colorType = GrColorType::kRGBA_8888;
Brian Salomonfc118442019-11-22 19:09:27 -0500391 SkAlphaType alphaType = kPremul_SkAlphaType;
Chris Dalton30eea6c2019-08-21 10:22:50 -0600392
Chris Dalton30eea6c2019-08-21 10:22:50 -0600393 GrProxyProvider* proxyProvider = context->priv().proxyProvider();
394
395 // Create a mipmapped render target.
Greg Daniel47c20e82020-01-21 14:29:57 -0500396
Brian Salomonbeb7f522019-08-30 16:19:42 -0400397 sk_sp<GrTextureProxy> mipmapProxy = proxyProvider->createProxy(
Brian Salomondf1bd6d2020-03-26 20:37:01 -0400398 format, {4, 4}, GrRenderable::kYes, 1, GrMipMapped::kYes, SkBackingFit::kExact,
399 SkBudgeted::kYes, GrProtected::kNo);
Chris Dalton30eea6c2019-08-21 10:22:50 -0600400
Chris Daltonaa3cbb82019-08-21 00:01:21 -0600401 // Mark the mipmaps clean to ensure things still work properly when they won't be marked
402 // dirty again until GrRenderTask::makeClosed().
403 mipmapProxy->markMipMapsClean();
404
Greg Danielba0ff782020-01-07 15:42:57 -0500405 auto mipmapRTC = GrRenderTargetContext::Make(
406 context.get(), colorType, nullptr, mipmapProxy, kTopLeft_GrSurfaceOrigin, nullptr);
407
Chris Dalton30eea6c2019-08-21 10:22:50 -0600408 mipmapRTC->clear(nullptr, {.1f,.2f,.3f,.4f}, CanClearFullscreen::kYes);
Chris Dalton30eea6c2019-08-21 10:22:50 -0600409 REPORTER_ASSERT(reporter, mipmapProxy->getLastRenderTask());
Greg Danielf41b2bd2019-08-22 16:19:24 -0400410 // mipmapProxy's last render task should now just be the opsTask containing the clear.
Chris Dalton30eea6c2019-08-21 10:22:50 -0600411 REPORTER_ASSERT(reporter,
Greg Danielf41b2bd2019-08-22 16:19:24 -0400412 mipmapRTC->testingOnly_PeekLastOpsTask() == mipmapProxy->getLastRenderTask());
Chris Dalton30eea6c2019-08-21 10:22:50 -0600413
Chris Daltonaa3cbb82019-08-21 00:01:21 -0600414 // Mipmaps don't get marked dirty until makeClosed().
415 REPORTER_ASSERT(reporter, !mipmapProxy->mipMapsAreDirty());
416
Brian Salomondf1bd6d2020-03-26 20:37:01 -0400417 GrSwizzle swizzle = context->priv().caps()->getReadSwizzle(format, colorType);
Greg Daniel40903af2020-01-30 14:55:05 -0500418 GrSurfaceProxyView mipmapView(mipmapProxy, kTopLeft_GrSurfaceOrigin, swizzle);
419
Chris Dalton30eea6c2019-08-21 10:22:50 -0600420 // Draw the dirty mipmap texture into a render target.
Greg Danielba0ff782020-01-07 15:42:57 -0500421 auto rtc1 = draw_mipmap_into_new_render_target(context.get(), proxyProvider, colorType,
Greg Daniel40903af2020-01-30 14:55:05 -0500422 alphaType, mipmapView, Filter::kMipMap);
Chris Dalton30eea6c2019-08-21 10:22:50 -0600423
Chris Daltonaa3cbb82019-08-21 00:01:21 -0600424 // Mipmaps should have gotten marked dirty during makeClosed, then marked clean again as
425 // soon as a GrTextureResolveRenderTask was inserted. The way we know they were resolved is
Greg Danielf41b2bd2019-08-22 16:19:24 -0400426 // if mipmapProxy->getLastRenderTask() has switched from the opsTask that drew to it, to the
Chris Daltonaa3cbb82019-08-21 00:01:21 -0600427 // task that resolved its mips.
Chris Dalton30eea6c2019-08-21 10:22:50 -0600428 GrRenderTask* initialMipmapRegenTask = mipmapProxy->getLastRenderTask();
429 REPORTER_ASSERT(reporter, initialMipmapRegenTask);
430 REPORTER_ASSERT(reporter,
Greg Danielf41b2bd2019-08-22 16:19:24 -0400431 initialMipmapRegenTask != mipmapRTC->testingOnly_PeekLastOpsTask());
Chris Dalton30eea6c2019-08-21 10:22:50 -0600432 REPORTER_ASSERT(reporter, !mipmapProxy->mipMapsAreDirty());
Chris Dalton30eea6c2019-08-21 10:22:50 -0600433
434 // Draw the now-clean mipmap texture into a second target.
Greg Danielba0ff782020-01-07 15:42:57 -0500435 auto rtc2 = draw_mipmap_into_new_render_target(context.get(), proxyProvider, colorType,
Greg Daniel40903af2020-01-30 14:55:05 -0500436 alphaType, mipmapView, Filter::kMipMap);
Chris Dalton30eea6c2019-08-21 10:22:50 -0600437
438 // Make sure the mipmap texture still has the same regen task.
439 REPORTER_ASSERT(reporter, mipmapProxy->getLastRenderTask() == initialMipmapRegenTask);
Chris Dalton30eea6c2019-08-21 10:22:50 -0600440 SkASSERT(!mipmapProxy->mipMapsAreDirty());
441
442 // Reset everything so we can go again, this time with the first draw not mipmapped.
443 context->flush();
444
Chris Daltone2a903e2019-09-18 13:41:50 -0600445 // Mip regen tasks don't get added as dependencies until makeClosed().
446 REPORTER_ASSERT(reporter,
447 rtc1->testingOnly_PeekLastOpsTask()->dependsOn(initialMipmapRegenTask));
448 REPORTER_ASSERT(reporter,
449 rtc2->testingOnly_PeekLastOpsTask()->dependsOn(initialMipmapRegenTask));
450
Chris Dalton30eea6c2019-08-21 10:22:50 -0600451 // Render something to dirty the mips.
452 mipmapRTC->clear(nullptr, {.1f,.2f,.3f,.4f}, CanClearFullscreen::kYes);
Chris Dalton30eea6c2019-08-21 10:22:50 -0600453 REPORTER_ASSERT(reporter, mipmapProxy->getLastRenderTask());
Greg Danielf41b2bd2019-08-22 16:19:24 -0400454 // mipmapProxy's last render task should now just be the opsTask containing the clear.
Chris Dalton30eea6c2019-08-21 10:22:50 -0600455 REPORTER_ASSERT(reporter,
Greg Danielf41b2bd2019-08-22 16:19:24 -0400456 mipmapRTC->testingOnly_PeekLastOpsTask() == mipmapProxy->getLastRenderTask());
Chris Dalton30eea6c2019-08-21 10:22:50 -0600457
Chris Daltonaa3cbb82019-08-21 00:01:21 -0600458 // Mipmaps don't get marked dirty until makeClosed().
459 REPORTER_ASSERT(reporter, !mipmapProxy->mipMapsAreDirty());
460
Chris Dalton30eea6c2019-08-21 10:22:50 -0600461 // Draw the dirty mipmap texture into a render target, but don't do mipmap filtering.
Greg Danielba0ff782020-01-07 15:42:57 -0500462 rtc1 = draw_mipmap_into_new_render_target(context.get(), proxyProvider, colorType,
Greg Daniel40903af2020-01-30 14:55:05 -0500463 alphaType, mipmapView, Filter::kBilerp);
Chris Dalton30eea6c2019-08-21 10:22:50 -0600464
Chris Daltonaa3cbb82019-08-21 00:01:21 -0600465 // Mipmaps should have gotten marked dirty during makeClosed() when adding the dependency.
466 // Since the last draw did not use mips, they will not have been regenerated and should
467 // therefore still be dirty.
Chris Dalton30eea6c2019-08-21 10:22:50 -0600468 REPORTER_ASSERT(reporter, mipmapProxy->mipMapsAreDirty());
Chris Daltonaa3cbb82019-08-21 00:01:21 -0600469
470 // Since mips weren't regenerated, the last render task shouldn't have changed.
Chris Dalton30eea6c2019-08-21 10:22:50 -0600471 REPORTER_ASSERT(reporter,
Greg Danielf41b2bd2019-08-22 16:19:24 -0400472 mipmapRTC->testingOnly_PeekLastOpsTask() == mipmapProxy->getLastRenderTask());
Chris Dalton30eea6c2019-08-21 10:22:50 -0600473
Chris Daltonaa3cbb82019-08-21 00:01:21 -0600474 // Draw the stil-dirty mipmap texture into a second target with mipmap filtering.
Greg Danielba0ff782020-01-07 15:42:57 -0500475 rtc2 = draw_mipmap_into_new_render_target(context.get(), proxyProvider, colorType,
Greg Daniel40903af2020-01-30 14:55:05 -0500476 alphaType, std::move(mipmapView),
477 Filter::kMipMap);
Chris Dalton30eea6c2019-08-21 10:22:50 -0600478
Chris Daltonaa3cbb82019-08-21 00:01:21 -0600479 // Make sure the mipmap texture now has a new last render task that regenerates the mips,
480 // and that the mipmaps are now clean.
Chris Daltone2a903e2019-09-18 13:41:50 -0600481 auto mipRegenTask2 = mipmapProxy->getLastRenderTask();
482 REPORTER_ASSERT(reporter, mipRegenTask2);
Chris Dalton30eea6c2019-08-21 10:22:50 -0600483 REPORTER_ASSERT(reporter,
Chris Daltone2a903e2019-09-18 13:41:50 -0600484 mipmapRTC->testingOnly_PeekLastOpsTask() != mipRegenTask2);
Chris Dalton30eea6c2019-08-21 10:22:50 -0600485 SkASSERT(!mipmapProxy->mipMapsAreDirty());
Chris Daltone2a903e2019-09-18 13:41:50 -0600486
487 // Mip regen tasks don't get added as dependencies until makeClosed().
488 context->flush();
489 REPORTER_ASSERT(reporter, rtc2->testingOnly_PeekLastOpsTask()->dependsOn(mipRegenTask2));
Chris Dalton3d770272019-08-14 09:24:37 -0600490 }
Chris Dalton3d770272019-08-14 09:24:37 -0600491}