Commit 710e408e by Geoff Lang Committed by Commit Bot

Add support for P010 IOSurfaces

Add test coverage of multi-plane IOSurfaces. Bug: chromium:1115621 Change-Id: Ib2150c4221a3e49f01ab016cebba4830194ab2b5 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2376174Reviewed-by: 's avatarJonah Ryan-Davis <jonahr@google.com> Commit-Queue: Geoff Lang <geofflang@chromium.org>
parent 8970ad3f
......@@ -21,7 +21,7 @@ Status
Draft
Version
Version 4, Dec 28, 2019
Version 6, Aug 25, 2020
Number
......@@ -109,8 +109,10 @@ 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
GL_UNSIGNED_SHORT GL_R16UI
GL_UNSIGNED_BYTE GL_RG
GL_UNSIGNED_SHORT GL_RG
GL_UNSIGNED_BYTE GL_RGB
GL_UNSIGNED_BYTE GL_BGRA_EXT
GL_UNSIGNED_INT_2_10_10_10_REV GL_RGB10_A2
......@@ -150,3 +152,4 @@ Revision History
Version 4, 2019/12/28 - Add usage hint; require TEXTURE_RECTANGLE on macOS
and TEXTURE_2D on iOS
Version 5, 2020/06/30 - Allow RGB10_A2 internal formats
Version 6, 2020/08/25 - Allow R16 and RG16 formats for P010 surfaces
......@@ -48,8 +48,10 @@ struct IOSurfaceFormatInfo
// clang-format off
static const IOSurfaceFormatInfo kIOSurfaceFormats[] = {
{GL_RED, GL_UNSIGNED_BYTE, 1, GL_RED, GL_RED, GL_UNSIGNED_BYTE },
{GL_RED, 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_SHORT, 4, GL_RG, GL_RG, GL_UNSIGNED_SHORT },
{GL_RGB, GL_UNSIGNED_BYTE, 4, GL_RGBA, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV },
{GL_BGRA_EXT, GL_UNSIGNED_BYTE, 4, GL_RGBA, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV },
{GL_RGB10_A2, GL_UNSIGNED_INT_2_10_10_10_REV, 4, GL_RGBA, GL_BGRA, GL_UNSIGNED_INT_2_10_10_10_REV},
......
......@@ -57,9 +57,11 @@ struct IOSurfaceFormatInfo
// clang-format off
// NOTE(hqle): Support R16_UINT once GLES3 is complete.
constexpr std::array<IOSurfaceFormatInfo, 6> kIOSurfaceFormats = {{
constexpr std::array<IOSurfaceFormatInfo, 8> kIOSurfaceFormats = {{
{GL_RED, GL_UNSIGNED_BYTE, 1, angle::FormatID::R8_UNORM},
{GL_RED, GL_UNSIGNED_SHORT, 2, angle::FormatID::R16_UNORM},
{GL_RG, GL_UNSIGNED_BYTE, 2, angle::FormatID::R8G8_UNORM},
{GL_RG, GL_UNSIGNED_SHORT, 4, angle::FormatID::R16G16_UNORM},
{GL_RGB, GL_UNSIGNED_BYTE, 4, angle::FormatID::B8G8R8A8_UNORM},
{GL_BGRA_EXT, GL_UNSIGNED_BYTE, 4, angle::FormatID::B8G8R8A8_UNORM},
{GL_RGBA, GL_HALF_FLOAT, 8, angle::FormatID::R16G16B16A16_FLOAT},
......
......@@ -35,10 +35,12 @@ struct IOSurfaceFormatInfo
};
// clang-format off
constexpr std::array<IOSurfaceFormatInfo, 7> kIOSurfaceFormats = {{
constexpr std::array<IOSurfaceFormatInfo, 9> kIOSurfaceFormats = {{
{GL_RED, GL_UNSIGNED_BYTE, 1, GL_R8 },
{GL_RED, GL_UNSIGNED_SHORT, 2, GL_R16_EXT },
{GL_R16UI, GL_UNSIGNED_SHORT, 2, GL_R16UI },
{GL_RG, GL_UNSIGNED_BYTE, 2, GL_RG8 },
{GL_RG, GL_UNSIGNED_SHORT, 4, GL_RG16_EXT },
{GL_RGB, GL_UNSIGNED_BYTE, 4, GL_BGRA8_EXT},
{GL_BGRA_EXT, GL_UNSIGNED_BYTE, 4, GL_BGRA8_EXT},
{GL_RGB10_A2, GL_UNSIGNED_INT_2_10_10_10_REV, 4, GL_BGR10_A2_ANGLEX },
......
......@@ -71,17 +71,47 @@ class ScopedIOSurfaceRef : angle::NonCopyable
IOSurfaceRef mSurface = nullptr;
};
ScopedIOSurfaceRef CreateSinglePlaneIOSurface(int width,
int height,
int32_t format,
int bytesPerElement)
struct IOSurfacePlaneInfo
{
int width;
int height;
int bytesPerElement;
};
ScopedIOSurfaceRef CreateIOSurface(int32_t format, const std::vector<IOSurfacePlaneInfo> &planes)
{
EXPECT_GT(planes.size(), 0u);
CFMutableDictionaryRef dict = CFDictionaryCreateMutable(
kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
AddIntegerValue(dict, kIOSurfaceWidth, width);
AddIntegerValue(dict, kIOSurfaceHeight, height);
AddIntegerValue(dict, kIOSurfaceWidth, planes[0].width);
AddIntegerValue(dict, kIOSurfaceHeight, planes[0].height);
AddIntegerValue(dict, kIOSurfacePixelFormat, format);
AddIntegerValue(dict, kIOSurfaceBytesPerElement, bytesPerElement);
if (planes.size() > 1)
{
CFMutableArrayRef planesInfo =
CFArrayCreateMutable(kCFAllocatorDefault, planes.size(), &kCFTypeArrayCallBacks);
for (const IOSurfacePlaneInfo &plane : planes)
{
CFMutableDictionaryRef planeInfo =
CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
AddIntegerValue(planeInfo, kIOSurfacePlaneWidth, plane.width);
AddIntegerValue(planeInfo, kIOSurfacePlaneHeight, plane.height);
AddIntegerValue(planeInfo, kIOSurfacePlaneBytesPerElement, plane.bytesPerElement);
CFArrayAppendValue(planesInfo, planeInfo);
CFRelease(planeInfo);
}
CFDictionaryAddValue(dict, kIOSurfacePlaneInfo, planesInfo);
CFRelease(planesInfo);
}
else
{
AddIntegerValue(dict, kIOSurfaceBytesPerElement, planes[0].bytesPerElement);
}
IOSurfaceRef ioSurface = IOSurfaceCreate(dict);
EXPECT_NE(nullptr, ioSurface);
......@@ -90,6 +120,15 @@ ScopedIOSurfaceRef CreateSinglePlaneIOSurface(int width,
return ScopedIOSurfaceRef(ioSurface);
}
ScopedIOSurfaceRef CreateSinglePlaneIOSurface(int width,
int height,
int32_t format,
int bytesPerElement)
{
std::vector<IOSurfacePlaneInfo> planes{{width, height, bytesPerElement}};
return CreateIOSurface(format, planes);
}
} // anonymous namespace
class IOSurfaceClientBufferTest : public ANGLETest
......@@ -173,16 +212,22 @@ class IOSurfaceClientBufferTest : public ANGLETest
}
void doClearTest(const ScopedIOSurfaceRef &ioSurface,
EGLint width,
EGLint height,
EGLint plane,
GLenum internalFormat,
GLenum type,
const GLColor &data)
{
std::array<uint8_t, 4> dataArray{data.R, data.G, data.B, data.A};
doClearTest(ioSurface, internalFormat, type, dataArray);
doClearTest(ioSurface, width, height, plane, internalFormat, type, dataArray);
}
template <typename T, size_t dataSize>
void doClearTest(const ScopedIOSurfaceRef &ioSurface,
EGLint width,
EGLint height,
EGLint plane,
GLenum internalFormat,
GLenum type,
const std::array<T, dataSize> &data)
......@@ -190,7 +235,8 @@ class IOSurfaceClientBufferTest : public ANGLETest
// Bind the IOSurface to a texture and clear it.
EGLSurface pbuffer;
GLTexture texture;
bindIOSurfaceToTexture(ioSurface, 1, 1, 0, internalFormat, type, &pbuffer, &texture);
bindIOSurfaceToTexture(ioSurface, width, height, plane, internalFormat, type, &pbuffer,
&texture);
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
......@@ -217,7 +263,7 @@ class IOSurfaceClientBufferTest : public ANGLETest
IOSurfaceLock(ioSurface.get(), kIOSurfaceLockReadOnly, nullptr);
std::array<T, dataSize> iosurfaceData;
memcpy(iosurfaceData.data(), IOSurfaceGetBaseAddress(ioSurface.get()),
memcpy(iosurfaceData.data(), IOSurfaceGetBaseAddressOfPlane(ioSurface.get(), plane),
sizeof(T) * data.size());
IOSurfaceUnlock(ioSurface.get(), kIOSurfaceLockReadOnly, nullptr);
......@@ -236,6 +282,9 @@ class IOSurfaceClientBufferTest : public ANGLETest
A = 8,
};
void doSampleTest(const ScopedIOSurfaceRef &ioSurface,
EGLint width,
EGLint height,
EGLint plane,
GLenum internalFormat,
GLenum type,
void *data,
......@@ -244,7 +293,7 @@ class IOSurfaceClientBufferTest : public ANGLETest
{
// Write the data to the IOSurface
IOSurfaceLock(ioSurface.get(), 0, nullptr);
memcpy(IOSurfaceGetBaseAddress(ioSurface.get()), data, dataSize);
memcpy(IOSurfaceGetBaseAddressOfPlane(ioSurface.get(), plane), data, dataSize);
IOSurfaceUnlock(ioSurface.get(), 0, nullptr);
GLTexture texture;
......@@ -254,9 +303,14 @@ class IOSurfaceClientBufferTest : public ANGLETest
// Bind the IOSurface to a texture and clear it.
EGLSurface pbuffer;
bindIOSurfaceToTexture(ioSurface, 1, 1, 0, internalFormat, type, &pbuffer, &texture);
bindIOSurfaceToTexture(ioSurface, width, height, plane, internalFormat, type, &pbuffer,
&texture);
doSampleTestWithTexture(texture, mask);
EGLBoolean result = eglDestroySurface(mDisplay, pbuffer);
EXPECT_EGL_TRUE(result);
EXPECT_EGL_SUCCESS();
}
void doSampleTestWithTexture(const GLTexture &texture, int mask)
......@@ -395,7 +449,7 @@ TEST_P(IOSurfaceClientBufferTest, RenderToBGRA8888IOSurface)
ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'BGRA', 4);
GLColor color(3, 2, 1, 4);
doClearTest(ioSurface, GL_BGRA_EXT, GL_UNSIGNED_BYTE, color);
doClearTest(ioSurface, 1, 1, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, color);
}
// Test reading from BGRA8888 IOSurfaces
......@@ -409,7 +463,8 @@ TEST_P(IOSurfaceClientBufferTest, ReadFromBGRA8888IOSurface)
ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'BGRA', 4);
GLColor color(3, 2, 1, 4);
doSampleTest(ioSurface, GL_BGRA_EXT, GL_UNSIGNED_BYTE, &color, sizeof(color), R | G | B | A);
doSampleTest(ioSurface, 1, 1, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, &color, sizeof(color),
R | G | B | A);
}
// Test using BGRX8888 IOSurfaces for rendering
......@@ -423,7 +478,7 @@ TEST_P(IOSurfaceClientBufferTest, RenderToBGRX8888IOSurface)
ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'BGRA', 4);
GLColor color(3, 2, 1, 255);
doClearTest(ioSurface, GL_RGB, GL_UNSIGNED_BYTE, color);
doClearTest(ioSurface, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, color);
}
// Test reading from BGRX8888 IOSurfaces
......@@ -434,7 +489,7 @@ TEST_P(IOSurfaceClientBufferTest, ReadFromBGRX8888IOSurface)
ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'BGRA', 4);
GLColor color(3, 2, 1, 4);
doSampleTest(ioSurface, GL_RGB, GL_UNSIGNED_BYTE, &color, sizeof(color), R | G | B);
doSampleTest(ioSurface, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, &color, sizeof(color), R | G | B);
}
// Test using RG88 IOSurfaces for rendering
......@@ -448,7 +503,7 @@ TEST_P(IOSurfaceClientBufferTest, RenderToRG88IOSurface)
ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, '2C08', 2);
std::array<uint8_t, 2> color{1, 2};
doClearTest(ioSurface, GL_RG, GL_UNSIGNED_BYTE, color);
doClearTest(ioSurface, 1, 1, 0, GL_RG, GL_UNSIGNED_BYTE, color);
}
// Test reading from RG88 IOSurfaces
......@@ -459,7 +514,7 @@ 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);
doSampleTest(ioSurface, 1, 1, 0, GL_RG, GL_UNSIGNED_BYTE, &color, sizeof(color), R | G);
}
// Test using R8 IOSurfaces for rendering
......@@ -473,7 +528,7 @@ TEST_P(IOSurfaceClientBufferTest, RenderToR8IOSurface)
ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'L008', 1);
std::array<uint8_t, 1> color{1};
doClearTest(ioSurface, GL_RED, GL_UNSIGNED_BYTE, color);
doClearTest(ioSurface, 1, 1, 0, GL_RED, GL_UNSIGNED_BYTE, color);
}
// Test reading from R8 IOSurfaces
......@@ -484,7 +539,7 @@ 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);
doSampleTest(ioSurface, 1, 1, 0, GL_RED, GL_UNSIGNED_BYTE, &color, sizeof(color), R);
}
// Test using R16 IOSurfaces for rendering
......@@ -503,7 +558,7 @@ TEST_P(IOSurfaceClientBufferTest, RenderToR16IOSurface)
ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'L016', 2);
std::array<uint16_t, 1> color{257};
doClearTest(ioSurface, GL_R16UI, GL_UNSIGNED_SHORT, color);
doClearTest(ioSurface, 1, 1, 0, GL_R16UI, GL_UNSIGNED_SHORT, color);
}
// TODO(cwallez@chromium.org): test reading from R16? It returns 0 maybe because samplerRect is
// only for floating textures?
......@@ -519,7 +574,7 @@ TEST_P(IOSurfaceClientBufferTest, RenderToBGRA1010102IOSurface)
ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'l10r', 4);
std::array<uint32_t, 1> color{(0 << 30) | (1 << 22) | (2 << 12) | (3 << 2)};
doClearTest(ioSurface, GL_RGB10_A2, GL_UNSIGNED_INT_2_10_10_10_REV, color);
doClearTest(ioSurface, 1, 1, 0, GL_RGB10_A2, GL_UNSIGNED_INT_2_10_10_10_REV, color);
}
// Test reading from BGRA_1010102 IOSurfaces
......@@ -530,7 +585,8 @@ TEST_P(IOSurfaceClientBufferTest, ReadFromBGRA1010102IOSurface)
ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'l10r', 4);
uint32_t color = (3 << 30) | (1 << 22) | (2 << 12) | (3 << 2);
doSampleTest(ioSurface, GL_RGB10_A2, GL_UNSIGNED_INT_2_10_10_10_REV, &color, sizeof(color),
doSampleTest(ioSurface, 1, 1, 0, GL_RGB10_A2, GL_UNSIGNED_INT_2_10_10_10_REV, &color,
sizeof(color),
R | G | B); // Don't test alpha, unorm '4' can't be represented with 2 bits.
}
......@@ -547,11 +603,11 @@ TEST_P(IOSurfaceClientBufferTest, RenderToRGBA16FIOSurface)
std::array<GLushort, 4> color{
gl::float32ToFloat16(1.0f / 255.0f), gl::float32ToFloat16(2.0f / 255.0f),
gl::float32ToFloat16(3.0f / 255.0f), gl::float32ToFloat16(4.0f / 255.0f)};
doClearTest(ioSurface, GL_RGBA, GL_HALF_FLOAT, color);
doClearTest(ioSurface, 1, 1, 0, GL_RGBA, GL_HALF_FLOAT, color);
}
// Test reading from RGBA_16F IOSurfaces
TEST_P(IOSurfaceClientBufferTest, ReadFromToRGBA16FIOSurfaceIOSurface)
TEST_P(IOSurfaceClientBufferTest, ReadFromToRGBA16FIOSurface)
{
ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
......@@ -563,11 +619,105 @@ TEST_P(IOSurfaceClientBufferTest, ReadFromToRGBA16FIOSurfaceIOSurface)
std::array<GLushort, 4> color{
gl::float32ToFloat16(1.0f / 255.0f), gl::float32ToFloat16(2.0f / 255.0f),
gl::float32ToFloat16(3.0f / 255.0f), gl::float32ToFloat16(4.0f / 255.0f)};
doSampleTest(ioSurface, GL_RGBA, GL_HALF_FLOAT, color.data(), sizeof(GLushort) * 4,
doSampleTest(ioSurface, 1, 1, 0, GL_RGBA, GL_HALF_FLOAT, color.data(), sizeof(GLushort) * 4,
R | G | B | A);
}
// TODO(cwallez@chromium.org): Test using RGBA half float IOSurfaces ('RGhA')
// Test using YUV420 IOSurfaces for rendering
TEST_P(IOSurfaceClientBufferTest, RenderToYUV420IOSurface)
{
ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
// TODO(http://anglebug.com/4369)
ANGLE_SKIP_TEST_IF(isSwiftshader());
std::vector<IOSurfacePlaneInfo> planes{{2, 2, 1}, {1, 1, 2}};
ScopedIOSurfaceRef ioSurface = CreateIOSurface('420v', planes);
{
std::array<GLubyte, 1> colors{1};
doClearTest(ioSurface, planes[0].width, planes[0].height, 0, GL_RED, GL_UNSIGNED_BYTE,
colors);
}
{
std::array<GLubyte, 2> colors{1, 2};
doClearTest(ioSurface, planes[1].width, planes[1].height, 1, GL_RG, GL_UNSIGNED_BYTE,
colors);
}
}
// Test reading from YUV420 IOSurfaces
TEST_P(IOSurfaceClientBufferTest, ReadFromToYUV420IOSurface)
{
ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
// TODO(http://anglebug.com/4369)
ANGLE_SKIP_TEST_IF(isSwiftshader());
std::vector<IOSurfacePlaneInfo> planes{{2, 2, 1}, {1, 1, 2}};
ScopedIOSurfaceRef ioSurface = CreateIOSurface('420v', planes);
{
std::array<GLubyte, 1> colors{1};
doSampleTest(ioSurface, planes[0].width, planes[0].height, 0, GL_RED, GL_UNSIGNED_BYTE,
colors.data(), sizeof(GLubyte) * colors.size(), R);
}
{
std::array<GLubyte, 2> colors{1, 2};
doSampleTest(ioSurface, planes[1].width, planes[1].height, 1, GL_RG, GL_UNSIGNED_BYTE,
colors.data(), sizeof(GLubyte) * colors.size(), R | G);
}
}
// Test using P010 IOSurfaces for rendering
TEST_P(IOSurfaceClientBufferTest, RenderToP010IOSurface)
{
ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
// TODO(http://anglebug.com/4369)
ANGLE_SKIP_TEST_IF(isSwiftshader());
std::vector<IOSurfacePlaneInfo> planes{{2, 2, 2}, {1, 1, 4}};
ScopedIOSurfaceRef ioSurface = CreateIOSurface('x420', planes);
{
std::array<GLushort, 1> colors{257};
doClearTest(ioSurface, planes[0].width, planes[0].height, 0, GL_RED, GL_UNSIGNED_SHORT,
colors);
}
{
std::array<GLushort, 2> colors{257, 514};
doClearTest(ioSurface, planes[1].width, planes[1].height, 1, GL_RG, GL_UNSIGNED_SHORT,
colors);
}
}
// Test reading from P010 IOSurfaces
TEST_P(IOSurfaceClientBufferTest, ReadFromToP010IOSurface)
{
ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
// TODO(http://anglebug.com/4369)
ANGLE_SKIP_TEST_IF(isSwiftshader());
std::vector<IOSurfacePlaneInfo> planes{{2, 2, 2}, {1, 1, 4}};
ScopedIOSurfaceRef ioSurface = CreateIOSurface('x420', planes);
{
std::array<GLushort, 1> colors{257};
doSampleTest(ioSurface, planes[0].width, planes[0].height, 0, GL_RED, GL_UNSIGNED_SHORT,
colors.data(), sizeof(GLushort) * colors.size(), R);
}
{
std::array<GLushort, 2> colors{257, 514};
doSampleTest(ioSurface, planes[1].width, planes[1].height, 1, GL_RG, GL_UNSIGNED_SHORT,
colors.data(), sizeof(GLushort) * colors.size(), R | G);
}
}
// Test blitting from IOSurface
TEST_P(IOSurfaceClientBufferTest, BlitFromIOSurface)
......
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