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