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