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 #if SK_SUPPORT_GPU
11
12 #include "GrBackendSurface.h"
13 #include "GrBackendTextureImageGenerator.h"
14 #include "GrContext.h"
15 #include "GrContextPriv.h"
16 #include "GrGpu.h"
17 #include "GrRenderTargetContext.h"
18 #include "GrSemaphore.h"
19 #include "GrSurfaceProxyPriv.h"
20 #include "GrTest.h"
21 #include "GrTexturePriv.h"
22 #include "GrTextureProxy.h"
23 #include "SkCanvas.h"
24 #include "SkImage_Base.h"
25 #include "SkGpuDevice.h"
26 #include "SkPoint.h"
27 #include "SkSurface.h"
28 #include "SkSurface_Gpu.h"
29 #include "Test.h"
30
31 static constexpr int kSize = 8;
32
33 // Test that the correct mip map states are on the GrTextures when wrapping GrBackendTextures in
34 // SkImages and SkSurfaces
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrWrappedMipMappedTest,reporter,ctxInfo)35 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrWrappedMipMappedTest, reporter, ctxInfo) {
36 GrContext* context = ctxInfo.grContext();
37 if (!context->caps()->mipMapSupport()) {
38 return;
39 }
40 GrGpu* gpu = context->contextPriv().getGpu();
41
42 for (auto mipMapped : {GrMipMapped::kNo, GrMipMapped::kYes}) {
43 for (auto isRT : {false, true}) {
44 // CreateTestingOnlyBackendTexture currently doesn't support uploading data to mip maps
45 // 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.
47 GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture(
48 nullptr, kSize, kSize, kRGBA_8888_GrPixelConfig, isRT, mipMapped);
49
50 sk_sp<GrTextureProxy> proxy;
51 sk_sp<SkImage> image;
52 if (isRT) {
53 sk_sp<SkSurface> surface = SkSurface::MakeFromBackendTexture(
54 context,
55 backendTex,
56 kTopLeft_GrSurfaceOrigin,
57 0,
58 kRGBA_8888_SkColorType,
59 nullptr,
60 nullptr);
61
62 SkGpuDevice* device = ((SkSurface_Gpu*)surface.get())->getDevice();
63 proxy = device->accessRenderTargetContext()->asTextureProxyRef();
64 } else {
65 image = SkImage::MakeFromTexture(context, backendTex,
66 kTopLeft_GrSurfaceOrigin,
67 kRGBA_8888_SkColorType,
68 kPremul_SkAlphaType, nullptr,
69 nullptr, nullptr);
70 proxy = as_IB(image)->asTextureProxyRef();
71 }
72 REPORTER_ASSERT(reporter, proxy);
73 if (!proxy) {
74 gpu->deleteTestingOnlyBackendTexture(&backendTex);
75 return;
76 }
77
78 REPORTER_ASSERT(reporter, proxy->priv().isInstantiated());
79
80 GrTexture* texture = proxy->priv().peekTexture();
81 REPORTER_ASSERT(reporter, texture);
82 if (!texture) {
83 gpu->deleteTestingOnlyBackendTexture(&backendTex);
84 return;
85 }
86
87 if (GrMipMapped::kYes == mipMapped) {
88 REPORTER_ASSERT(reporter, GrMipMapped::kYes == texture->texturePriv().mipMapped());
89 if (isRT) {
90 REPORTER_ASSERT(reporter, texture->texturePriv().mipMapsAreDirty());
91 } else {
92 REPORTER_ASSERT(reporter, !texture->texturePriv().mipMapsAreDirty());
93 }
94 } else {
95 REPORTER_ASSERT(reporter, GrMipMapped::kNo == texture->texturePriv().mipMapped());
96 }
97 gpu->deleteTestingOnlyBackendTexture(&backendTex);
98 }
99 }
100 }
101
102 // Test that we correctly copy or don't copy GrBackendTextures in the GrBackendTextureImageGenerator
103 // based on if we will use mips in the draw and the mip status of the GrBackendTexture.
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrBackendTextureImageMipMappedTest,reporter,ctxInfo)104 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrBackendTextureImageMipMappedTest, reporter, ctxInfo) {
105 GrContext* context = ctxInfo.grContext();
106 if (!context->caps()->mipMapSupport()) {
107 return;
108 }
109 GrGpu* gpu = context->contextPriv().getGpu();
110
111 for (auto mipMapped : {GrMipMapped::kNo, GrMipMapped::kYes}) {
112 for (auto willUseMips : {false, true}) {
113 GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture(
114 nullptr, kSize, kSize, kRGBA_8888_GrPixelConfig, false, mipMapped);
115
116 sk_sp<SkImage> image = SkImage::MakeFromTexture(context, backendTex,
117 kTopLeft_GrSurfaceOrigin,
118 kRGBA_8888_SkColorType,
119 kPremul_SkAlphaType, nullptr,
120 nullptr, nullptr);
121
122 GrTextureProxy* proxy = as_IB(image)->peekProxy();
123 REPORTER_ASSERT(reporter, proxy);
124 if (!proxy) {
125 gpu->deleteTestingOnlyBackendTexture(&backendTex);
126 return;
127 }
128
129 REPORTER_ASSERT(reporter, proxy->priv().isInstantiated());
130
131 sk_sp<GrTexture> texture = sk_ref_sp(proxy->priv().peekTexture());
132 REPORTER_ASSERT(reporter, texture);
133 if (!texture) {
134 gpu->deleteTestingOnlyBackendTexture(&backendTex);
135 return;
136 }
137
138 std::unique_ptr<SkImageGenerator> imageGen = GrBackendTextureImageGenerator::Make(
139 texture, kTopLeft_GrSurfaceOrigin, nullptr, kPremul_SkAlphaType, nullptr);
140 REPORTER_ASSERT(reporter, imageGen);
141 if (!imageGen) {
142 gpu->deleteTestingOnlyBackendTexture(&backendTex);
143 return;
144 }
145
146 SkIPoint origin = SkIPoint::Make(0,0);
147 // The transfer function behavior isn't used in the generator so set we set it
148 // arbitrarily here.
149 SkTransferFunctionBehavior behavior = SkTransferFunctionBehavior::kIgnore;
150 SkImageInfo imageInfo = SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType,
151 kPremul_SkAlphaType);
152 sk_sp<GrTextureProxy> genProxy = imageGen->generateTexture(context, imageInfo,
153 origin, behavior,
154 willUseMips);
155
156 REPORTER_ASSERT(reporter, genProxy);
157 if (!genProxy) {
158 gpu->deleteTestingOnlyBackendTexture(&backendTex);
159 return;
160 }
161
162 if (GrSurfaceProxy::LazyState::kNot != genProxy->lazyInstantiationState()) {
163 genProxy->priv().doLazyInstantiation(context->contextPriv().resourceProvider());
164 } else if (!genProxy->priv().isInstantiated()) {
165 genProxy->instantiate(context->contextPriv().resourceProvider());
166 }
167
168 REPORTER_ASSERT(reporter, genProxy->priv().isInstantiated());
169 if (!genProxy->priv().isInstantiated()) {
170 gpu->deleteTestingOnlyBackendTexture(&backendTex);
171 return;
172 }
173
174 GrTexture* genTexture = genProxy->priv().peekTexture();
175 REPORTER_ASSERT(reporter, genTexture);
176 if (!genTexture) {
177 gpu->deleteTestingOnlyBackendTexture(&backendTex);
178 return;
179 }
180
181 GrBackendTexture genBackendTex = genTexture->getBackendTexture();
182
183 if (const GrGLTextureInfo* genTexInfo = genBackendTex.getGLTextureInfo()) {
184 const GrGLTextureInfo* origTexInfo = backendTex.getGLTextureInfo();
185 if (willUseMips && GrMipMapped::kNo == mipMapped) {
186 // We did a copy so the texture IDs should be different
187 REPORTER_ASSERT(reporter, origTexInfo->fID != genTexInfo->fID);
188 } else {
189 REPORTER_ASSERT(reporter, origTexInfo->fID == genTexInfo->fID);
190 }
191 #ifdef SK_VULKAN
192 } else if (const GrVkImageInfo* genImageInfo = genBackendTex.getVkImageInfo()) {
193 const GrVkImageInfo* origImageInfo = backendTex.getVkImageInfo();
194 if (willUseMips && GrMipMapped::kNo == mipMapped) {
195 // We did a copy so the texture IDs should be different
196 REPORTER_ASSERT(reporter, origImageInfo->fImage != genImageInfo->fImage);
197 } else {
198 REPORTER_ASSERT(reporter, origImageInfo->fImage == genImageInfo->fImage);
199 }
200 #endif
201 } else {
202 REPORTER_ASSERT(reporter, false);
203 }
204
205 // Must make sure the uses of the backend texture have finished (we possibly have a
206 // queued up copy) before we delete the backend texture. Thus we use readPixels here
207 // just to force the synchronization.
208 sk_sp<GrSurfaceContext> surfContext =
209 context->contextPriv().makeWrappedSurfaceContext(genProxy);
210
211 SkBitmap bitmap;
212 bitmap.allocPixels(imageInfo);
213 surfContext->readPixels(imageInfo, bitmap.getPixels(), 0, 0, 0, 0);
214
215 gpu->deleteTestingOnlyBackendTexture(&backendTex);
216 }
217 }
218 }
219
220 // Test that when we call makeImageSnapshot on an SkSurface we retains the same mip status as the
221 // resource we took the snapshot of.
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrImageSnapshotMipMappedTest,reporter,ctxInfo)222 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrImageSnapshotMipMappedTest, reporter, ctxInfo) {
223 GrContext* context = ctxInfo.grContext();
224 if (!context->caps()->mipMapSupport()) {
225 return;
226 }
227
228 auto resourceProvider = context->contextPriv().resourceProvider();
229 GrGpu* gpu = context->contextPriv().getGpu();
230
231 for (auto willUseMips : {false, true}) {
232 for (auto isWrapped : {false, true}) {
233 GrMipMapped mipMapped = willUseMips ? GrMipMapped::kYes : GrMipMapped::kNo;
234 sk_sp<SkSurface> surface;
235 GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture(
236 nullptr, kSize, kSize, kRGBA_8888_GrPixelConfig, true, mipMapped);
237 if (isWrapped) {
238 surface = SkSurface::MakeFromBackendTexture(context,
239 backendTex,
240 kTopLeft_GrSurfaceOrigin,
241 0,
242 kRGBA_8888_SkColorType,
243 nullptr,
244 nullptr);
245 } else {
246 SkImageInfo info = SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType,
247 kPremul_SkAlphaType);
248 surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, info, 0,
249 kTopLeft_GrSurfaceOrigin, nullptr,
250 willUseMips);
251 }
252 REPORTER_ASSERT(reporter, surface);
253 if (!surface) {
254 gpu->deleteTestingOnlyBackendTexture(&backendTex);
255 }
256 SkGpuDevice* device = ((SkSurface_Gpu*)surface.get())->getDevice();
257 GrTextureProxy* texProxy = device->accessRenderTargetContext()->asTextureProxy();
258 REPORTER_ASSERT(reporter, mipMapped == texProxy->mipMapped());
259
260 texProxy->instantiate(resourceProvider);
261 GrTexture* texture = texProxy->priv().peekTexture();
262 REPORTER_ASSERT(reporter, mipMapped == texture->texturePriv().mipMapped());
263
264 sk_sp<SkImage> image = surface->makeImageSnapshot();
265 REPORTER_ASSERT(reporter, image);
266 if (!image) {
267 gpu->deleteTestingOnlyBackendTexture(&backendTex);
268 }
269 texProxy = as_IB(image)->peekProxy();
270 REPORTER_ASSERT(reporter, mipMapped == texProxy->mipMapped());
271
272 texProxy->instantiate(resourceProvider);
273 texture = texProxy->priv().peekTexture();
274 REPORTER_ASSERT(reporter, mipMapped == texture->texturePriv().mipMapped());
275
276 // Must flush the context to make sure all the cmds (copies, etc.) from above are sent
277 // to the gpu before we delete the backendHandle.
278 context->flush();
279 gpu->deleteTestingOnlyBackendTexture(&backendTex);
280 }
281 }
282 }
283
284 #endif
285