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