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 #include "TestUtils.h" 10 #if SK_SUPPORT_GPU 11 #include "GrContext.h" 12 #include "GrContextPriv.h" 13 #include "GrContextFactory.h" 14 #include "GrShaderCaps.h" 15 #include "GrSurfaceContext.h" 16 #include "gl/GrGLGpu.h" 17 #include "gl/GrGLUtil.h" 18 #include "gl/GLTestContext.h" 19 20 using sk_gpu_test::GLTestContext; 21 22 static void cleanup(GLTestContext* glctx0, GrGLuint texID0, GLTestContext* glctx1, GrContext* grctx1, 23 const GrGLTextureInfo* grbackendtex1, GrEGLImage image1) { 24 if (glctx1) { 25 glctx1->makeCurrent(); 26 if (grctx1) { 27 if (grbackendtex1) { 28 GrGLGpu* gpu1 = static_cast<GrGLGpu*>(grctx1->getGpu()); 29 GrBackendObject handle = reinterpret_cast<GrBackendObject>(grbackendtex1); 30 gpu1->deleteTestingOnlyBackendTexture(handle, false); 31 } 32 grctx1->unref(); 33 } 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 45 DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(EGLImageTest, reporter, ctxInfo) { 46 GrContext* context0 = ctxInfo.grContext(); 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->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 GrContext* context1 = GrContext::Create(kOpenGL_GrBackend, (GrBackendContext)glCtx1->gl()); 65 const GrGLTextureInfo* backendTexture1 = nullptr; 66 GrEGLImage image = GR_EGL_NO_IMAGE; 67 GrGLTextureInfo externalTexture; 68 externalTexture.fID = 0; 69 70 if (!context1) { 71 cleanup(glCtx0, externalTexture.fID, glCtx1.get(), context1, backendTexture1, image); 72 return; 73 } 74 75 if (!glCtx1->gl()->hasExtension("EGL_KHR_image") || 76 !glCtx1->gl()->hasExtension("EGL_KHR_gl_texture_2D_image")) { 77 cleanup(glCtx0, externalTexture.fID, glCtx1.get(), context1, backendTexture1, image); 78 return; 79 } 80 81 ///////////////////////////////// CONTEXT 1 /////////////////////////////////// 82 83 // Use GL Context 1 to create a texture unknown to GrContext. 84 context1->flush(); 85 GrGpu* gpu1 = context1->getGpu(); 86 static const int kSize = 100; 87 backendTexture1 = reinterpret_cast<const GrGLTextureInfo*>( 88 gpu1->createTestingOnlyBackendTexture(nullptr, kSize, kSize, kRGBA_8888_GrPixelConfig)); 89 if (!backendTexture1 || !backendTexture1->fID) { 90 ERRORF(reporter, "Error creating texture for EGL Image"); 91 cleanup(glCtx0, externalTexture.fID, glCtx1.get(), context1, backendTexture1, image); 92 return; 93 } 94 if (GR_GL_TEXTURE_2D != backendTexture1->fTarget) { 95 ERRORF(reporter, "Expected backend texture to be 2D"); 96 cleanup(glCtx0, externalTexture.fID, glCtx1.get(), context1, backendTexture1, image); 97 return; 98 } 99 100 // Wrap the texture in an EGLImage 101 image = glCtx1->texture2DToEGLImage(backendTexture1->fID); 102 if (GR_EGL_NO_IMAGE == image) { 103 ERRORF(reporter, "Error creating EGL Image from texture"); 104 cleanup(glCtx0, externalTexture.fID, glCtx1.get(), context1, backendTexture1, image); 105 return; 106 } 107 108 // Populate the texture using GL context 1. Important to use TexSubImage as TexImage orphans 109 // the EGL image. Also, this must be done after creating the EGLImage as the texture 110 // contents may not be preserved when the image is created. 111 SkAutoTMalloc<uint32_t> pixels(kSize * kSize); 112 for (int i = 0; i < kSize*kSize; ++i) { 113 pixels.get()[i] = 0xDDAABBCC; 114 } 115 GR_GL_CALL(glCtx1->gl(), ActiveTexture(GR_GL_TEXTURE0)); 116 GR_GL_CALL(glCtx1->gl(), BindTexture(backendTexture1->fTarget, backendTexture1->fID)); 117 GR_GL_CALL(glCtx1->gl(), TexSubImage2D(backendTexture1->fTarget, 0, 0, 0, kSize, kSize, 118 GR_GL_RGBA, GR_GL_UNSIGNED_BYTE, pixels.get())); 119 GR_GL_CALL(glCtx1->gl(), Finish()); 120 // We've been making direct GL calls in GL context 1, let GrContext 1 know its internal 121 // state is invalid. 122 context1->resetContext(); 123 124 ///////////////////////////////// CONTEXT 0 /////////////////////////////////// 125 126 // Make a new texture ID in GL Context 0 from the EGL Image 127 glCtx0->makeCurrent(); 128 externalTexture.fTarget = GR_GL_TEXTURE_EXTERNAL; 129 externalTexture.fID = glCtx0->eglImageToExternalTexture(image); 130 131 // Wrap this texture ID in a GrTexture 132 GrBackendTextureDesc externalDesc; 133 externalDesc.fConfig = kRGBA_8888_GrPixelConfig; 134 externalDesc.fWidth = kSize; 135 externalDesc.fHeight = kSize; 136 externalDesc.fTextureHandle = reinterpret_cast<GrBackendObject>(&externalTexture); 137 138 sk_sp<GrSurfaceContext> surfaceContext = context0->contextPriv().makeBackendSurfaceContext( 139 externalDesc, nullptr); 140 141 if (!surfaceContext) { 142 ERRORF(reporter, "Error wrapping external texture in GrSurfaceContext."); 143 cleanup(glCtx0, externalTexture.fID, glCtx1.get(), context1, backendTexture1, image); 144 return; 145 } 146 147 // Should not be able to wrap as a RT 148 { 149 externalDesc.fFlags = kRenderTarget_GrBackendTextureFlag; 150 151 sk_sp<GrSurfaceContext> temp = context0->contextPriv().makeBackendSurfaceContext( 152 externalDesc, nullptr); 153 if (temp) { 154 ERRORF(reporter, "Should not be able to wrap an EXTERNAL texture as a RT."); 155 } 156 externalDesc.fFlags = kNone_GrBackendTextureFlag; 157 } 158 159 // Should not be able to wrap with a sample count 160 { 161 externalDesc.fSampleCnt = 4; 162 sk_sp<GrSurfaceContext> temp = context0->contextPriv().makeBackendSurfaceContext( 163 externalDesc, nullptr); 164 if (temp) { 165 ERRORF(reporter, "Should not be able to wrap an EXTERNAL texture with MSAA."); 166 } 167 externalDesc.fSampleCnt = 0; 168 } 169 170 test_read_pixels(reporter, surfaceContext.get(), pixels.get(), "EGLImageTest-read"); 171 172 // We should not be able to write to a EXTERNAL texture 173 test_write_pixels(reporter, surfaceContext.get(), false, "EGLImageTest-write"); 174 175 // Only test RT-config 176 // TODO: why do we always need to draw to copy from an external texture? 177 test_copy_from_surface(reporter, context0, surfaceContext->asSurfaceProxy(), 178 pixels.get(), true, "EGLImageTest-copy"); 179 180 cleanup(glCtx0, externalTexture.fID, glCtx1.get(), context1, backendTexture1, image); 181 } 182 183 #endif 184