• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/GrBackendSurface.h"
20 #include "include/gpu/GrDirectContext.h"
21 #include "include/gpu/GrTypes.h"
22 #include "include/gpu/gl/GrGLFunctions.h"
23 #include "include/gpu/gl/GrGLInterface.h"
24 #include "include/gpu/gl/GrGLTypes.h"
25 #include "include/private/base/SkDebug.h"
26 #include "include/private/base/SkTemplates.h"
27 #include "include/private/gpu/ganesh/GrTypesPriv.h"
28 #include "src/gpu/RefCntedCallback.h"
29 #include "src/gpu/Swizzle.h"
30 #include "src/gpu/ganesh/GrCaps.h"
31 #include "src/gpu/ganesh/GrColorInfo.h"
32 #include "src/gpu/ganesh/GrDirectContextPriv.h"
33 #include "src/gpu/ganesh/GrProxyProvider.h"
34 #include "src/gpu/ganesh/GrShaderCaps.h"
35 #include "src/gpu/ganesh/GrSurfaceProxy.h"
36 #include "src/gpu/ganesh/GrSurfaceProxyView.h"
37 #include "src/gpu/ganesh/GrTexture.h"
38 #include "src/gpu/ganesh/GrTextureProxy.h"
39 #include "src/gpu/ganesh/SurfaceContext.h"
40 #include "src/gpu/ganesh/SurfaceFillContext.h" // IWYU pragma: keep
41 #include "src/gpu/ganesh/gl/GrGLCaps.h"
42 #include "src/gpu/ganesh/gl/GrGLDefines_impl.h"
43 #include "src/gpu/ganesh/gl/GrGLGpu.h"
44 #include "src/gpu/ganesh/gl/GrGLUtil.h"
45 #include "tests/CtsEnforcement.h"
46 #include "tests/TestUtils.h"
47 #include "tools/gpu/ManagedBackendTexture.h"
48 #include "tools/gpu/gl/GLTestContext.h"
49 
50 #include <cstdint>
51 #include <memory>
52 #include <utility>
53 
54 using namespace skia_private;
55 
56 struct GrContextOptions;
57 
58 using sk_gpu_test::GLTestContext;
59 
cleanup(GLTestContext * glctx0,GrGLuint texID0,GLTestContext * glctx1,sk_sp<GrDirectContext> dContext,GrEGLImage image1)60 static void cleanup(GLTestContext* glctx0,
61                     GrGLuint texID0,
62                     GLTestContext* glctx1,
63                     sk_sp<GrDirectContext> dContext,
64                     GrEGLImage image1) {
65     if (glctx1) {
66         glctx1->makeCurrent();
67         if (GR_EGL_NO_IMAGE != image1) {
68             glctx1->destroyEGLImage(image1);
69         }
70     }
71 
72     glctx0->makeCurrent();
73     if (texID0) {
74         GR_GL_CALL(glctx0->gl(), DeleteTextures(1, &texID0));
75     }
76 }
77 
DEF_GANESH_TEST_FOR_GL_RENDERING_CONTEXTS(EGLImageTest,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)78 DEF_GANESH_TEST_FOR_GL_RENDERING_CONTEXTS(EGLImageTest,
79                                           reporter,
80                                           ctxInfo,
81                                           CtsEnforcement::kApiLevel_T) {
82     auto context0 = ctxInfo.directContext();
83     sk_gpu_test::GLTestContext* glCtx0 = ctxInfo.glContext();
84 
85     // Try to create a second GL context and then check if the contexts have necessary
86     // extensions to run this test.
87 
88     if (kGLES_GrGLStandard != glCtx0->gl()->fStandard) {
89         return;
90     }
91     GrGLGpu* gpu0 = static_cast<GrGLGpu*>(context0->priv().getGpu());
92     if (!gpu0->glCaps().shaderCaps()->fExternalTextureSupport) {
93         return;
94     }
95 
96     std::unique_ptr<GLTestContext> glCtx1 = glCtx0->makeNew();
97     if (!glCtx1) {
98         return;
99     }
100     sk_sp<GrDirectContext> context1 = GrDirectContext::MakeGL(sk_ref_sp(glCtx1->gl()));
101     GrEGLImage image = GR_EGL_NO_IMAGE;
102     GrGLTextureInfo externalTexture;
103     externalTexture.fID = 0;
104 
105     if (!context1) {
106         cleanup(glCtx0, externalTexture.fID, glCtx1.get(), context1, image);
107         return;
108     }
109 
110     if (!glCtx1->gl()->hasExtension("EGL_KHR_image") ||
111         !glCtx1->gl()->hasExtension("EGL_KHR_gl_texture_2D_image")) {
112         cleanup(glCtx0, externalTexture.fID, glCtx1.get(), context1, image);
113         return;
114     }
115 
116     ///////////////////////////////// CONTEXT 1 ///////////////////////////////////
117 
118     // Use GL Context 1 to create a texture unknown to context 0.
119     context1->flushAndSubmit();
120     static const int kSize = 100;
121 
122     auto mbet = sk_gpu_test::ManagedBackendTexture::MakeWithoutData(context1.get(),
123                                                                     kSize,
124                                                                     kSize,
125                                                                     kRGBA_8888_SkColorType,
126                                                                     GrMipmapped::kNo,
127                                                                     GrRenderable::kNo,
128                                                                     GrProtected::kNo);
129 
130     if (!mbet) {
131         ERRORF(reporter, "Error creating texture for EGL Image");
132         cleanup(glCtx0, externalTexture.fID, glCtx1.get(), context1, image);
133         return;
134     }
135 
136     GrGLTextureInfo texInfo;
137     if (!mbet->texture().getGLTextureInfo(&texInfo)) {
138         ERRORF(reporter, "Failed to get GrGLTextureInfo");
139         return;
140     }
141 
142     if (GR_GL_TEXTURE_2D != texInfo.fTarget) {
143         ERRORF(reporter, "Expected backend texture to be 2D");
144         cleanup(glCtx0, externalTexture.fID, glCtx1.get(), context1, image);
145         return;
146     }
147 
148     // Wrap the texture in an EGLImage
149     image = glCtx1->texture2DToEGLImage(texInfo.fID);
150     if (GR_EGL_NO_IMAGE == image) {
151         ERRORF(reporter, "Error creating EGL Image from texture");
152         cleanup(glCtx0, externalTexture.fID, glCtx1.get(), context1, image);
153         return;
154     }
155 
156     // Since we are dealing with two different GL contexts here, we need to call finish so that the
157     // clearing of the texture that happens in createTextingOnlyBackendTexture occurs before we call
158     // TexSubImage below on the other context. Otherwise, it is possible the calls get reordered and
159     // the clearing overwrites the TexSubImage writes.
160     GR_GL_CALL(glCtx1->gl(), Finish());
161 
162     // Populate the texture using GL context 1. Important to use TexSubImage as TexImage orphans
163     // the EGL image. Also, this must be done after creating the EGLImage as the texture
164     // contents may not be preserved when the image is created.
165     AutoTMalloc<uint32_t> pixels(kSize * kSize);
166     for (int i = 0; i < kSize*kSize; ++i) {
167         pixels.get()[i] = 0xDDAABBCC;
168     }
169     GR_GL_CALL(glCtx1->gl(), ActiveTexture(GR_GL_TEXTURE0));
170     GR_GL_CALL(glCtx1->gl(), BindTexture(texInfo.fTarget, texInfo.fID));
171     GR_GL_CALL(glCtx1->gl(), TexSubImage2D(texInfo.fTarget, 0, 0, 0, kSize, kSize,
172                                            GR_GL_RGBA, GR_GL_UNSIGNED_BYTE, pixels.get()));
173     GR_GL_CALL(glCtx1->gl(), Finish());
174     // We've been making direct GL calls in GL context 1, let GrDirectContext 1 know its internal
175     // state is invalid.
176     context1->resetContext();
177 
178     ///////////////////////////////// CONTEXT 0 ///////////////////////////////////
179 
180     // Make a new texture ID in GL Context 0 from the EGL Image
181     glCtx0->makeCurrent();
182     externalTexture.fTarget = GR_GL_TEXTURE_EXTERNAL;
183     externalTexture.fID = glCtx0->eglImageToExternalTexture(image);
184     externalTexture.fFormat = GR_GL_RGBA8;
185     if (0 == externalTexture.fID) {
186         ERRORF(reporter, "Error converting EGL Image back to texture");
187         cleanup(glCtx0, externalTexture.fID, glCtx1.get(), context1, image);
188         return;
189     }
190 
191     // Wrap this texture ID in a GrTexture
192     GrBackendTexture backendTex(kSize, kSize, GrMipmapped::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() == GrMipmapped::kNo);
218     REPORTER_ASSERT(reporter, proxy->peekTexture()->mipmapped() == GrMipmapped::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     SkDebugf("type: %d\n", (int)surfaceContext->asTextureProxy()->textureType());
240     // We should not be able to write to an EXTERNAL texture
241     TestWritePixels(reporter, context0, surfaceContext.get(), false, "EGLImageTest-write");
242 
243     // Only test RT-config
244     // TODO: why do we always need to draw to copy from an external texture?
245     TestCopyFromSurface(reporter,
246                         context0,
247                         surfaceContext->asSurfaceProxyRef(),
248                         surfaceContext->origin(),
249                         colorInfo.colorType(),
250                         pixels.get(),
251                         "EGLImageTest-copy");
252 
253     cleanup(glCtx0, externalTexture.fID, glCtx1.get(), context1, image);
254 }
255 
256 #endif  // SK_GL
257