Home | History | Annotate | Download | only in tests
      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