xref: /aosp_15_r20/external/skia/tests/EGLImageTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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