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)
Append to the end of Section 3.5.3.
"When <buftype> is EGL_IOSURFACE_ANGLE, <attrib_list> must contain all the
following attributes under the following constraints otherwise
EGL_BAD_PARAMETER is generated:
following attributes otherwise EGL_BAD_PARAMETER is generated. The
attributes must satisfy the following constraints otherwise
EGL_BAD_ATTRIBUTE is generated:
- EGL_TEXTURE_TYPE_ANGLE, and EGL_TEXTURE_INTERNAL_FORMAT_ANGLE followed
by OpenGL enums for texture types, and texture internal format
respectively.
- EGL_TEXTURE_FORMAT with a value of EGL_TEXTURE_RGBA
- 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_IOSURFACE_PLANE_ANGLE with a value between 0 and the number of
planes of <buffer> (exclusive).
......@@ -93,7 +94,7 @@ Additions to Chapter 3 of the EGL 1.4 Specification (EGL Functions and Errors)
Texture Type Texture Internal Format
---------------------------------------------------------------------------
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_BGRA_EXT
GL_HALF_FLOAT GL_RGBA
......
......@@ -42,7 +42,7 @@ struct IOSurfaceFormatInfo
// clang-format off
static const IOSurfaceFormatInfo kIOSurfaceFormats[] = {
{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_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 },
......@@ -211,7 +211,7 @@ bool IOSurfaceSurfaceCGL::validateAttributes(EGLClientBuffer buffer,
EGLAttrib width = attribs.get(EGL_WIDTH);
EGLAttrib height = attribs.get(EGL_HEIGHT);
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;
}
......
......@@ -1200,8 +1200,8 @@ Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, E
(textureFormat == EGL_TEXTURE_RGBA && config->bindToTextureRGBA != EGL_TRUE))
{
// 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
// bindToTextureRGB/RGBA flag. This issue is that enabling this flags means that
// set so that eglBindTexImage works. Normally this is only allowed if the config exposes
// 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.
// 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
......
......@@ -7,13 +7,13 @@
//
#include "test_utils/ANGLETest.h"
#include "common/mathutil.h"
#include "test_utils/gl_raii.h"
#include <CoreFoundation/CoreFoundation.h>
#include <IOSurface/IOSurface.h>
#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
using namespace angle;
namespace
......@@ -26,6 +26,67 @@ void AddIntegerValue(CFMutableDictionaryRef dictionary, const CFStringRef key, i
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
class IOSurfaceClientBufferTest : public ANGLETest
......@@ -43,76 +104,624 @@ class IOSurfaceClientBufferTest : public ANGLETest
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;
EGLDisplay mDisplay;
};
// Test using BGRA8888 IOSurfaces for rendering
TEST_P(IOSurfaceClientBufferTest, RenderToBGRA8888IOSurface)
{
// Create a 1 by 1 BGRA8888 IOSurface
IOSurfaceRef ioSurface = nullptr;
ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'BGRA', 4);
CFMutableDictionaryRef dict = CFDictionaryCreateMutable(
kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
AddIntegerValue(dict, kIOSurfaceWidth, 1);
AddIntegerValue(dict, kIOSurfaceHeight, 1);
AddIntegerValue(dict, kIOSurfacePixelFormat, 'BGRA');
AddIntegerValue(dict, kIOSurfaceBytesPerElement, 4);
GLColor color(3, 2, 1, 4);
doClearTest(ioSurface, GL_BGRA_EXT, GL_UNSIGNED_BYTE, &color, sizeof(color));
}
ioSurface = IOSurfaceCreate(dict);
CFRelease(dict);
// Test reading from BGRA8888 IOSurfaces
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);
}
// Make a PBuffer from it using the EGL_ANGLE_iosurface_client_buffer extension
// clang-format off
const EGLint attribs[] = {
EGL_WIDTH, 1,
EGL_HEIGHT, 1,
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, mConfig, attribs);
EXPECT_NE(EGL_NO_SURFACE, pbuffer);
// Bind and glClear the pbuffer
GLTexture tex;
glBindTexture(GL_TEXTURE_RECTANGLE_ANGLE, tex);
EGLBoolean result = eglBindTexImage(mDisplay, pbuffer, EGL_BACK_BUFFER);
EXPECT_EGL_TRUE(result);
EXPECT_EGL_SUCCESS();
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
EXPECT_GL_NO_ERROR();
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ANGLE, tex, 0);
EXPECT_GL_NO_ERROR();
EXPECT_GLENUM_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER), GL_FRAMEBUFFER_COMPLETE);
EXPECT_GL_NO_ERROR();
glClearColor(0, 1, 0, 1);
EXPECT_GL_NO_ERROR();
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_GL_NO_ERROR();
// Unbind pbuffer and check content.
result = eglReleaseTexImage(mDisplay, pbuffer, EGL_BACK_BUFFER);
EXPECT_EGL_TRUE(result);
EXPECT_EGL_SUCCESS();
IOSurfaceLock(ioSurface, kIOSurfaceLockReadOnly, nullptr);
GLColor color = *reinterpret_cast<const GLColor*>(IOSurfaceGetBaseAddress(ioSurface));
IOSurfaceUnlock(ioSurface, kIOSurfaceLockReadOnly, nullptr);
CFRelease(ioSurface);
EXPECT_EQ(color, GLColor::green);
// 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);
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
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_SUCCESS();
}
// Missing EGL_WIDTH
{
// clang-format off
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,
};
// 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_HEIGHT
{
// 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_SUCCESS();
}
// EGL_TEXTURE_FORMAT must be EGL_TEXTURE_RGBA
{
// 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
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 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());
......@@ -308,6 +308,11 @@ TEST_P(TextureRectangleTest, SamplingFromRectangle)
"}\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);
......
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