Commit 3f4b87b4 by Corentin Wallez Committed by Commit Bot

Expand the EGLIOSurfaceClientBufferTests

This expands the test to check for validation errors and that multiple formats of IOSurfaces can be read from / rendered to. It fixes a couple issues in the implementation of the extension too. Minor fixes in the EGL_ANGLE_iosurface_client_buffer extension text. Fix a fragile test that was not setting the texture unit a shader is to sample from. BUG=angleproject:1649 Change-Id: Ied2a9bfff95cb3a9a7a59008260899eb2fc55575 Reviewed-on: https://chromium-review.googlesource.com/924477Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Commit-Queue: Corentin Wallez <cwallez@chromium.org>
parent 029e8ca7
...@@ -71,14 +71,15 @@ Additions to Chapter 3 of the EGL 1.4 Specification (EGL Functions and Errors) ...@@ -71,14 +71,15 @@ Additions to Chapter 3 of the EGL 1.4 Specification (EGL Functions and Errors)
Append to the end of Section 3.5.3. Append to the end of Section 3.5.3.
"When <buftype> is EGL_IOSURFACE_ANGLE, <attrib_list> must contain all the "When <buftype> is EGL_IOSURFACE_ANGLE, <attrib_list> must contain all the
following attributes under the following constraints otherwise following attributes otherwise EGL_BAD_PARAMETER is generated. The
EGL_BAD_PARAMETER is generated: attributes must satisfy the following constraints otherwise
EGL_BAD_ATTRIBUTE is generated:
- EGL_TEXTURE_TYPE_ANGLE, and EGL_TEXTURE_INTERNAL_FORMAT_ANGLE followed - EGL_TEXTURE_TYPE_ANGLE, and EGL_TEXTURE_INTERNAL_FORMAT_ANGLE followed
by OpenGL enums for texture types, and texture internal format by OpenGL enums for texture types, and texture internal format
respectively. respectively.
- EGL_TEXTURE_FORMAT with a value of EGL_TEXTURE_RGBA - EGL_TEXTURE_FORMAT with a value of EGL_TEXTURE_RGBA
- EGL_WIDTH with a value between 1 and the width of <buffer>. - EGL_WIDTH with a value between 1 and the width of <buffer>.
- EGL_HEIGHT with a value between 1 and the width of <buffer>. - EGL_HEIGHT with a value between 1 and the height of <buffer>.
- EGL_TEXTURE_TARGET with a value of EGL_TEXTURE_RECTANGLE_ANGLE - EGL_TEXTURE_TARGET with a value of EGL_TEXTURE_RECTANGLE_ANGLE
- EGL_IOSURFACE_PLANE_ANGLE with a value between 0 and the number of - EGL_IOSURFACE_PLANE_ANGLE with a value between 0 and the number of
planes of <buffer> (exclusive). planes of <buffer> (exclusive).
...@@ -93,7 +94,7 @@ Additions to Chapter 3 of the EGL 1.4 Specification (EGL Functions and Errors) ...@@ -93,7 +94,7 @@ Additions to Chapter 3 of the EGL 1.4 Specification (EGL Functions and Errors)
Texture Type Texture Internal Format Texture Type Texture Internal Format
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
GL_UNSIGNED_BYTE GL_RED GL_UNSIGNED_BYTE GL_RED
GL_UNSIGNED_SHORT GL_RED_INTEGER GL_UNSIGNED_SHORT GL_R16UI
GL_UNSIGNED_BYTE GL_RG GL_UNSIGNED_BYTE GL_RG
GL_UNSIGNED_BYTE GL_BGRA_EXT GL_UNSIGNED_BYTE GL_BGRA_EXT
GL_HALF_FLOAT GL_RGBA GL_HALF_FLOAT GL_RGBA
......
...@@ -42,7 +42,7 @@ struct IOSurfaceFormatInfo ...@@ -42,7 +42,7 @@ struct IOSurfaceFormatInfo
// clang-format off // clang-format off
static const IOSurfaceFormatInfo kIOSurfaceFormats[] = { static const IOSurfaceFormatInfo kIOSurfaceFormats[] = {
{GL_RED, GL_UNSIGNED_BYTE, 1, GL_RED, GL_RED, GL_UNSIGNED_BYTE }, {GL_RED, GL_UNSIGNED_BYTE, 1, GL_RED, GL_RED, GL_UNSIGNED_BYTE },
{GL_R8UI, GL_UNSIGNED_SHORT, 2, GL_RED, GL_RED, GL_UNSIGNED_SHORT }, {GL_R16UI, GL_UNSIGNED_SHORT, 2, GL_RED, GL_RED, GL_UNSIGNED_SHORT },
{GL_RG, GL_UNSIGNED_BYTE, 2, GL_RG, GL_RG, GL_UNSIGNED_BYTE }, {GL_RG, GL_UNSIGNED_BYTE, 2, GL_RG, GL_RG, GL_UNSIGNED_BYTE },
{GL_BGRA_EXT, GL_UNSIGNED_BYTE, 4, GL_BGRA, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV}, {GL_BGRA_EXT, GL_UNSIGNED_BYTE, 4, GL_BGRA, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV},
{GL_RGBA, GL_HALF_FLOAT, 8, GL_RGBA, GL_RGBA, GL_HALF_FLOAT }, {GL_RGBA, GL_HALF_FLOAT, 8, GL_RGBA, GL_RGBA, GL_HALF_FLOAT },
...@@ -211,7 +211,7 @@ bool IOSurfaceSurfaceCGL::validateAttributes(EGLClientBuffer buffer, ...@@ -211,7 +211,7 @@ bool IOSurfaceSurfaceCGL::validateAttributes(EGLClientBuffer buffer,
EGLAttrib width = attribs.get(EGL_WIDTH); EGLAttrib width = attribs.get(EGL_WIDTH);
EGLAttrib height = attribs.get(EGL_HEIGHT); EGLAttrib height = attribs.get(EGL_HEIGHT);
if (width <= 0 || static_cast<size_t>(width) > IOSurfaceGetWidthOfPlane(ioSurface, plane) || if (width <= 0 || static_cast<size_t>(width) > IOSurfaceGetWidthOfPlane(ioSurface, plane) ||
height < 0 || static_cast<size_t>(height) > IOSurfaceGetHeightOfPlane(ioSurface, plane)) height <= 0 || static_cast<size_t>(height) > IOSurfaceGetHeightOfPlane(ioSurface, plane))
{ {
return false; return false;
} }
......
...@@ -1200,8 +1200,8 @@ Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, E ...@@ -1200,8 +1200,8 @@ Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, E
(textureFormat == EGL_TEXTURE_RGBA && config->bindToTextureRGBA != EGL_TRUE)) (textureFormat == EGL_TEXTURE_RGBA && config->bindToTextureRGBA != EGL_TRUE))
{ {
// TODO(cwallez@chromium.org): For IOSurface pbuffers we require that EGL_TEXTURE_RGBA is // TODO(cwallez@chromium.org): For IOSurface pbuffers we require that EGL_TEXTURE_RGBA is
// set so that eglBinTexImage works. Normally this is only allowed if the config exposes the // set so that eglBindTexImage works. Normally this is only allowed if the config exposes
// bindToTextureRGB/RGBA flag. This issue is that enabling this flags means that // the bindToTextureRGB/RGBA flag. This issue is that enabling this flags means that
// eglBindTexImage should also work for regular pbuffers which isn't implemented on macOS. // eglBindTexImage should also work for regular pbuffers which isn't implemented on macOS.
// Instead of adding the flag we special case the check here to be ignored for IOSurfaces. // Instead of adding the flag we special case the check here to be ignored for IOSurfaces.
// The TODO is to find a proper solution for this, maybe by implementing eglBindTexImage on // The TODO is to find a proper solution for this, maybe by implementing eglBindTexImage on
......
...@@ -7,13 +7,13 @@ ...@@ -7,13 +7,13 @@
// //
#include "test_utils/ANGLETest.h" #include "test_utils/ANGLETest.h"
#include "common/mathutil.h"
#include "test_utils/gl_raii.h" #include "test_utils/gl_raii.h"
#include <CoreFoundation/CoreFoundation.h> #include <CoreFoundation/CoreFoundation.h>
#include <IOSurface/IOSurface.h> #include <IOSurface/IOSurface.h>
#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
using namespace angle; using namespace angle;
namespace namespace
...@@ -26,6 +26,67 @@ void AddIntegerValue(CFMutableDictionaryRef dictionary, const CFStringRef key, i ...@@ -26,6 +26,67 @@ void AddIntegerValue(CFMutableDictionaryRef dictionary, const CFStringRef key, i
CFRelease(number); CFRelease(number);
} }
class ScopedIOSurfaceRef : angle::NonCopyable
{
public:
explicit ScopedIOSurfaceRef(IOSurfaceRef surface) : mSurface(surface) {}
~ScopedIOSurfaceRef()
{
if (mSurface != nullptr)
{
CFRelease(mSurface);
mSurface = nullptr;
}
}
IOSurfaceRef get() const { return mSurface; }
ScopedIOSurfaceRef(ScopedIOSurfaceRef &&other)
{
if (mSurface != nullptr)
{
CFRelease(mSurface);
}
mSurface = other.mSurface;
other.mSurface = nullptr;
}
ScopedIOSurfaceRef &operator=(ScopedIOSurfaceRef &&other)
{
if (mSurface != nullptr)
{
CFRelease(mSurface);
}
mSurface = other.mSurface;
other.mSurface = nullptr;
return *this;
}
private:
IOSurfaceRef mSurface = nullptr;
};
ScopedIOSurfaceRef CreateSinglePlaneIOSurface(int width,
int height,
int32_t format,
int bytesPerElement)
{
CFMutableDictionaryRef dict = CFDictionaryCreateMutable(
kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
AddIntegerValue(dict, kIOSurfaceWidth, width);
AddIntegerValue(dict, kIOSurfaceHeight, height);
AddIntegerValue(dict, kIOSurfacePixelFormat, format);
AddIntegerValue(dict, kIOSurfaceBytesPerElement, bytesPerElement);
IOSurfaceRef ioSurface = IOSurfaceCreate(dict);
EXPECT_NE(nullptr, ioSurface);
CFRelease(dict);
return ScopedIOSurfaceRef(ioSurface);
}
} // anonymous namespace } // anonymous namespace
class IOSurfaceClientBufferTest : public ANGLETest class IOSurfaceClientBufferTest : public ANGLETest
...@@ -43,32 +104,231 @@ class IOSurfaceClientBufferTest : public ANGLETest ...@@ -43,32 +104,231 @@ class IOSurfaceClientBufferTest : public ANGLETest
void TearDown() override { ANGLETest::TearDown(); } void TearDown() override { ANGLETest::TearDown(); }
void createIOSurfacePbuffer(const ScopedIOSurfaceRef &ioSurface,
EGLint width,
EGLint height,
EGLint plane,
GLenum internalFormat,
GLenum type,
EGLSurface *pbuffer) const
{
// clang-format off
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, internalFormat,
EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA,
EGL_TEXTURE_TYPE_ANGLE, type,
EGL_NONE, EGL_NONE,
};
// clang-format on
*pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE, ioSurface.get(),
mConfig, attribs);
EXPECT_NE(EGL_NO_SURFACE, *pbuffer);
}
void bindIOSurfaceToTexture(const ScopedIOSurfaceRef &ioSurface,
EGLint width,
EGLint height,
EGLint plane,
GLenum internalFormat,
GLenum type,
EGLSurface *pbuffer,
GLTexture *texture) const
{
createIOSurfacePbuffer(ioSurface, width, height, plane, internalFormat, type, pbuffer);
// Bind the pbuffer
glBindTexture(GL_TEXTURE_RECTANGLE_ANGLE, *texture);
EGLBoolean result = eglBindTexImage(mDisplay, *pbuffer, EGL_BACK_BUFFER);
EXPECT_EGL_TRUE(result);
EXPECT_EGL_SUCCESS();
}
void doClearTest(const ScopedIOSurfaceRef &ioSurface,
GLenum internalFormat,
GLenum type,
void *data,
size_t dataSize)
{
// Bind the IOSurface to a texture and clear it.
EGLSurface pbuffer;
GLTexture texture;
bindIOSurfaceToTexture(ioSurface, 1, 1, 0, internalFormat, type, &pbuffer, &texture);
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
EXPECT_GL_NO_ERROR();
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ANGLE,
texture, 0);
EXPECT_GL_NO_ERROR();
EXPECT_GLENUM_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER), GL_FRAMEBUFFER_COMPLETE);
EXPECT_GL_NO_ERROR();
glClearColor(1.0f / 255.0f, 2.0f / 255.0f, 3.0f / 255.0f, 4.0f / 255.0f);
EXPECT_GL_NO_ERROR();
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_GL_NO_ERROR();
// Unbind pbuffer and check content.
EGLBoolean result = eglReleaseTexImage(mDisplay, pbuffer, EGL_BACK_BUFFER);
EXPECT_EGL_TRUE(result);
EXPECT_EGL_SUCCESS();
IOSurfaceLock(ioSurface.get(), kIOSurfaceLockReadOnly, nullptr);
ASSERT_EQ(0, memcmp(IOSurfaceGetBaseAddress(ioSurface.get()), data, dataSize));
IOSurfaceUnlock(ioSurface.get(), kIOSurfaceLockReadOnly, nullptr);
result = eglDestroySurface(mDisplay, pbuffer);
EXPECT_EGL_TRUE(result);
EXPECT_EGL_SUCCESS();
}
enum ColorMask
{
R = 1,
G = 2,
B = 4,
A = 8,
};
void doSampleTest(const ScopedIOSurfaceRef &ioSurface,
GLenum internalFormat,
GLenum type,
void *data,
size_t dataSize,
int mask)
{
// Write the data to the IOSurface
IOSurfaceLock(ioSurface.get(), 0, nullptr);
memcpy(IOSurfaceGetBaseAddress(ioSurface.get()), data, dataSize);
IOSurfaceUnlock(ioSurface.get(), 0, nullptr);
// Bind the IOSurface to a texture and clear it.
EGLSurface pbuffer;
GLTexture texture;
bindIOSurfaceToTexture(ioSurface, 1, 1, 0, internalFormat, type, &pbuffer, &texture);
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";
ANGLE_GL_PROGRAM(program, vs, fs);
glUseProgram(program);
GLint location = glGetUniformLocation(program, "tex");
ASSERT_NE(-1, location);
glUniform1i(location, 0);
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
drawQuad(program, "position", 0.5f, 1.0f, false);
GLColor expectedColor((mask & R) ? 1 : 0, (mask & G) ? 2 : 0, (mask & B) ? 3 : 0,
(mask & A) ? 4 : 255);
EXPECT_PIXEL_COLOR_EQ(0, 0, expectedColor);
ASSERT_GL_NO_ERROR();
}
EGLConfig mConfig; EGLConfig mConfig;
EGLDisplay mDisplay; EGLDisplay mDisplay;
}; };
// Test using BGRA8888 IOSurfaces for rendering
TEST_P(IOSurfaceClientBufferTest, RenderToBGRA8888IOSurface) TEST_P(IOSurfaceClientBufferTest, RenderToBGRA8888IOSurface)
{ {
// Create a 1 by 1 BGRA8888 IOSurface ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'BGRA', 4);
IOSurfaceRef ioSurface = nullptr;
CFMutableDictionaryRef dict = CFDictionaryCreateMutable( GLColor color(3, 2, 1, 4);
kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); doClearTest(ioSurface, GL_BGRA_EXT, GL_UNSIGNED_BYTE, &color, sizeof(color));
AddIntegerValue(dict, kIOSurfaceWidth, 1); }
AddIntegerValue(dict, kIOSurfaceHeight, 1);
AddIntegerValue(dict, kIOSurfacePixelFormat, 'BGRA');
AddIntegerValue(dict, kIOSurfaceBytesPerElement, 4);
ioSurface = IOSurfaceCreate(dict); // Test reading from BGRA8888 IOSurfaces
CFRelease(dict); TEST_P(IOSurfaceClientBufferTest, ReadFromBGRA8888IOSurface)
{
ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'BGRA', 4);
EXPECT_NE(nullptr, ioSurface); GLColor color(3, 2, 1, 4);
doSampleTest(ioSurface, GL_BGRA_EXT, GL_UNSIGNED_BYTE, &color, sizeof(color), R | G | B | A);
}
// Test using RG88 IOSurfaces for rendering
TEST_P(IOSurfaceClientBufferTest, RenderToRG88IOSurface)
{
ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, '2C08', 2);
uint8_t color[2] = {1, 2};
doClearTest(ioSurface, GL_RG, GL_UNSIGNED_BYTE, &color, sizeof(color));
}
// Test reading from RG88 IOSurfaces
TEST_P(IOSurfaceClientBufferTest, ReadFromRG88IOSurface)
{
ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, '2C08', 2);
uint8_t color[2] = {1, 2};
doSampleTest(ioSurface, GL_RG, GL_UNSIGNED_BYTE, &color, sizeof(color), R | G);
}
// Test using R8 IOSurfaces for rendering
TEST_P(IOSurfaceClientBufferTest, RenderToR8IOSurface)
{
ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'L008', 1);
uint8_t color = 1;
doClearTest(ioSurface, GL_RED, GL_UNSIGNED_BYTE, &color, sizeof(color));
}
// Test reading from R8 IOSurfaces
TEST_P(IOSurfaceClientBufferTest, ReadFromR8IOSurface)
{
ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'L008', 1);
uint8_t color = 1;
doSampleTest(ioSurface, GL_RED, GL_UNSIGNED_BYTE, &color, sizeof(color), R);
}
// Test using R16 IOSurfaces for rendering
TEST_P(IOSurfaceClientBufferTest, RenderToR16IOSurface)
{
// HACK(cwallez@chromium.org) 'L016' doesn't seem to be an official pixel format but it works
// sooooooo let's test using it
ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'L016', 2);
// Make a PBuffer from it using the EGL_ANGLE_iosurface_client_buffer extension uint16_t color = 257;
doClearTest(ioSurface, GL_R16UI, GL_UNSIGNED_SHORT, &color, sizeof(color));
}
// TODO(cwallez@chromium.org): test reading from R16? It returns 0 maybe because samplerRect is
// only for floating textures?
// TODO(cwallez@chromium.org): Test using RGBA half float IOSurfaces ('RGhA')
// Test the validation errors for missing attributes for eglCreatePbufferFromClientBuffer with
// IOSurface
TEST_P(IOSurfaceClientBufferTest, NegativeValidationMissingAttributes)
{
ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(10, 10, 'BGRA', 4);
// Success case
{
// clang-format off // clang-format off
const EGLint attribs[] = { const EGLint attribs[] = {
EGL_WIDTH, 1, EGL_WIDTH, 10,
EGL_HEIGHT, 1, EGL_HEIGHT, 10,
EGL_IOSURFACE_PLANE_ANGLE, 0, EGL_IOSURFACE_PLANE_ANGLE, 0,
EGL_TEXTURE_TARGET, EGL_TEXTURE_RECTANGLE_ANGLE, EGL_TEXTURE_TARGET, EGL_TEXTURE_RECTANGLE_ANGLE,
EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT, EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT,
...@@ -78,41 +338,390 @@ TEST_P(IOSurfaceClientBufferTest, RenderToBGRA8888IOSurface) ...@@ -78,41 +338,390 @@ TEST_P(IOSurfaceClientBufferTest, RenderToBGRA8888IOSurface)
}; };
// clang-format off // clang-format off
EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE, ioSurface, mConfig, attribs); EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE, ioSurface.get(), mConfig, attribs);
EXPECT_NE(EGL_NO_SURFACE, pbuffer); EXPECT_NE(EGL_NO_SURFACE, pbuffer);
// Bind and glClear the pbuffer EGLBoolean result = eglDestroySurface(mDisplay, pbuffer);
GLTexture tex;
glBindTexture(GL_TEXTURE_RECTANGLE_ANGLE, tex);
EGLBoolean result = eglBindTexImage(mDisplay, pbuffer, EGL_BACK_BUFFER);
EXPECT_EGL_TRUE(result); EXPECT_EGL_TRUE(result);
EXPECT_EGL_SUCCESS(); EXPECT_EGL_SUCCESS();
}
GLFramebuffer fbo; // Missing EGL_WIDTH
glBindFramebuffer(GL_FRAMEBUFFER, fbo); {
EXPECT_GL_NO_ERROR(); // clang-format off
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ANGLE, tex, 0); const EGLint attribs[] = {
EXPECT_GL_NO_ERROR(); EGL_HEIGHT, 10,
EXPECT_GLENUM_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER), GL_FRAMEBUFFER_COMPLETE); EGL_IOSURFACE_PLANE_ANGLE, 0,
EXPECT_GL_NO_ERROR(); 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,
};
// clang-format on
glClearColor(0, 1, 0, 1); EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
EXPECT_GL_NO_ERROR(); ioSurface.get(), mConfig, attribs);
glClear(GL_COLOR_BUFFER_BIT); EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
EXPECT_GL_NO_ERROR(); EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
}
// Unbind pbuffer and check content. // Missing EGL_HEIGHT
result = eglReleaseTexImage(mDisplay, pbuffer, EGL_BACK_BUFFER); {
// clang-format off
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,
};
// clang-format on
EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
ioSurface.get(), mConfig, attribs);
EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
}
// Missing EGL_IOSURFACE_PLANE_ANGLE
{
// clang-format off
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,
};
// clang-format on
EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
ioSurface.get(), mConfig, attribs);
EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
}
// Missing EGL_TEXTURE_TARGET - EGL_BAD_MATCH from the base spec of
// eglCreatePbufferFromClientBuffer
{
// clang-format off
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,
};
// clang-format on
EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
ioSurface.get(), mConfig, attribs);
EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
EXPECT_EGL_ERROR(EGL_BAD_MATCH);
}
// Missing EGL_TEXTURE_INTERNAL_FORMAT_ANGLE
{
// clang-format off
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,
};
// clang-format on
EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
ioSurface.get(), mConfig, attribs);
EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
}
// Missing EGL_TEXTURE_FORMAT - EGL_BAD_MATCH from the base spec of
// eglCreatePbufferFromClientBuffer
{
// clang-format off
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,
};
// clang-format on
EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
ioSurface.get(), mConfig, attribs);
EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
EXPECT_EGL_ERROR(EGL_BAD_MATCH);
}
// Missing EGL_TEXTURE_TYPE_ANGLE
{
// clang-format off
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,
};
// clang-format on
EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
ioSurface.get(), mConfig, attribs);
EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
}
}
// Test the validation errors for bad parameters for eglCreatePbufferFromClientBuffer with IOSurface
TEST_P(IOSurfaceClientBufferTest, NegativeValidationBadAttributes)
{
ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(10, 10, 'BGRA', 4);
// Success case
{
// clang-format off
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,
};
// clang-format off
EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE, ioSurface.get(), mConfig, attribs);
EXPECT_NE(EGL_NO_SURFACE, pbuffer);
EGLBoolean result = eglDestroySurface(mDisplay, pbuffer);
EXPECT_EGL_TRUE(result); EXPECT_EGL_TRUE(result);
EXPECT_EGL_SUCCESS(); EXPECT_EGL_SUCCESS();
}
IOSurfaceLock(ioSurface, kIOSurfaceLockReadOnly, nullptr); // EGL_TEXTURE_FORMAT must be EGL_TEXTURE_RGBA
GLColor color = *reinterpret_cast<const GLColor*>(IOSurfaceGetBaseAddress(ioSurface)); {
IOSurfaceUnlock(ioSurface, kIOSurfaceLockReadOnly, nullptr); // clang-format off
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,
};
// clang-format on
CFRelease(ioSurface); EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
ioSurface.get(), mConfig, attribs);
EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
}
EXPECT_EQ(color, GLColor::green); // EGL_WIDTH must be at least 1
{
// clang-format off
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,
};
// clang-format on
EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
ioSurface.get(), mConfig, attribs);
EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
}
// EGL_WIDTH must be at most the width of the IOSurface
{
// clang-format off
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,
};
// clang-format on
EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
ioSurface.get(), mConfig, attribs);
EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
}
// EGL_HEIGHT must be at least 1
{
// clang-format off
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,
};
// clang-format on
EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
ioSurface.get(), mConfig, attribs);
EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
}
// EGL_HEIGHT must be at most the height of the IOSurface
{
// clang-format off
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,
};
// clang-format on
EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
ioSurface.get(), mConfig, attribs);
EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
}
// EGL_TEXTURE_FORMAT must be at EGL_TEXTURE_RECTANGLE_ANGLE
{
// clang-format off
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,
};
// clang-format on
EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
ioSurface.get(), mConfig, attribs);
EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
}
// EGL_IOSURFACE_PLANE_ANGLE must be at least 0
{
// clang-format off
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,
};
// clang-format on
EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
ioSurface.get(), mConfig, attribs);
EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
}
// EGL_IOSURFACE_PLANE_ANGLE must less than the number of planes of the IOSurface
{
// clang-format off
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,
};
// clang-format on
EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
ioSurface.get(), mConfig, attribs);
EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
}
// The internal format / type most be listed in the table
{
// clang-format off
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,
};
// clang-format on
EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE,
ioSurface.get(), mConfig, attribs);
EXPECT_EQ(EGL_NO_SURFACE, pbuffer);
EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
}
}
// Test IOSurface pbuffers cannot be made current
TEST_P(IOSurfaceClientBufferTest, MakeCurrentDisallowed)
{
ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(10, 10, 'BGRA', 4);
EGLSurface pbuffer;
createIOSurfacePbuffer(ioSurface, 10, 10, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, &pbuffer);
EGLContext context = getEGLWindow()->getContext();
EGLBoolean result = eglMakeCurrent(mDisplay, pbuffer, pbuffer, context);
EXPECT_EGL_FALSE(result);
EXPECT_EGL_ERROR(EGL_BAD_SURFACE);
} }
// TODO(cwallez@chromium.org): Test setting width and height to less than the IOSurface's work as
// expected.
ANGLE_INSTANTIATE_TEST(IOSurfaceClientBufferTest, ES3_OPENGL()); ANGLE_INSTANTIATE_TEST(IOSurfaceClientBufferTest, ES3_OPENGL());
...@@ -308,6 +308,11 @@ TEST_P(TextureRectangleTest, SamplingFromRectangle) ...@@ -308,6 +308,11 @@ TEST_P(TextureRectangleTest, SamplingFromRectangle)
"}\n"; "}\n";
ANGLE_GL_PROGRAM(program, vs, fs); ANGLE_GL_PROGRAM(program, vs, fs);
glUseProgram(program);
GLint location = glGetUniformLocation(program, "tex");
ASSERT_NE(-1, location);
glUniform1i(location, 0);
glClearColor(0.0, 0.0, 0.0, 0.0); glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment