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 "Test.h"
9 #if SK_SUPPORT_GPU
10 #include "GrContext.h"
11 #include "GrContextFactory.h"
12 #include "gl/GrGLGpu.h"
13 #include "gl/GrGLUtil.h"
14 #include "gl/SkGLContext.h"
15 
cleanup(SkGLContext * glctx0,GrGLuint texID0,SkGLContext * glctx1,GrContext * grctx1,const GrGLTextureInfo * grbackendtex1,GrEGLImage image1)16 static void cleanup(SkGLContext* glctx0, GrGLuint texID0, SkGLContext* glctx1, GrContext* grctx1,
17                     const GrGLTextureInfo* grbackendtex1, GrEGLImage image1) {
18     if (glctx1) {
19         glctx1->makeCurrent();
20         if (grctx1) {
21             if (grbackendtex1) {
22                 GrGLGpu* gpu1 = static_cast<GrGLGpu*>(grctx1->getGpu());
23                 GrBackendObject handle = reinterpret_cast<GrBackendObject>(grbackendtex1);
24                 gpu1->deleteTestingOnlyBackendTexture(handle, false);
25             }
26             grctx1->unref();
27         }
28         if (GR_EGL_NO_IMAGE != image1) {
29             glctx1->destroyEGLImage(image1);
30         }
31     }
32 
33     glctx0->makeCurrent();
34     if (texID0) {
35         GR_GL_CALL(glctx0->gl(), DeleteTextures(1, &texID0));
36     }
37 }
38 
test_read_pixels(skiatest::Reporter * reporter,GrContext * context,GrTexture * externalTexture,uint32_t expectedPixelValues[])39 static void test_read_pixels(skiatest::Reporter* reporter, GrContext* context,
40                              GrTexture* externalTexture, uint32_t expectedPixelValues[]) {
41     int pixelCnt = externalTexture->width() * externalTexture->height();
42     SkAutoTMalloc<uint32_t> pixels(pixelCnt);
43     memset(pixels.get(), 0, sizeof(uint32_t)*pixelCnt);
44     bool read = externalTexture->readPixels(0, 0, externalTexture->width(),
45                                             externalTexture->height(), kRGBA_8888_GrPixelConfig,
46                                             pixels.get());
47     if (!read) {
48         ERRORF(reporter, "Error reading external texture.");
49     }
50     for (int i = 0; i < pixelCnt; ++i) {
51         if (pixels.get()[i] != expectedPixelValues[i]) {
52             ERRORF(reporter, "Error, external texture pixel value %d should be 0x%08x,"
53                              " got 0x%08x.", i, expectedPixelValues[i], pixels.get()[i]);
54             break;
55         }
56     }
57 }
58 
test_write_pixels(skiatest::Reporter * reporter,GrContext * context,GrTexture * externalTexture)59 static void test_write_pixels(skiatest::Reporter* reporter, GrContext* context,
60                               GrTexture* externalTexture) {
61     int pixelCnt = externalTexture->width() * externalTexture->height();
62     SkAutoTMalloc<uint32_t> pixels(pixelCnt);
63     memset(pixels.get(), 0, sizeof(uint32_t)*pixelCnt);
64     bool write = externalTexture->writePixels(0, 0, 0, 0, kRGBA_8888_GrPixelConfig, pixels.get());
65     REPORTER_ASSERT_MESSAGE(reporter, !write, "Should not be able to write to a EXTERNAL"
66                                               " texture.");
67 }
68 
test_copy_surface(skiatest::Reporter * reporter,GrContext * context,GrTexture * externalTexture,uint32_t expectedPixelValues[])69 static void test_copy_surface(skiatest::Reporter* reporter, GrContext* context,
70                               GrTexture* externalTexture, uint32_t expectedPixelValues[]) {
71     GrSurfaceDesc copyDesc;
72     copyDesc.fConfig = kRGBA_8888_GrPixelConfig;
73     copyDesc.fWidth = externalTexture->width();
74     copyDesc.fHeight = externalTexture->height();
75     copyDesc.fFlags = kRenderTarget_GrSurfaceFlag;
76     SkAutoTUnref<GrTexture> copy(context->textureProvider()->createTexture(
77             copyDesc, SkBudgeted::kYes));
78     context->copySurface(copy, externalTexture);
79     test_read_pixels(reporter, context, copy, expectedPixelValues);
80 }
81 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(EGLImageTest,reporter,context0,glCtx0)82 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(EGLImageTest, reporter, context0, glCtx0) {
83     // Try to create a second GL context and then check if the contexts have necessary
84     // extensions to run this test.
85 
86     if (kGLES_GrGLStandard != glCtx0->gl()->fStandard) {
87         return;
88     }
89     GrGLGpu* gpu0 = static_cast<GrGLGpu*>(context0->getGpu());
90     if (!gpu0->glCaps().externalTextureSupport()) {
91         return;
92     }
93 
94     SkAutoTDelete<SkGLContext> glCtx1 = glCtx0->createNew();
95     if (!glCtx1) {
96         return;
97     }
98     GrContext* context1 = GrContext::Create(kOpenGL_GrBackend, (GrBackendContext)glCtx1->gl());
99     const GrGLTextureInfo* backendTexture1 = nullptr;
100     GrEGLImage image = GR_EGL_NO_IMAGE;
101     GrGLTextureInfo externalTexture;
102     externalTexture.fID = 0;
103 
104     if (!context1) {
105         cleanup(glCtx0, externalTexture.fID, glCtx1, context1, backendTexture1, 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, context1, backendTexture1, image);
112         return;
113     }
114 
115     ///////////////////////////////// CONTEXT 1 ///////////////////////////////////
116 
117     // Use GL Context 1 to create a texture unknown to GrContext.
118     context1->flush();
119     GrGpu* gpu1 = context1->getGpu();
120     static const int kSize = 100;
121     backendTexture1 = reinterpret_cast<const GrGLTextureInfo*>(
122         gpu1->createTestingOnlyBackendTexture(nullptr, kSize, kSize, kRGBA_8888_GrPixelConfig));
123     if (!backendTexture1 || !backendTexture1->fID) {
124         ERRORF(reporter, "Error creating texture for EGL Image");
125         cleanup(glCtx0, externalTexture.fID, glCtx1, context1, backendTexture1, image);
126         return;
127     }
128     if (GR_GL_TEXTURE_2D != backendTexture1->fTarget) {
129         ERRORF(reporter, "Expected backend texture to be 2D");
130         cleanup(glCtx0, externalTexture.fID, glCtx1, context1, backendTexture1, image);
131         return;
132     }
133 
134     // Wrap the texture in an EGLImage
135     image = glCtx1->texture2DToEGLImage(backendTexture1->fID);
136     if (GR_EGL_NO_IMAGE == image) {
137         ERRORF(reporter, "Error creating EGL Image from texture");
138         cleanup(glCtx0, externalTexture.fID, glCtx1, context1, backendTexture1, image);
139         return;
140     }
141 
142     // Populate the texture using GL context 1. Important to use TexSubImage as TexImage orphans
143     // the EGL image. Also, this must be done after creating the EGLImage as the texture
144     // contents may not be preserved when the image is created.
145     SkAutoTMalloc<uint32_t> pixels(kSize * kSize);
146     for (int i = 0; i < kSize*kSize; ++i) {
147         pixels.get()[i] = 0xDDAABBCC;
148     }
149     GR_GL_CALL(glCtx1->gl(), ActiveTexture(GR_GL_TEXTURE0));
150     GR_GL_CALL(glCtx1->gl(), BindTexture(backendTexture1->fTarget, backendTexture1->fID));
151     GR_GL_CALL(glCtx1->gl(), TexSubImage2D(backendTexture1->fTarget, 0, 0, 0, kSize, kSize,
152                                            GR_GL_RGBA, GR_GL_UNSIGNED_BYTE, pixels.get()));
153     GR_GL_CALL(glCtx1->gl(), Finish());
154     // We've been making direct GL calls in GL context 1, let GrContext 1 know its internal
155     // state is invalid.
156     context1->resetContext();
157 
158     ///////////////////////////////// CONTEXT 0 ///////////////////////////////////
159 
160     // Make a new texture ID in GL Context 0 from the EGL Image
161     glCtx0->makeCurrent();
162     externalTexture.fTarget = GR_GL_TEXTURE_EXTERNAL;
163     externalTexture.fID = glCtx0->eglImageToExternalTexture(image);
164 
165     // Wrap this texture ID in a GrTexture
166     GrBackendTextureDesc externalDesc;
167     externalDesc.fConfig = kRGBA_8888_GrPixelConfig;
168     externalDesc.fWidth = kSize;
169     externalDesc.fHeight = kSize;
170     externalDesc.fTextureHandle = reinterpret_cast<GrBackendObject>(&externalTexture);
171     SkAutoTUnref<GrTexture> externalTextureObj(
172         context0->textureProvider()->wrapBackendTexture(externalDesc));
173     if (!externalTextureObj) {
174         ERRORF(reporter, "Error wrapping external texture in GrTexture.");
175         cleanup(glCtx0, externalTexture.fID, glCtx1, context1, backendTexture1, image);
176         return;
177     }
178 
179     // Should not be able to wrap as a RT
180     externalDesc.fFlags = kRenderTarget_GrBackendTextureFlag;
181     SkAutoTUnref<GrTexture> externalTextureRTObj(
182         context0->textureProvider()->wrapBackendTexture(externalDesc));
183     if (externalTextureRTObj) {
184         ERRORF(reporter, "Should not be able to wrap an EXTERNAL texture as a RT.");
185     }
186     externalDesc.fFlags = kNone_GrBackendTextureFlag;
187 
188     // Should not be able to wrap with a sample count
189     externalDesc.fSampleCnt = 4;
190     SkAutoTUnref<GrTexture> externalTextureMSAAObj(
191         context0->textureProvider()->wrapBackendTexture(externalDesc));
192     if (externalTextureMSAAObj) {
193         ERRORF(reporter, "Should not be able to wrap an EXTERNAL texture with MSAA.");
194     }
195     externalDesc.fSampleCnt = 0;
196 
197     test_read_pixels(reporter, context0, externalTextureObj, pixels.get());
198 
199     test_write_pixels(reporter, context0, externalTextureObj);
200 
201     test_copy_surface(reporter, context0, externalTextureObj, pixels.get());
202 
203     cleanup(glCtx0, externalTexture.fID, glCtx1, context1, backendTexture1, image);
204 }
205 
206 #endif
207