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