diff options
Diffstat (limited to 'tests/unittests/unittests.cpp')
-rw-r--r-- | tests/unittests/unittests.cpp | 802 |
1 files changed, 781 insertions, 21 deletions
diff --git a/tests/unittests/unittests.cpp b/tests/unittests/unittests.cpp index 7ae84da3c..99cbb6117 100644 --- a/tests/unittests/unittests.cpp +++ b/tests/unittests/unittests.cpp @@ -97,6 +97,7 @@ protected: EGL_ALPHA_SIZE, 8, EGL_NONE }; + EGLint num_config = -1; EGLBoolean success = eglChooseConfig(display, configAttributes, &config, 1, &num_config); EXPECT_EQ(EGL_SUCCESS, eglGetError()); @@ -203,29 +204,43 @@ protected: EXPECT_EQ((EGLBoolean)EGL_TRUE, success); } - GLuint createProgram(const std::string& vs, const std::string& fs) + struct ProgramHandles { + GLuint program; + GLuint vsShader; + GLuint fsShader; + }; + + ProgramHandles createProgram(const std::string& vs, const std::string& fs) { - GLuint program = glCreateProgram(); + ProgramHandles ph; + ph.program = glCreateProgram(); EXPECT_GLENUM_EQ(GL_NONE, glGetError()); - GLuint vsShader = glCreateShader(GL_VERTEX_SHADER); + ph.vsShader = glCreateShader(GL_VERTEX_SHADER); const char* vsSource[1] = { vs.c_str() }; - glShaderSource(vsShader, 1, vsSource, nullptr); - glCompileShader(vsShader); + glShaderSource(ph.vsShader, 1, vsSource, nullptr); + glCompileShader(ph.vsShader); EXPECT_GLENUM_EQ(GL_NONE, glGetError()); - GLuint fsShader = glCreateShader(GL_FRAGMENT_SHADER); + ph.fsShader = glCreateShader(GL_FRAGMENT_SHADER); const char* fsSource[1] = { fs.c_str() }; - glShaderSource(fsShader, 1, fsSource, nullptr); - glCompileShader(fsShader); + glShaderSource(ph.fsShader, 1, fsSource, nullptr); + glCompileShader(ph.fsShader); EXPECT_GLENUM_EQ(GL_NONE, glGetError()); - glAttachShader(program, vsShader); - glAttachShader(program, fsShader); - glLinkProgram(program); + glAttachShader(ph.program, ph.vsShader); + glAttachShader(ph.program, ph.fsShader); + glLinkProgram(ph.program); EXPECT_GLENUM_EQ(GL_NONE, glGetError()); - return program; + return ph; + } + + void deleteProgram(const ProgramHandles& ph) + { + glDeleteShader(ph.fsShader); + glDeleteShader(ph.vsShader); + glDeleteProgram(ph.program); } void drawQuad(GLuint program) @@ -262,7 +277,7 @@ protected: } EGLDisplay getDisplay() const { return display; } - EGLDisplay getConfig() const { return config; } + EGLConfig getConfig() const { return config; } EGLSurface getSurface() const { return surface; } EGLContext getContext() const { return context; } private: @@ -532,10 +547,10 @@ TEST_F(SwiftShaderTest, TextureRectangle_SamplingFromRectangle) " gl_FragColor = texture2DRect(tex, vec2(0, 0));\n" "}\n"; - GLuint program = createProgram(vs, fs); + const ProgramHandles ph = createProgram(vs, fs); - glUseProgram(program); - GLint location = glGetUniformLocation(program, "tex"); + glUseProgram(ph.program); + GLint location = glGetUniformLocation(ph.program, "tex"); ASSERT_NE(-1, location); glUniform1i(location, 0); @@ -543,7 +558,9 @@ TEST_F(SwiftShaderTest, TextureRectangle_SamplingFromRectangle) glClear(GL_COLOR_BUFFER_BIT); EXPECT_GLENUM_EQ(GL_NONE, glGetError()); - drawQuad(program); + drawQuad(ph.program); + + deleteProgram(ph); compareColor(green); @@ -584,9 +601,10 @@ TEST_F(SwiftShaderTest, TextureRectangle_SamplingFromRectangleESSL3) " fragColor = texture(tex, vec2(0, 0));\n" "}\n"; - GLuint program = createProgram(vs, fs); - glUseProgram(program); - GLint location = glGetUniformLocation(program, "tex"); + const ProgramHandles ph = createProgram(vs, fs); + + glUseProgram(ph.program); + GLint location = glGetUniformLocation(ph.program, "tex"); ASSERT_NE(-1, location); glUniform1i(location, 0); @@ -594,7 +612,9 @@ TEST_F(SwiftShaderTest, TextureRectangle_SamplingFromRectangleESSL3) glClear(GL_COLOR_BUFFER_BIT); EXPECT_GLENUM_EQ(GL_NONE, glGetError()); - drawQuad(program); + drawQuad(ph.program); + + deleteProgram(ph); compareColor(green); @@ -717,3 +737,743 @@ TEST_F(SwiftShaderTest, TextureRectangle_CopyTexSubImage) Uninitialize(); } + +#ifndef EGL_ANGLE_iosurface_client_buffer +#define EGL_ANGLE_iosurface_client_buffer 1 +#define EGL_IOSURFACE_ANGLE 0x3454 +#define EGL_IOSURFACE_PLANE_ANGLE 0x345A +#define EGL_TEXTURE_RECTANGLE_ANGLE 0x345B +#define EGL_TEXTURE_TYPE_ANGLE 0x345C +#define EGL_TEXTURE_INTERNAL_FORMAT_ANGLE 0x345D +#endif /* EGL_ANGLE_iosurface_client_buffer */ + +#if defined(__APPLE__) +#include <CoreFoundation/CoreFoundation.h> +#include <IOSurface/IOSurface.h> + +namespace +{ + void AddIntegerValue(CFMutableDictionaryRef dictionary, const CFStringRef key, int32_t value) + { + CFNumberRef number = CFNumberCreate(nullptr, kCFNumberSInt32Type, &value); + CFDictionaryAddValue(dictionary, key, number); + CFRelease(number); + } +} // anonymous namespace + +class EGLClientBufferWrapper +{ +public: + EGLClientBufferWrapper(int width = 1, int height = 1) + { + // Create a 1 by 1 BGRA8888 IOSurface + ioSurface = nullptr; + + CFMutableDictionaryRef dict = CFDictionaryCreateMutable( + kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + AddIntegerValue(dict, kIOSurfaceWidth, width); + AddIntegerValue(dict, kIOSurfaceHeight, height); + AddIntegerValue(dict, kIOSurfacePixelFormat, 'BGRA'); + AddIntegerValue(dict, kIOSurfaceBytesPerElement, 4); + + ioSurface = IOSurfaceCreate(dict); + CFRelease(dict); + + EXPECT_NE(nullptr, ioSurface); + } + + ~EGLClientBufferWrapper() + { + IOSurfaceUnlock(ioSurface, kIOSurfaceLockReadOnly, nullptr); + + CFRelease(ioSurface); + } + + EGLClientBuffer getClientBuffer() const + { + return ioSurface; + } + + const unsigned char* lockColor() + { + IOSurfaceLock(ioSurface, kIOSurfaceLockReadOnly, nullptr); + return reinterpret_cast<const unsigned char*>(IOSurfaceGetBaseAddress(ioSurface)); + } + + void unlockColor() + { + IOSurfaceUnlock(ioSurface, kIOSurfaceLockReadOnly, nullptr); + } + + void writeColor(void* data, size_t dataSize) + { + // Write the data to the IOSurface + IOSurfaceLock(ioSurface, 0, nullptr); + memcpy(IOSurfaceGetBaseAddress(ioSurface), data, dataSize); + IOSurfaceUnlock(ioSurface, 0, nullptr); + } +private: + IOSurfaceRef ioSurface; +}; + +#else // __APPLE__ + +class EGLClientBufferWrapper +{ +public: + EGLClientBufferWrapper(int width = 1, int height = 1) + { + clientBuffer = new unsigned char[4 * width * height]; + } + + ~EGLClientBufferWrapper() + { + delete[] clientBuffer; + } + + EGLClientBuffer getClientBuffer() const + { + return clientBuffer; + } + + const unsigned char* lockColor() + { + return clientBuffer; + } + + void unlockColor() + { + } + + void writeColor(void* data, size_t dataSize) + { + memcpy(clientBuffer, data, dataSize); + } +private: + unsigned char* clientBuffer; +}; + +#endif + +class IOSurfaceClientBufferTest : public SwiftShaderTest +{ +protected: + EGLSurface createIOSurfacePbuffer(EGLClientBuffer buffer, EGLint width, EGLint height, EGLint plane, GLenum internalFormat, GLenum type) const + { + // Make a PBuffer from it using the EGL_ANGLE_iosurface_client_buffer extension + const EGLint attribs[] = { + EGL_WIDTH, width, + EGL_HEIGHT, height, + EGL_IOSURFACE_PLANE_ANGLE, plane, + EGL_TEXTURE_TARGET, EGL_TEXTURE_RECTANGLE_ANGLE, + EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, (EGLint)internalFormat, + EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA, + EGL_TEXTURE_TYPE_ANGLE, (EGLint)type, + EGL_NONE, EGL_NONE, + }; + + EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(getDisplay(), EGL_IOSURFACE_ANGLE, buffer, getConfig(), attribs); + EXPECT_NE(EGL_NO_SURFACE, pbuffer); + return pbuffer; + } + + void bindIOSurfaceToTexture(EGLClientBuffer buffer, EGLint width, EGLint height, EGLint plane, GLenum internalFormat, GLenum type, EGLSurface *pbuffer, GLuint *texture) const + { + *pbuffer = createIOSurfacePbuffer(buffer, width, height, plane, internalFormat, type); + + // Bind the pbuffer + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, *texture); + EGLBoolean result = eglBindTexImage(getDisplay(), *pbuffer, EGL_BACK_BUFFER); + EXPECT_EQ((EGLBoolean)EGL_TRUE, result); + EXPECT_EQ(EGL_SUCCESS, eglGetError()); + } + + void doClear(GLenum internalFormat, bool clearToZero) + { + if(internalFormat == GL_R16UI) + { + GLuint color = clearToZero ? 0 : 257; + glClearBufferuiv(GL_COLOR, 0, &color); + EXPECT_GLENUM_EQ(GL_NO_ERROR, glGetError()); + } + else + { + glClearColor(clearToZero ? 0.0f : 1.0f / 255.0f, + clearToZero ? 0.0f : 2.0f / 255.0f, + clearToZero ? 0.0f : 3.0f / 255.0f, + clearToZero ? 0.0f : 4.0f / 255.0f); + EXPECT_GLENUM_EQ(GL_NO_ERROR, glGetError()); + glClear(GL_COLOR_BUFFER_BIT); + EXPECT_GLENUM_EQ(GL_NO_ERROR, glGetError()); + } + } + + void doClearTest(EGLClientBufferWrapper& clientBufferWrapper, GLenum internalFormat, GLenum type, void *data, size_t dataSize) + { + ASSERT_TRUE(dataSize <= 4); + + // Bind the IOSurface to a texture and clear it. + GLuint texture = 1; + EGLSurface pbuffer; + bindIOSurfaceToTexture(clientBufferWrapper.getClientBuffer(), 1, 1, 0, internalFormat, type, &pbuffer, &texture); + + // glClear the pbuffer + GLuint fbo = 2; + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + EXPECT_GLENUM_EQ(GL_NO_ERROR, glGetError()); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, texture, 0); + EXPECT_GLENUM_EQ(GL_NO_ERROR, glGetError()); + EXPECT_GLENUM_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER), GL_FRAMEBUFFER_COMPLETE); + EXPECT_GLENUM_EQ(GL_NO_ERROR, glGetError()); + + doClear(internalFormat, false); + + // Unbind pbuffer and check content. + EGLBoolean result = eglReleaseTexImage(getDisplay(), pbuffer, EGL_BACK_BUFFER); + EXPECT_EQ((EGLBoolean)EGL_TRUE, result); + EXPECT_EQ(EGL_SUCCESS, eglGetError()); + + const unsigned char* color = clientBufferWrapper.lockColor(); + for(size_t i = 0; i < dataSize; ++i) + { + EXPECT_EQ(color[i], reinterpret_cast<unsigned char*>(data)[i]); + } + + result = eglDestroySurface(getDisplay(), pbuffer); + EXPECT_EQ((EGLBoolean)EGL_TRUE, result); + EXPECT_EQ(EGL_SUCCESS, eglGetError()); + } + + void doSampleTest(EGLClientBufferWrapper& clientBufferWrapper, GLenum internalFormat, GLenum type, void *data, size_t dataSize) + { + ASSERT_TRUE(dataSize <= 4); + + clientBufferWrapper.writeColor(data, dataSize); + + // Bind the IOSurface to a texture and clear it. + GLuint texture = 1; + EGLSurface pbuffer; + bindIOSurfaceToTexture(clientBufferWrapper.getClientBuffer(), 1, 1, 0, internalFormat, type, &pbuffer, &texture); + + doClear(internalFormat, true); + + // Create program and draw quad using it + const std::string vs = + "attribute vec4 position;\n" + "void main()\n" + "{\n" + " gl_Position = vec4(position.xy, 0.0, 1.0);\n" + "}\n"; + + const std::string fs = + "#extension GL_ARB_texture_rectangle : require\n" + "precision mediump float;\n" + "uniform sampler2DRect tex;\n" + "void main()\n" + "{\n" + " gl_FragColor = texture2DRect(tex, vec2(0, 0));\n" + "}\n"; + + const ProgramHandles ph = createProgram(vs, fs); + + drawQuad(ph.program); + + deleteProgram(ph); + + EXPECT_GLENUM_EQ(GL_NO_ERROR, glGetError()); + + // Unbind pbuffer and check content. + EGLBoolean result = eglReleaseTexImage(getDisplay(), pbuffer, EGL_BACK_BUFFER); + EXPECT_EQ((EGLBoolean)EGL_TRUE, result); + EXPECT_EQ(EGL_SUCCESS, eglGetError()); + + const unsigned char* color = clientBufferWrapper.lockColor(); + for(size_t i = 0; i < dataSize; ++i) + { + EXPECT_EQ(color[i], reinterpret_cast<unsigned char*>(data)[i]); + } + clientBufferWrapper.unlockColor(); + } +}; + +// Tests for the EGL_ANGLE_iosurface_client_buffer extension +TEST_F(IOSurfaceClientBufferTest, RenderToBGRA8888IOSurface) +{ + Initialize(3, false); + + { // EGLClientBufferWrapper scope + EGLClientBufferWrapper clientBufferWrapper; + unsigned char data[4] = { 3, 2, 1, 4 }; + doClearTest(clientBufferWrapper, GL_BGRA_EXT, GL_UNSIGNED_BYTE, data, 4); + } // end of EGLClientBufferWrapper scope + + Uninitialize(); +} + +// Test reading from BGRA8888 IOSurfaces +TEST_F(IOSurfaceClientBufferTest, ReadFromBGRA8888IOSurface) +{ + Initialize(3, false); + + { // EGLClientBufferWrapper scope + EGLClientBufferWrapper clientBufferWrapper; + unsigned char data[4] = { 3, 2, 1, 4 }; + doSampleTest(clientBufferWrapper, GL_BGRA_EXT, GL_UNSIGNED_BYTE, data, 4); + } // end of EGLClientBufferWrapper scope + + Uninitialize(); +} + +// Test using RG88 IOSurfaces for rendering +TEST_F(IOSurfaceClientBufferTest, RenderToRG88IOSurface) +{ + Initialize(3, false); + + { // EGLClientBufferWrapper scope + EGLClientBufferWrapper clientBufferWrapper; + unsigned char data[2] = { 1, 2 }; + doClearTest(clientBufferWrapper, GL_RG, GL_UNSIGNED_BYTE, data, 2); + } // end of EGLClientBufferWrapper scope + + Uninitialize(); +} + +// Test reading from RG88 IOSurfaces +TEST_F(IOSurfaceClientBufferTest, ReadFromRG88IOSurface) +{ + Initialize(3, false); + + { // EGLClientBufferWrapper scope + EGLClientBufferWrapper clientBufferWrapper; + unsigned char data[2] = { 1, 2 }; + doSampleTest(clientBufferWrapper, GL_RG, GL_UNSIGNED_BYTE, data, 2); + } // end of EGLClientBufferWrapper scope + + Uninitialize(); +} + +// Test using R8 IOSurfaces for rendering +TEST_F(IOSurfaceClientBufferTest, RenderToR8IOSurface) +{ + Initialize(3, false); + + { // EGLClientBufferWrapper scope + EGLClientBufferWrapper clientBufferWrapper; + unsigned char data[1] = { 1 }; + doClearTest(clientBufferWrapper, GL_RED, GL_UNSIGNED_BYTE, data, 1); + } // end of EGLClientBufferWrapper scope + + Uninitialize(); +} + +// Test reading from R8 IOSurfaces +TEST_F(IOSurfaceClientBufferTest, ReadFromR8IOSurface) +{ + Initialize(3, false); + + { // EGLClientBufferWrapper scope + EGLClientBufferWrapper clientBufferWrapper; + unsigned char data[1] = { 1 }; + doSampleTest(clientBufferWrapper, GL_RED, GL_UNSIGNED_BYTE, data, 1); + } // end of EGLClientBufferWrapper scope + + Uninitialize(); +} + +// Test using R16 IOSurfaces for rendering +TEST_F(IOSurfaceClientBufferTest, RenderToR16IOSurface) +{ + Initialize(3, false); + + { // EGLClientBufferWrapper scope + EGLClientBufferWrapper clientBufferWrapper; + uint16_t data[1] = { 257 }; + doClearTest(clientBufferWrapper, GL_R16UI, GL_UNSIGNED_SHORT, data, 2); + } // end of EGLClientBufferWrapper scope + + Uninitialize(); +} + +// Test reading from R8 IOSurfaces +TEST_F(IOSurfaceClientBufferTest, ReadFromR16IOSurface) +{ + Initialize(3, false); + + { // EGLClientBufferWrapper scope + EGLClientBufferWrapper clientBufferWrapper; + uint16_t data[1] = { 257 }; + doSampleTest(clientBufferWrapper, GL_R16UI, GL_UNSIGNED_SHORT, data, 1); + } // end of EGLClientBufferWrapper scope + + Uninitialize(); +} + +// Test the validation errors for missing attributes for eglCreatePbufferFromClientBuffer with +// IOSurface +TEST_F(IOSurfaceClientBufferTest, NegativeValidationMissingAttributes) +{ + Initialize(3, false); + + { + EGLClientBufferWrapper clientBufferWrapper(10, 10); + + // Success case + { + const EGLint attribs[] = { + EGL_WIDTH, 10, + EGL_HEIGHT, 10, + EGL_IOSURFACE_PLANE_ANGLE, 0, + EGL_TEXTURE_TARGET, EGL_TEXTURE_RECTANGLE_ANGLE, + EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT, + EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA, + EGL_TEXTURE_TYPE_ANGLE, GL_UNSIGNED_BYTE, + EGL_NONE, EGL_NONE, + }; + + EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(getDisplay(), EGL_IOSURFACE_ANGLE, clientBufferWrapper.getClientBuffer(), getConfig(), attribs); + EXPECT_NE(EGL_NO_SURFACE, pbuffer); + + EGLBoolean result = eglDestroySurface(getDisplay(), pbuffer); + EXPECT_EQ((EGLBoolean)EGL_TRUE, result); + EXPECT_EQ(EGL_SUCCESS, eglGetError()); + } + + // Missing EGL_WIDTH + { + const EGLint attribs[] = { + EGL_HEIGHT, 10, + EGL_IOSURFACE_PLANE_ANGLE, 0, + EGL_TEXTURE_TARGET, EGL_TEXTURE_RECTANGLE_ANGLE, + EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT, + EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA, + EGL_TEXTURE_TYPE_ANGLE, GL_UNSIGNED_BYTE, + EGL_NONE, EGL_NONE, + }; + + EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(getDisplay(), EGL_IOSURFACE_ANGLE, clientBufferWrapper.getClientBuffer(), getConfig(), attribs); + EXPECT_EQ(EGL_NO_SURFACE, pbuffer); + EXPECT_EQ(EGL_BAD_PARAMETER, eglGetError()); + } + + // Missing EGL_HEIGHT + { + const EGLint attribs[] = { + EGL_WIDTH, 10, + EGL_IOSURFACE_PLANE_ANGLE, 0, + EGL_TEXTURE_TARGET, EGL_TEXTURE_RECTANGLE_ANGLE, + EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT, + EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA, + EGL_TEXTURE_TYPE_ANGLE, GL_UNSIGNED_BYTE, + EGL_NONE, EGL_NONE, + }; + + EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(getDisplay(), EGL_IOSURFACE_ANGLE, clientBufferWrapper.getClientBuffer(), getConfig(), attribs); + EXPECT_EQ(EGL_NO_SURFACE, pbuffer); + EXPECT_EQ(EGL_BAD_PARAMETER, eglGetError()); + } + + // Missing EGL_IOSURFACE_PLANE_ANGLE + { + const EGLint attribs[] = { + EGL_WIDTH, 10, + EGL_HEIGHT, 10, + EGL_TEXTURE_TARGET, EGL_TEXTURE_RECTANGLE_ANGLE, + EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT, + EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA, + EGL_TEXTURE_TYPE_ANGLE, GL_UNSIGNED_BYTE, + EGL_NONE, EGL_NONE, + }; + + EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(getDisplay(), EGL_IOSURFACE_ANGLE, clientBufferWrapper.getClientBuffer(), getConfig(), attribs); + EXPECT_EQ(EGL_NO_SURFACE, pbuffer); + EXPECT_EQ(EGL_BAD_PARAMETER, eglGetError()); + } + + // Missing EGL_TEXTURE_TARGET - EGL_BAD_MATCH from the base spec of + // eglCreatePbufferFromClientBuffer + { + const EGLint attribs[] = { + EGL_WIDTH, 10, + EGL_HEIGHT, 10, + EGL_IOSURFACE_PLANE_ANGLE, 0, + EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT, + EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA, + EGL_TEXTURE_TYPE_ANGLE, GL_UNSIGNED_BYTE, + EGL_NONE, EGL_NONE, + }; + + EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(getDisplay(), EGL_IOSURFACE_ANGLE, clientBufferWrapper.getClientBuffer(), getConfig(), attribs); + EXPECT_EQ(EGL_NO_SURFACE, pbuffer); + EXPECT_EQ(EGL_BAD_MATCH, eglGetError()); + } + + // Missing EGL_TEXTURE_INTERNAL_FORMAT_ANGLE + { + const EGLint attribs[] = { + EGL_WIDTH, 10, + EGL_HEIGHT, 10, + EGL_IOSURFACE_PLANE_ANGLE, 0, + EGL_TEXTURE_TARGET, EGL_TEXTURE_RECTANGLE_ANGLE, + EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA, + EGL_TEXTURE_TYPE_ANGLE, GL_UNSIGNED_BYTE, + EGL_NONE, EGL_NONE, + }; + + EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(getDisplay(), EGL_IOSURFACE_ANGLE, clientBufferWrapper.getClientBuffer(), getConfig(), attribs); + EXPECT_EQ(EGL_NO_SURFACE, pbuffer); + EXPECT_EQ(EGL_BAD_PARAMETER, eglGetError()); + } + + // Missing EGL_TEXTURE_FORMAT - EGL_BAD_MATCH from the base spec of + // eglCreatePbufferFromClientBuffer + { + const EGLint attribs[] = { + EGL_WIDTH, 10, + EGL_HEIGHT, 10, + EGL_IOSURFACE_PLANE_ANGLE, 0, + EGL_TEXTURE_TARGET, EGL_TEXTURE_RECTANGLE_ANGLE, + EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT, + EGL_TEXTURE_TYPE_ANGLE, GL_UNSIGNED_BYTE, + EGL_NONE, EGL_NONE, + }; + + EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(getDisplay(), EGL_IOSURFACE_ANGLE, clientBufferWrapper.getClientBuffer(), getConfig(), attribs); + EXPECT_EQ(EGL_NO_SURFACE, pbuffer); + EXPECT_EQ(EGL_BAD_MATCH, eglGetError()); + } + + // Missing EGL_TEXTURE_TYPE_ANGLE + { + const EGLint attribs[] = { + EGL_WIDTH, 10, + EGL_HEIGHT, 10, + EGL_IOSURFACE_PLANE_ANGLE, 0, + EGL_TEXTURE_TARGET, EGL_TEXTURE_RECTANGLE_ANGLE, + EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT, + EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA, + EGL_NONE, EGL_NONE, + }; + + EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(getDisplay(), EGL_IOSURFACE_ANGLE, clientBufferWrapper.getClientBuffer(), getConfig(), attribs); + EXPECT_EQ(EGL_NO_SURFACE, pbuffer); + EXPECT_EQ(EGL_BAD_PARAMETER, eglGetError()); + } + } + + Uninitialize(); +} + +// Test the validation errors for bad parameters for eglCreatePbufferFromClientBuffer with IOSurface +TEST_F(IOSurfaceClientBufferTest, NegativeValidationBadAttributes) +{ + Initialize(3, false); + + { + EGLClientBufferWrapper clientBufferWrapper(10, 10); + + // Success case + { + const EGLint attribs[] = { + EGL_WIDTH, 10, + EGL_HEIGHT, 10, + EGL_IOSURFACE_PLANE_ANGLE, 0, + EGL_TEXTURE_TARGET, EGL_TEXTURE_RECTANGLE_ANGLE, + EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT, + EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA, + EGL_TEXTURE_TYPE_ANGLE, GL_UNSIGNED_BYTE, + EGL_NONE, EGL_NONE, + }; + + EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(getDisplay(), EGL_IOSURFACE_ANGLE, clientBufferWrapper.getClientBuffer(), getConfig(), attribs); + EXPECT_NE(EGL_NO_SURFACE, pbuffer); + + EGLBoolean result = eglDestroySurface(getDisplay(), pbuffer); + EXPECT_EQ((EGLBoolean)EGL_TRUE, result); + EXPECT_EQ(EGL_SUCCESS, eglGetError()); + } + + // EGL_TEXTURE_FORMAT must be EGL_TEXTURE_RGBA + { + const EGLint attribs[] = { + EGL_WIDTH, 10, + EGL_HEIGHT, 10, + EGL_IOSURFACE_PLANE_ANGLE, 0, + EGL_TEXTURE_TARGET, EGL_TEXTURE_RECTANGLE_ANGLE, + EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT, + EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGB, + EGL_TEXTURE_TYPE_ANGLE, GL_UNSIGNED_BYTE, + EGL_NONE, EGL_NONE, + }; + + EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(getDisplay(), EGL_IOSURFACE_ANGLE, clientBufferWrapper.getClientBuffer(), getConfig(), attribs); + EXPECT_EQ(EGL_NO_SURFACE, pbuffer); + EXPECT_EQ(EGL_BAD_ATTRIBUTE, eglGetError()); + } + + // EGL_WIDTH must be at least 1 + { + const EGLint attribs[] = { + EGL_WIDTH, 0, + EGL_HEIGHT, 10, + EGL_IOSURFACE_PLANE_ANGLE, 0, + EGL_TEXTURE_TARGET, EGL_TEXTURE_RECTANGLE_ANGLE, + EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT, + EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA, + EGL_TEXTURE_TYPE_ANGLE, GL_UNSIGNED_BYTE, + EGL_NONE, EGL_NONE, + }; + + EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(getDisplay(), EGL_IOSURFACE_ANGLE, clientBufferWrapper.getClientBuffer(), getConfig(), attribs); + EXPECT_EQ(EGL_NO_SURFACE, pbuffer); + EXPECT_EQ(EGL_BAD_ATTRIBUTE, eglGetError()); + } + + // EGL_HEIGHT must be at least 1 + { + const EGLint attribs[] = { + EGL_WIDTH, 10, + EGL_HEIGHT, 0, + EGL_IOSURFACE_PLANE_ANGLE, 0, + EGL_TEXTURE_TARGET, EGL_TEXTURE_RECTANGLE_ANGLE, + EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT, + EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA, + EGL_TEXTURE_TYPE_ANGLE, GL_UNSIGNED_BYTE, + EGL_NONE, EGL_NONE, + }; + + EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(getDisplay(), EGL_IOSURFACE_ANGLE, clientBufferWrapper.getClientBuffer(), getConfig(), attribs); + EXPECT_EQ(EGL_NO_SURFACE, pbuffer); + EXPECT_EQ(EGL_BAD_ATTRIBUTE, eglGetError()); + } + +#if defined(__APPLE__) + // EGL_WIDTH must be at most the width of the IOSurface + { + const EGLint attribs[] = { + EGL_WIDTH, 11, + EGL_HEIGHT, 10, + EGL_IOSURFACE_PLANE_ANGLE, 0, + EGL_TEXTURE_TARGET, EGL_TEXTURE_RECTANGLE_ANGLE, + EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT, + EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA, + EGL_TEXTURE_TYPE_ANGLE, GL_UNSIGNED_BYTE, + EGL_NONE, EGL_NONE, + }; + + EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(getDisplay(), EGL_IOSURFACE_ANGLE, clientBufferWrapper.getClientBuffer(), getConfig(), attribs); + EXPECT_EQ(EGL_NO_SURFACE, pbuffer); + EXPECT_EQ(EGL_BAD_ATTRIBUTE, eglGetError()); + } + + // EGL_HEIGHT must be at most the height of the IOSurface + { + const EGLint attribs[] = { + EGL_WIDTH, 10, + EGL_HEIGHT, 11, + EGL_IOSURFACE_PLANE_ANGLE, 0, + EGL_TEXTURE_TARGET, EGL_TEXTURE_RECTANGLE_ANGLE, + EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT, + EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA, + EGL_TEXTURE_TYPE_ANGLE, GL_UNSIGNED_BYTE, + EGL_NONE, EGL_NONE, + }; + + EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(getDisplay(), EGL_IOSURFACE_ANGLE, clientBufferWrapper.getClientBuffer(), getConfig(), attribs); + EXPECT_EQ(EGL_NO_SURFACE, pbuffer); + EXPECT_EQ(EGL_BAD_ATTRIBUTE, eglGetError()); + } + + // EGL_IOSURFACE_PLANE_ANGLE must less than the number of planes of the IOSurface + { + const EGLint attribs[] = { + EGL_WIDTH, 10, + EGL_HEIGHT, 10, + EGL_IOSURFACE_PLANE_ANGLE, 1, + EGL_TEXTURE_TARGET, EGL_TEXTURE_RECTANGLE_ANGLE, + EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT, + EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA, + EGL_TEXTURE_TYPE_ANGLE, GL_UNSIGNED_BYTE, + EGL_NONE, EGL_NONE, + }; + + EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(getDisplay(), EGL_IOSURFACE_ANGLE, clientBufferWrapper.getClientBuffer(), getConfig(), attribs); + EXPECT_EQ(EGL_NO_SURFACE, pbuffer); + EXPECT_EQ(EGL_BAD_ATTRIBUTE, eglGetError()); + } +#endif + + // EGL_TEXTURE_FORMAT must be at EGL_TEXTURE_RECTANGLE_ANGLE + { + const EGLint attribs[] = { + EGL_WIDTH, 10, + EGL_HEIGHT, 10, + EGL_IOSURFACE_PLANE_ANGLE, 0, + EGL_TEXTURE_TARGET, EGL_TEXTURE_2D, + EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT, + EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA, + EGL_TEXTURE_TYPE_ANGLE, GL_UNSIGNED_BYTE, + EGL_NONE, EGL_NONE, + }; + + EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(getDisplay(), EGL_IOSURFACE_ANGLE, clientBufferWrapper.getClientBuffer(), getConfig(), attribs); + EXPECT_EQ(EGL_NO_SURFACE, pbuffer); + EXPECT_EQ(EGL_BAD_ATTRIBUTE, eglGetError()); + } + + // EGL_IOSURFACE_PLANE_ANGLE must be at least 0 + { + const EGLint attribs[] = { + EGL_WIDTH, 10, + EGL_HEIGHT, 10, + EGL_IOSURFACE_PLANE_ANGLE, -1, + EGL_TEXTURE_TARGET, EGL_TEXTURE_RECTANGLE_ANGLE, + EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT, + EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA, + EGL_TEXTURE_TYPE_ANGLE, GL_UNSIGNED_BYTE, + EGL_NONE, EGL_NONE, + }; + + EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(getDisplay(), EGL_IOSURFACE_ANGLE, clientBufferWrapper.getClientBuffer(), getConfig(), attribs); + EXPECT_EQ(EGL_NO_SURFACE, pbuffer); + EXPECT_EQ(EGL_BAD_ATTRIBUTE, eglGetError()); + } + + // The internal format / type most be listed in the table + { + const EGLint attribs[] = { + EGL_WIDTH, 10, + EGL_HEIGHT, 10, + EGL_IOSURFACE_PLANE_ANGLE, 0, + EGL_TEXTURE_TARGET, EGL_TEXTURE_RECTANGLE_ANGLE, + EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_RGBA, + EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA, + EGL_TEXTURE_TYPE_ANGLE, GL_UNSIGNED_BYTE, + EGL_NONE, EGL_NONE, + }; + + EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(getDisplay(), EGL_IOSURFACE_ANGLE, clientBufferWrapper.getClientBuffer(), getConfig(), attribs); + EXPECT_EQ(EGL_NO_SURFACE, pbuffer); + EXPECT_EQ(EGL_BAD_ATTRIBUTE, eglGetError()); + } + } + + Uninitialize(); +} + +// Test IOSurface pbuffers cannot be made current +TEST_F(IOSurfaceClientBufferTest, MakeCurrentDisallowed) +{ + Initialize(3, false); + + { + EGLClientBufferWrapper clientBufferWrapper(10, 10); + + EGLSurface pbuffer = createIOSurfacePbuffer(clientBufferWrapper.getClientBuffer(), 10, 10, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE); + + EGLBoolean result = eglMakeCurrent(getDisplay(), pbuffer, pbuffer, getContext()); + EXPECT_EQ((EGLBoolean)EGL_FALSE, result); + EXPECT_EQ(EGL_BAD_SURFACE, eglGetError()); + } + + Uninitialize(); +} |