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