Edit

kc3-lang/angle/src/tests/egl_tests/EGLStreamTest.cpp

Branch :

  • Show log

    Commit

  • Author : Martin Radev
    Date : 2016-07-11 17:59:16
    Hash : 1be913cf
    Message : Add support for ES31 context creation The dEQP test for context creation passes. SH_WEBGL3_SPEC has been added, but it should be considered whether we should keep it, remove it or rename it. It was added so that there is a webgl mapping to es 310 shaders. Check Compiler.cpp. The bison file has been modified so that some tokens from es3 can be also used in es31 as well. A separate macro ES3_1_ONLY is added so that some tokens are limited only for es 310 shaders. BUG=angleproject:1442 TEST=angle_unittests Change-Id: I2e5ca227c96046c30dc796ab934f3fda9c533eba Reviewed-on: https://chromium-review.googlesource.com/360300 Reviewed-by: Jamie Madill <jmadill@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>

  • src/tests/egl_tests/EGLStreamTest.cpp
  • //
    // Copyright 2016 The ANGLE Project Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    //
    // EGLStreamTest:
    //   Tests pertaining to egl::Stream.
    //
    
    #include <gtest/gtest.h>
    
    #include <vector>
    
    #include "media/yuvtest.inl"
    #include "OSWindow.h"
    #include "test_utils/ANGLETest.h"
    
    using namespace angle;
    
    namespace
    {
    
    class EGLStreamTest : public ANGLETest
    {
      protected:
        EGLStreamTest()
        {
            setWindowWidth(128);
            setWindowHeight(128);
            setConfigRedBits(8);
            setConfigGreenBits(8);
            setConfigBlueBits(8);
            setConfigAlphaBits(8);
            setConfigDepthBits(24);
        }
    };
    
    // Tests validation of the stream API
    TEST_P(EGLStreamTest, StreamValidationTest)
    {
        EGLWindow *window            = getEGLWindow();
        EGLDisplay display           = window->getDisplay();
        const char *extensionsString = eglQueryString(display, EGL_EXTENSIONS);
        if (strstr(extensionsString, "EGL_KHR_stream") == nullptr)
        {
            std::cout << "Stream extension not supported" << std::endl;
            return;
        }
    
        const EGLint streamAttributesBad[] = {
            EGL_STREAM_STATE_KHR,
            0,
            EGL_NONE,
            EGL_PRODUCER_FRAME_KHR,
            0,
            EGL_NONE,
            EGL_CONSUMER_FRAME_KHR,
            0,
            EGL_NONE,
            EGL_CONSUMER_LATENCY_USEC_KHR,
            -1,
            EGL_NONE,
            EGL_RED_SIZE,
            EGL_DONT_CARE,
            EGL_NONE,
        };
    
        // Validate create stream attributes
        EGLStreamKHR stream = eglCreateStreamKHR(display, &streamAttributesBad[0]);
        ASSERT_EGL_ERROR(EGL_BAD_ACCESS);
        ASSERT_EQ(EGL_NO_STREAM_KHR, stream);
    
        stream = eglCreateStreamKHR(display, &streamAttributesBad[3]);
        ASSERT_EGL_ERROR(EGL_BAD_ACCESS);
        ASSERT_EQ(EGL_NO_STREAM_KHR, stream);
    
        stream = eglCreateStreamKHR(display, &streamAttributesBad[6]);
        ASSERT_EGL_ERROR(EGL_BAD_ACCESS);
        ASSERT_EQ(EGL_NO_STREAM_KHR, stream);
    
        stream = eglCreateStreamKHR(display, &streamAttributesBad[9]);
        ASSERT_EGL_ERROR(EGL_BAD_PARAMETER);
        ASSERT_EQ(EGL_NO_STREAM_KHR, stream);
    
        stream = eglCreateStreamKHR(display, &streamAttributesBad[12]);
        ASSERT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
        ASSERT_EQ(EGL_NO_STREAM_KHR, stream);
    
        const EGLint streamAttributes[] = {
            EGL_CONSUMER_LATENCY_USEC_KHR, 0, EGL_NONE,
        };
    
        stream = eglCreateStreamKHR(EGL_NO_DISPLAY, streamAttributes);
        ASSERT_EGL_ERROR(EGL_BAD_DISPLAY);
        ASSERT_EQ(EGL_NO_STREAM_KHR, stream);
    
        // Create an actual stream
        stream = eglCreateStreamKHR(display, streamAttributes);
        ASSERT_EGL_SUCCESS();
        ASSERT_NE(EGL_NO_STREAM_KHR, stream);
    
        // Assert it is in the created state
        EGLint state;
        eglQueryStreamKHR(display, stream, EGL_STREAM_STATE_KHR, &state);
        ASSERT_EGL_SUCCESS();
        ASSERT_EQ(EGL_STREAM_STATE_CREATED_KHR, state);
    
        // Test getting and setting the latency
        EGLint latency = 10;
        eglStreamAttribKHR(display, stream, EGL_CONSUMER_LATENCY_USEC_KHR, latency);
        ASSERT_EGL_SUCCESS();
        eglQueryStreamKHR(display, stream, EGL_CONSUMER_LATENCY_USEC_KHR, &latency);
        ASSERT_EGL_SUCCESS();
        ASSERT_EQ(10, latency);
        eglStreamAttribKHR(display, stream, EGL_CONSUMER_LATENCY_USEC_KHR, -1);
        ASSERT_EGL_ERROR(EGL_BAD_PARAMETER);
        ASSERT_EQ(10, latency);
    
        // Test the 64-bit queries
        EGLuint64KHR value;
        eglQueryStreamu64KHR(display, stream, EGL_CONSUMER_FRAME_KHR, &value);
        ASSERT_EGL_SUCCESS();
        eglQueryStreamu64KHR(display, stream, EGL_PRODUCER_FRAME_KHR, &value);
        ASSERT_EGL_SUCCESS();
    
        // Destroy the stream
        eglDestroyStreamKHR(display, stream);
        ASSERT_EGL_SUCCESS();
    }
    
    // Tests validation of stream consumer gltexture API
    TEST_P(EGLStreamTest, StreamConsumerGLTextureValidationTest)
    {
        EGLWindow *window            = getEGLWindow();
        EGLDisplay display           = window->getDisplay();
        const char *extensionsString = eglQueryString(display, EGL_EXTENSIONS);
        if (strstr(extensionsString, "EGL_KHR_stream_consumer_gltexture") == nullptr)
        {
            std::cout << "Stream consumer gltexture extension not supported" << std::endl;
            return;
        }
    
        const EGLint streamAttributes[] = {
            EGL_CONSUMER_LATENCY_USEC_KHR, 0, EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR, 0, EGL_NONE,
        };
    
        EGLStreamKHR stream = eglCreateStreamKHR(display, streamAttributes);
        ASSERT_EGL_SUCCESS();
    
        EGLBoolean result = eglStreamConsumerGLTextureExternalKHR(display, stream);
        ASSERT_EGL_FALSE(result);
        ASSERT_EGL_ERROR(EGL_BAD_ACCESS);
    
        GLuint tex;
        glGenTextures(1, &tex);
        glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex);
        result = eglStreamConsumerGLTextureExternalKHR(display, stream);
        ASSERT_EGL_TRUE(result);
        ASSERT_EGL_SUCCESS();
    
        EGLint state;
        eglQueryStreamKHR(display, stream, EGL_STREAM_STATE_KHR, &state);
        ASSERT_EGL_SUCCESS();
        ASSERT_EQ(EGL_STREAM_STATE_CONNECTING_KHR, state);
    
        eglDestroyStreamKHR(display, stream);
        ASSERT_EGL_SUCCESS();
    }
    
    // Tests validation of stream consumer gltexture yuv API
    TEST_P(EGLStreamTest, StreamConsumerGLTextureYUVValidationTest)
    {
        EGLWindow *window            = getEGLWindow();
        EGLDisplay display           = window->getDisplay();
        const char *extensionsString = eglQueryString(display, EGL_EXTENSIONS);
        if (strstr(extensionsString, "EGL_NV_stream_consumer_gltexture_yuv") == nullptr)
        {
            std::cout << "Stream consumer gltexture yuv extension not supported" << std::endl;
            return;
        }
    
        const EGLint streamAttributes[] = {
            EGL_CONSUMER_LATENCY_USEC_KHR, 0, EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR, 0, EGL_NONE,
        };
    
        EGLStreamKHR stream = eglCreateStreamKHR(display, streamAttributes);
        ASSERT_EGL_SUCCESS();
    
        EGLAttrib consumerAttributesBad[] = {
            EGL_COLOR_BUFFER_TYPE,
            EGL_YUV_BUFFER_EXT,  // 0
            EGL_YUV_NUMBER_OF_PLANES_EXT,
            0,
            EGL_NONE,
            EGL_COLOR_BUFFER_TYPE,
            EGL_YUV_BUFFER_EXT,  // 5
            EGL_YUV_NUMBER_OF_PLANES_EXT,
            1,
            EGL_NONE,
            EGL_COLOR_BUFFER_TYPE,
            EGL_YUV_BUFFER_EXT,  // 10
            EGL_YUV_NUMBER_OF_PLANES_EXT,
            1,
            EGL_YUV_PLANE0_TEXTURE_UNIT_NV,
            9999,
            EGL_NONE,
            EGL_COLOR_BUFFER_TYPE,
            EGL_YUV_BUFFER_EXT,  // 17
            EGL_YUV_NUMBER_OF_PLANES_EXT,
            1,
            EGL_YUV_PLANE0_TEXTURE_UNIT_NV,
            0,
            EGL_YUV_PLANE1_TEXTURE_UNIT_NV,
            1,
            EGL_NONE,
            EGL_COLOR_BUFFER_TYPE,
            EGL_YUV_BUFFER_EXT,  // 26
            EGL_YUV_NUMBER_OF_PLANES_EXT,
            2,
            EGL_YUV_PLANE0_TEXTURE_UNIT_NV,
            0,
            EGL_YUV_PLANE1_TEXTURE_UNIT_NV,
            0,
            EGL_NONE,
        };
    
        EGLAttrib consumerAttributes[] = {
            EGL_COLOR_BUFFER_TYPE,
            EGL_YUV_BUFFER_EXT,
            EGL_YUV_NUMBER_OF_PLANES_EXT,
            2,
            EGL_YUV_PLANE0_TEXTURE_UNIT_NV,
            0,
            EGL_YUV_PLANE1_TEXTURE_UNIT_NV,
            1,
            EGL_NONE,
        };
    
        EGLBoolean result =
            eglStreamConsumerGLTextureExternalAttribsNV(display, stream, &consumerAttributesBad[0]);
        ASSERT_EGL_FALSE(result);
        ASSERT_EGL_ERROR(EGL_BAD_MATCH);
    
        result =
            eglStreamConsumerGLTextureExternalAttribsNV(display, stream, &consumerAttributesBad[5]);
        ASSERT_EGL_FALSE(result);
        ASSERT_EGL_ERROR(EGL_BAD_MATCH);
    
        result =
            eglStreamConsumerGLTextureExternalAttribsNV(display, stream, &consumerAttributesBad[10]);
        ASSERT_EGL_FALSE(result);
        ASSERT_EGL_ERROR(EGL_BAD_ACCESS);
    
        result =
            eglStreamConsumerGLTextureExternalAttribsNV(display, stream, &consumerAttributesBad[17]);
        ASSERT_EGL_FALSE(result);
        ASSERT_EGL_ERROR(EGL_BAD_MATCH);
    
        result = eglStreamConsumerGLTextureExternalAttribsNV(display, stream, consumerAttributes);
        ASSERT_EGL_FALSE(result);
        ASSERT_EGL_ERROR(EGL_BAD_ACCESS);
    
        GLuint tex[2];
        glGenTextures(2, tex);
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex[0]);
        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex[1]);
    
        result =
            eglStreamConsumerGLTextureExternalAttribsNV(display, stream, &consumerAttributesBad[26]);
        ASSERT_EGL_FALSE(result);
        ASSERT_EGL_ERROR(EGL_BAD_ACCESS);
    
        result = eglStreamConsumerGLTextureExternalAttribsNV(display, stream, consumerAttributes);
        ASSERT_EGL_TRUE(result);
        ASSERT_EGL_SUCCESS();
    
        EGLint state;
        eglQueryStreamKHR(display, stream, EGL_STREAM_STATE_KHR, &state);
        ASSERT_EGL_SUCCESS();
        ASSERT_EQ(EGL_STREAM_STATE_CONNECTING_KHR, state);
    
        eglDestroyStreamKHR(display, stream);
        ASSERT_EGL_SUCCESS();
    }
    
    // Tests that deleting a texture invalidates the associated stream
    TEST_P(EGLStreamTest, StreamConsumerGLTextureYUVDeletionTest)
    {
        EGLWindow *window            = getEGLWindow();
        EGLDisplay display           = window->getDisplay();
        const char *extensionsString = eglQueryString(display, EGL_EXTENSIONS);
        if (strstr(extensionsString, "EGL_ANGLE_stream_producer_d3d_texture_nv12") == nullptr)
        {
            std::cout << "Stream producer d3d nv12 texture not supported" << std::endl;
            return;
        }
    
        const EGLint streamAttributes[] = {
            EGL_CONSUMER_LATENCY_USEC_KHR, 0, EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR, 0, EGL_NONE,
        };
    
        EGLStreamKHR stream = eglCreateStreamKHR(display, streamAttributes);
        ASSERT_EGL_SUCCESS();
    
        EGLAttrib consumerAttributes[] = {
            EGL_COLOR_BUFFER_TYPE,
            EGL_YUV_BUFFER_EXT,
            EGL_YUV_NUMBER_OF_PLANES_EXT,
            2,
            EGL_YUV_PLANE0_TEXTURE_UNIT_NV,
            0,
            EGL_YUV_PLANE1_TEXTURE_UNIT_NV,
            1,
            EGL_NONE,
        };
    
        GLuint tex[2];
        glGenTextures(2, tex);
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex[0]);
        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex[1]);
    
        EGLBoolean result =
            eglStreamConsumerGLTextureExternalAttribsNV(display, stream, consumerAttributes);
        ASSERT_EGL_TRUE(result);
        ASSERT_EGL_SUCCESS();
    
        EGLAttrib producerAttributes[] = {
            EGL_NONE,
        };
    
        result = eglCreateStreamProducerD3DTextureNV12ANGLE(display, stream, producerAttributes);
        ASSERT_EGL_TRUE(result);
        ASSERT_EGL_SUCCESS();
    
        EGLint state;
        eglQueryStreamKHR(display, stream, EGL_STREAM_STATE_KHR, &state);
        ASSERT_EGL_SUCCESS();
        ASSERT_EQ(EGL_STREAM_STATE_EMPTY_KHR, state);
    
        // Delete the first texture, which should be enough to invalidate the stream
        glDeleteTextures(1, tex);
    
        eglQueryStreamKHR(display, stream, EGL_STREAM_STATE_KHR, &state);
        ASSERT_EGL_SUCCESS();
        ASSERT_EQ(EGL_STREAM_STATE_DISCONNECTED_KHR, state);
    
        eglDestroyStreamKHR(display, stream);
        ASSERT_EGL_SUCCESS();
    }
    
    // End2end test for rendering an NV12 texture. Renders a YUV quad, reads back the RGB values, and
    // ensures they are correct
    TEST_P(EGLStreamTest, StreamProducerTextureNV12End2End)
    {
        EGLWindow *window            = getEGLWindow();
        EGLDisplay display           = window->getDisplay();
        if (!eglDisplayExtensionEnabled(display, "EGL_ANGLE_stream_producer_d3d_texture_nv12"))
        {
            std::cout << "Stream producer d3d nv12 texture not supported" << std::endl;
            return;
        }
    
        bool useESSL3Shaders =
            getClientMajorVersion() >= 3 && extensionEnabled("GL_OES_EGL_image_external_essl3");
    
        // yuv to rgb conversion shader using Microsoft's given conversion formulas
        std::string yuvVS, yuvPS;
        if (useESSL3Shaders)
        {
            yuvVS =
                "#version 300 es\n"
                "in highp vec4 position;\n"
                "out vec2 texcoord;\n"
                "void main(void)\n"
                "{\n"
                "    gl_Position = position;\n"
                "    texcoord = (position.xy * 0.5) + 0.5;\n"
                "    texcoord.y = 1.0 - texcoord.y;\n"
                "}\n";
            yuvPS =
                "#version 300 es\n"
                "#extension GL_OES_EGL_image_external_essl3 : require\n"
                "#extension GL_NV_EGL_stream_consumer_external : require\n"
                "precision highp float;\n"
                "in vec2 texcoord;\n"
                "out vec4 color;\n"
                "uniform samplerExternalOES y;\n"
                "uniform samplerExternalOES uv\n;"
                "void main(void)\n"
                "{\n"
                "    float c = texture(y, texcoord).r - (16.0 / 256.0);\n"
                "    float d = texture(uv, texcoord).r - 0.5;\n"
                "    float e = texture(uv, texcoord).g - 0.5;\n"
                "    float r = 1.164383 * c + 1.596027 * e;\n"
                "    float g = 1.164383 * c - 0.391762 * d - 0.812968 * e;\n"
                "    float b = 1.164383 * c + 2.017232 * d;\n"
                "    color = vec4(r, g, b, 1.0);\n"
                "}\n";
        }
        else
        {
            yuvVS =
                "attribute highp vec4 position;\n"
                "varying vec2 texcoord;\n"
                "void main(void)\n"
                "{\n"
                "    gl_Position = position;\n"
                "    texcoord = (position.xy * 0.5) + 0.5;\n"
                "    texcoord.y = 1.0 - texcoord.y;\n"
                "}\n";
    
            yuvPS =
                "#extension GL_NV_EGL_stream_consumer_external : require\n"
                "precision highp float;\n"
                "varying vec2 texcoord;\n"
                "uniform samplerExternalOES y;\n"
                "uniform samplerExternalOES uv\n;"
                "void main(void)\n"
                "{\n"
                "    float c = texture2D(y, texcoord).r - (16.0 / 256.0);\n"
                "    float d = texture2D(uv, texcoord).r - 0.5;\n"
                "    float e = texture2D(uv, texcoord).g - 0.5;\n"
                "    float r = 1.164383 * c + 1.596027 * e;\n"
                "    float g = 1.164383 * c - 0.391762 * d - 0.812968 * e;\n"
                "    float b = 1.164383 * c + 2.017232 * d;\n"
                "    gl_FragColor = vec4(r, g, b, 1.0);\n"
                "}\n";
        }
    
        GLuint program = CompileProgram(yuvVS, yuvPS);
        ASSERT_NE(0u, program);
        GLuint yUniform  = glGetUniformLocation(program, "y");
        GLuint uvUniform = glGetUniformLocation(program, "uv");
    
        // Fetch the D3D11 device
        EGLDeviceEXT eglDevice;
        eglQueryDisplayAttribEXT(display, EGL_DEVICE_EXT, (EGLAttrib *)&eglDevice);
        ID3D11Device *device;
        eglQueryDeviceAttribEXT(eglDevice, EGL_D3D11_DEVICE_ANGLE, (EGLAttrib *)&device);
    
        // Create the NV12 D3D11 texture
        HRESULT res;
        D3D11_TEXTURE2D_DESC desc;
        desc.Width              = yuvtest_width;
        desc.Height             = yuvtest_height;
        desc.Format             = DXGI_FORMAT_NV12;
        desc.MipLevels          = 1;
        desc.ArraySize          = 1;
        desc.SampleDesc.Count   = 1;
        desc.SampleDesc.Quality = 0;
        desc.Usage              = D3D11_USAGE_DEFAULT;
        desc.BindFlags          = D3D11_BIND_SHADER_RESOURCE;
        desc.CPUAccessFlags     = 0;
        desc.MiscFlags          = 0;
    
        D3D11_SUBRESOURCE_DATA subres;
        subres.pSysMem          = yuvtest_data;
        subres.SysMemPitch      = yuvtest_width;
        subres.SysMemSlicePitch = yuvtest_width * yuvtest_height * 3 / 2;
    
        ID3D11Texture2D *texture = nullptr;
        res                      = device->CreateTexture2D(&desc, &subres, &texture);
    
        // Create the stream
        const EGLint streamAttributes[] = {
            EGL_CONSUMER_LATENCY_USEC_KHR, 0, EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR, 0, EGL_NONE,
        };
    
        EGLStreamKHR stream = eglCreateStreamKHR(display, streamAttributes);
        ASSERT_EGL_SUCCESS();
    
        EGLAttrib consumerAttributes[] = {
            EGL_COLOR_BUFFER_TYPE,
            EGL_YUV_BUFFER_EXT,
            EGL_YUV_NUMBER_OF_PLANES_EXT,
            2,
            EGL_YUV_PLANE0_TEXTURE_UNIT_NV,
            0,
            EGL_YUV_PLANE1_TEXTURE_UNIT_NV,
            1,
            EGL_NONE,
        };
    
        GLuint tex[2];
        glGenTextures(2, tex);
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex[0]);
        glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        ASSERT_GL_NO_ERROR();
        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex[1]);
        glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        ASSERT_GL_NO_ERROR();
    
        EGLBoolean result =
            eglStreamConsumerGLTextureExternalAttribsNV(display, stream, consumerAttributes);
        ASSERT_EGL_TRUE(result);
        ASSERT_EGL_SUCCESS();
    
        EGLAttrib producerAttributes[] = {
            EGL_NONE,
        };
    
        result = eglCreateStreamProducerD3DTextureNV12ANGLE(display, stream, producerAttributes);
        ASSERT_EGL_TRUE(result);
        ASSERT_EGL_SUCCESS();
    
        // Insert the frame
        EGLAttrib frameAttributes[] = {
            EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE, 0, EGL_NONE,
        };
        result = eglStreamPostD3DTextureNV12ANGLE(display, stream, (void *)texture, frameAttributes);
        ASSERT_EGL_TRUE(result);
        ASSERT_EGL_SUCCESS();
    
        EGLint state;
        eglQueryStreamKHR(display, stream, EGL_STREAM_STATE_KHR, &state);
        ASSERT_EGL_SUCCESS();
        ASSERT_EQ(EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR, state);
    
        eglStreamConsumerAcquireKHR(display, stream);
        ASSERT_EGL_SUCCESS();
    
        glUseProgram(program);
        glUniform1i(yUniform, 0);
        glUniform1i(uvUniform, 1);
        drawQuad(program, "position", 0.0f);
        ASSERT_GL_NO_ERROR();
    
        eglStreamConsumerReleaseKHR(display, stream);
        ASSERT_EGL_SUCCESS();
    
        eglSwapBuffers(display, window->getSurface());
        SafeRelease(texture);
    }
    
    ANGLE_INSTANTIATE_TEST(EGLStreamTest,
                           ES2_D3D9(),
                           ES2_D3D11(),
                           ES3_D3D11(),
                           ES2_OPENGL(),
                           ES3_OPENGL());
    }  // anonymous namespace