diff options
Diffstat (limited to 'gfx/angle/src/tests/egl_tests/EGLStreamTest.cpp')
-rwxr-xr-x | gfx/angle/src/tests/egl_tests/EGLStreamTest.cpp | 547 |
1 files changed, 547 insertions, 0 deletions
diff --git a/gfx/angle/src/tests/egl_tests/EGLStreamTest.cpp b/gfx/angle/src/tests/egl_tests/EGLStreamTest.cpp new file mode 100755 index 000000000..b667cf778 --- /dev/null +++ b/gfx/angle/src/tests/egl_tests/EGLStreamTest.cpp @@ -0,0 +1,547 @@ +// +// 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 |