1 /*
2 * Copyright 2015 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
9 #include "tests/Test.h"
10
11
12 #ifdef SK_GL
13 #include "include/core/SkAlphaType.h"
14 #include "include/core/SkColorSpace.h"
15 #include "include/core/SkColorType.h"
16 #include "include/core/SkRefCnt.h"
17 #include "include/core/SkTypes.h"
18 #include "include/gpu/GpuTypes.h"
19 #include "include/gpu/ganesh/GrBackendSurface.h"
20 #include "include/gpu/ganesh/GrDirectContext.h"
21 #include "include/gpu/ganesh/GrTypes.h"
22 #include "include/gpu/ganesh/gl/GrGLBackendSurface.h"
23 #include "include/gpu/ganesh/gl/GrGLDirectContext.h"
24 #include "include/gpu/ganesh/gl/GrGLFunctions.h"
25 #include "include/gpu/ganesh/gl/GrGLInterface.h"
26 #include "include/gpu/ganesh/gl/GrGLTypes.h"
27 #include "include/private/base/SkDebug.h"
28 #include "include/private/base/SkTemplates.h"
29 #include "include/private/gpu/ganesh/GrTypesPriv.h"
30 #include "src/gpu/RefCntedCallback.h"
31 #include "src/gpu/Swizzle.h"
32 #include "src/gpu/ganesh/GrCaps.h"
33 #include "src/gpu/ganesh/GrColorInfo.h"
34 #include "src/gpu/ganesh/GrDirectContextPriv.h"
35 #include "src/gpu/ganesh/GrProxyProvider.h"
36 #include "src/gpu/ganesh/GrShaderCaps.h"
37 #include "src/gpu/ganesh/GrSurfaceProxy.h"
38 #include "src/gpu/ganesh/GrSurfaceProxyView.h"
39 #include "src/gpu/ganesh/GrTexture.h"
40 #include "src/gpu/ganesh/GrTextureProxy.h"
41 #include "src/gpu/ganesh/SurfaceContext.h"
42 #include "src/gpu/ganesh/SurfaceFillContext.h" // IWYU pragma: keep
43 #include "src/gpu/ganesh/gl/GrGLCaps.h"
44 #include "src/gpu/ganesh/gl/GrGLDefines.h"
45 #include "src/gpu/ganesh/gl/GrGLGpu.h"
46 #include "src/gpu/ganesh/gl/GrGLUtil.h"
47 #include "tests/CtsEnforcement.h"
48 #include "tests/TestUtils.h"
49 #include "tools/gpu/ManagedBackendTexture.h"
50 #include "tools/gpu/gl/GLTestContext.h"
51
52 #include <cstdint>
53 #include <memory>
54 #include <utility>
55
56 using namespace skia_private;
57
58 struct GrContextOptions;
59
60 using sk_gpu_test::GLTestContext;
61
cleanup(GLTestContext * glctx0,GrGLuint texID0,GLTestContext * glctx1,const sk_sp<GrDirectContext> & dContext,GrEGLImage image1)62 static void cleanup(GLTestContext* glctx0,
63 GrGLuint texID0,
64 GLTestContext* glctx1,
65 const sk_sp<GrDirectContext>& dContext,
66 GrEGLImage image1) {
67 if (glctx1) {
68 glctx1->makeCurrent();
69 if (GR_EGL_NO_IMAGE != image1) {
70 glctx1->destroyEGLImage(image1);
71 }
72 }
73
74 glctx0->makeCurrent();
75 if (texID0) {
76 GR_GL_CALL(glctx0->gl(), DeleteTextures(1, &texID0));
77 }
78 }
79
DEF_GANESH_TEST_FOR_GL_CONTEXT(EGLImageTest,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)80 DEF_GANESH_TEST_FOR_GL_CONTEXT(EGLImageTest, reporter, ctxInfo, CtsEnforcement::kApiLevel_T) {
81 auto context0 = ctxInfo.directContext();
82 sk_gpu_test::GLTestContext* glCtx0 = ctxInfo.glContext();
83
84 // Try to create a second GL context and then check if the contexts have necessary
85 // extensions to run this test.
86
87 if (kGLES_GrGLStandard != glCtx0->gl()->fStandard) {
88 return;
89 }
90 GrGLGpu* gpu0 = static_cast<GrGLGpu*>(context0->priv().getGpu());
91 if (!gpu0->glCaps().shaderCaps()->fExternalTextureSupport) {
92 return;
93 }
94
95 std::unique_ptr<GLTestContext> glCtx1 = glCtx0->makeNew();
96 if (!glCtx1) {
97 return;
98 }
99 sk_sp<GrDirectContext> context1 = GrDirectContexts::MakeGL(sk_ref_sp(glCtx1->gl()));
100 GrEGLImage image = GR_EGL_NO_IMAGE;
101 GrGLTextureInfo externalTexture;
102 externalTexture.fID = 0;
103
104 if (!context1) {
105 cleanup(glCtx0, externalTexture.fID, glCtx1.get(), context1, image);
106 return;
107 }
108
109 if (!glCtx1->gl()->hasExtension("EGL_KHR_image") ||
110 !glCtx1->gl()->hasExtension("EGL_KHR_gl_texture_2D_image")) {
111 cleanup(glCtx0, externalTexture.fID, glCtx1.get(), context1, image);
112 return;
113 }
114
115 ///////////////////////////////// CONTEXT 1 ///////////////////////////////////
116
117 // Use GL Context 1 to create a texture unknown to context 0.
118 context1->flushAndSubmit();
119 static const int kSize = 100;
120
121 auto mbet = sk_gpu_test::ManagedBackendTexture::MakeWithoutData(context1.get(),
122 kSize,
123 kSize,
124 kRGBA_8888_SkColorType,
125 skgpu::Mipmapped::kNo,
126 GrRenderable::kNo,
127 GrProtected::kNo);
128
129 if (!mbet) {
130 ERRORF(reporter, "Error creating texture for EGL Image");
131 cleanup(glCtx0, externalTexture.fID, glCtx1.get(), context1, image);
132 return;
133 }
134
135 GrGLTextureInfo texInfo;
136 if (!GrBackendTextures::GetGLTextureInfo(mbet->texture(), &texInfo)) {
137 ERRORF(reporter, "Failed to get GrGLTextureInfo");
138 return;
139 }
140
141 if (GR_GL_TEXTURE_2D != texInfo.fTarget) {
142 ERRORF(reporter, "Expected backend texture to be 2D");
143 cleanup(glCtx0, externalTexture.fID, glCtx1.get(), context1, image);
144 return;
145 }
146
147 // Wrap the texture in an EGLImage
148 image = glCtx1->texture2DToEGLImage(texInfo.fID);
149 if (GR_EGL_NO_IMAGE == image) {
150 ERRORF(reporter, "Error creating EGL Image from texture");
151 cleanup(glCtx0, externalTexture.fID, glCtx1.get(), context1, image);
152 return;
153 }
154
155 // Since we are dealing with two different GL contexts here, we need to call finish so that the
156 // clearing of the texture that happens in createTextingOnlyBackendTexture occurs before we call
157 // TexSubImage below on the other context. Otherwise, it is possible the calls get reordered and
158 // the clearing overwrites the TexSubImage writes.
159 GR_GL_CALL(glCtx1->gl(), Finish());
160
161 // Populate the texture using GL context 1. Important to use TexSubImage as TexImage orphans
162 // the EGL image. Also, this must be done after creating the EGLImage as the texture
163 // contents may not be preserved when the image is created.
164 AutoTMalloc<uint32_t> pixels(kSize * kSize);
165 for (int i = 0; i < kSize*kSize; ++i) {
166 pixels.get()[i] = 0xDDAABBCC;
167 }
168 GR_GL_CALL(glCtx1->gl(), ActiveTexture(GR_GL_TEXTURE0));
169 GR_GL_CALL(glCtx1->gl(), BindTexture(texInfo.fTarget, texInfo.fID));
170 GR_GL_CALL(glCtx1->gl(), TexSubImage2D(texInfo.fTarget, 0, 0, 0, kSize, kSize,
171 GR_GL_RGBA, GR_GL_UNSIGNED_BYTE, pixels.get()));
172 GR_GL_CALL(glCtx1->gl(), Finish());
173 // We've been making direct GL calls in GL context 1, let GrDirectContext 1 know its internal
174 // state is invalid.
175 context1->resetContext();
176
177 ///////////////////////////////// CONTEXT 0 ///////////////////////////////////
178
179 // Make a new texture ID in GL Context 0 from the EGL Image
180 glCtx0->makeCurrent();
181 externalTexture.fTarget = GR_GL_TEXTURE_EXTERNAL;
182 externalTexture.fID = glCtx0->eglImageToExternalTexture(image);
183 externalTexture.fFormat = GR_GL_RGBA8;
184 if (0 == externalTexture.fID) {
185 ERRORF(reporter, "Error converting EGL Image back to texture");
186 cleanup(glCtx0, externalTexture.fID, glCtx1.get(), context1, image);
187 return;
188 }
189
190 // Wrap this texture ID in a GrTexture
191 GrBackendTexture backendTex =
192 GrBackendTextures::MakeGL(kSize, kSize, skgpu::Mipmapped::kNo, externalTexture);
193
194 GrColorInfo colorInfo(GrColorType::kRGBA_8888, kPremul_SkAlphaType, nullptr);
195 // TODO: If I make this TopLeft origin to match resolve_origin calls for kDefault, this test
196 // fails on the Nexus5. Why?
197 GrSurfaceOrigin origin = kBottomLeft_GrSurfaceOrigin;
198 sk_sp<GrSurfaceProxy> texProxy = context0->priv().proxyProvider()->wrapBackendTexture(
199 backendTex, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo, kRW_GrIOType);
200 if (!texProxy) {
201 ERRORF(reporter, "Error wrapping external texture in GrTextureProxy.");
202 cleanup(glCtx0, externalTexture.fID, glCtx1.get(), context1, image);
203 return;
204 }
205 skgpu::Swizzle swizzle = context0->priv().caps()->getReadSwizzle(texProxy->backendFormat(),
206 colorInfo.colorType());
207 GrSurfaceProxyView view(std::move(texProxy), origin, swizzle);
208 auto surfaceContext = context0->priv().makeSC(std::move(view), colorInfo);
209
210 if (!surfaceContext) {
211 ERRORF(reporter, "Error wrapping external texture in SurfaceContext.");
212 cleanup(glCtx0, externalTexture.fID, glCtx1.get(), context1, image);
213 return;
214 }
215
216 GrTextureProxy* proxy = surfaceContext->asTextureProxy();
217 REPORTER_ASSERT(reporter, proxy->mipmapped() == skgpu::Mipmapped::kNo);
218 REPORTER_ASSERT(reporter, proxy->peekTexture()->mipmapped() == skgpu::Mipmapped::kNo);
219
220 REPORTER_ASSERT(reporter, proxy->textureType() == GrTextureType::kExternal);
221 REPORTER_ASSERT(reporter, proxy->peekTexture()->textureType() == GrTextureType::kExternal);
222 REPORTER_ASSERT(reporter, proxy->hasRestrictedSampling());
223 REPORTER_ASSERT(reporter, proxy->peekTexture()->hasRestrictedSampling());
224
225 // Should not be able to wrap as a RT
226 {
227 auto temp = context0->priv().makeSFCFromBackendTexture(colorInfo,
228 backendTex,
229 1,
230 origin,
231 /*release helper*/ nullptr);
232 if (temp) {
233 ERRORF(reporter, "Should not be able to wrap an EXTERNAL texture as a RT.");
234 }
235 }
236
237 //TestReadPixels(reporter, context0, surfaceContext.get(), pixels.get(), "EGLImageTest-read");
238
239 // We should not be able to write to an EXTERNAL texture
240 TestWritePixels(reporter, context0, surfaceContext.get(), false, "EGLImageTest-write");
241
242 // Only test RT-config
243 // TODO: why do we always need to draw to copy from an external texture?
244 TestCopyFromSurface(reporter,
245 context0,
246 surfaceContext->asSurfaceProxyRef(),
247 surfaceContext->origin(),
248 colorInfo.colorType(),
249 pixels.get(),
250 "EGLImageTest-copy");
251
252 cleanup(glCtx0, externalTexture.fID, glCtx1.get(), context1, image);
253 }
254
255 #endif // SK_GL
256