Commit 198dc345 by Sunny Sachanandani Committed by Commit Bot

Support importing NV12/P010/P016 D3D textures as EGLImage

Allow importing individual planes of NV12/P010/P016 D3D textures with supported SRV/RTV formats. Restrict these to GL_TEXTURE_EXTERNAL_OES to limit to using as shader inputs or render targets and prevent unsupported operations like ReadPixels. Test: D3DTextureYUVTest* Bug: angleproject:5538, chromium:1116101 Change-Id: If5bf54f4f75bb2c703890ce3f5fbd67e4461c98f Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2338827 Commit-Queue: Sunny Sachanandani <sunnyps@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 124cdcb5
...@@ -83,6 +83,10 @@ Additions to Chapter 2 of the EGL 1.2 Specification (EGL Operation) ...@@ -83,6 +83,10 @@ Additions to Chapter 2 of the EGL 1.2 Specification (EGL Operation)
<buffer> according to the provided internal format. See table <buffer> according to the provided internal format. See table
egl.restrictions for acceptable texture object types and formats. egl.restrictions for acceptable texture object types and formats.
If EGL_D3D11_TEXTURE_PLANE_ANGLE is specified, it is used to access the
specified plane of <buffer>. See table egl.restrictions for acceptable
values.
If EGL_TEXTURE_OFFSET_X_ANGLE or EGL_TEXTURE_OFFSET_Y_ANGLE are specified, If EGL_TEXTURE_OFFSET_X_ANGLE or EGL_TEXTURE_OFFSET_Y_ANGLE are specified,
they must be non-negative and are used to offset all rendering into the they must be non-negative and are used to offset all rendering into the
surface including blits, clears and draws. surface including blits, clears and draws.
...@@ -140,16 +144,32 @@ Additions to Chapter 3 of the EGL 1.2 Specification (EGL Functions and Errors) ...@@ -140,16 +144,32 @@ Additions to Chapter 3 of the EGL 1.2 Specification (EGL Functions and Errors)
DXGI_FORMAT_R8G8B8A8_TYPELESS (support is optional), DXGI_FORMAT_R8G8B8A8_TYPELESS (support is optional),
DXGI_FORMAT_B8G8R8A8_TYPELESS (support is optional), DXGI_FORMAT_B8G8R8A8_TYPELESS (support is optional),
DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT,
DXGI_FORMAT_R32G32B32A32_FLOAT, or DXGI_FORMAT_R32G32B32A32_FLOAT,
DXGI_FORMAT_R10G10B10A2_UNORM. DXGI_FORMAT_R10G10B10A2_UNORM,
DXGI_FORMAT_NV12,
DXGI_FORMAT_P010, or
DXGI_FORMAT_P016.
EGL_D3D11_TEXTURE_PLANE_ANGLE must be specified for YUV
formats DXGI_FORMAT_NV12, DXGI_FORMAT_P010, or
DXGI_FORMAT_P016, and must be 0 or 1.
EGL_TEXTURE_INTERNAL_FORMAT_ANGLE (if supported) must be EGL_TEXTURE_INTERNAL_FORMAT_ANGLE (if supported) must be
GL_RGBA (supported for all formats), GL_RGBA (supported for all non-YUV formats),
GL_RGB (supported except for DXGI_FORMAT_R10G10B10A2_UNORM), or GL_RGB (supported for all non-YUV formats except
DXGI_FORMAT_R10G10B10A2_UNORM),
GL_BGRA_EXT (supported only for GL_BGRA_EXT (supported only for
DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM,
DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, or DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, or
DXGI_FORMAT_B8G8R8A8_TYPELESS). DXGI_FORMAT_B8G8R8A8_TYPELESS),
GL_R8_EXT (supported only for plane 0 with
DXGI_FORMAT_NV12),
GL_RG8_EXT (supported only for plane 1 with
DXGI_FORMAT_NV12),
GL_R16_EXT (supported only for plane 0 with
DXGI_FORMAT_P010 or DXGI_FORMAT_P016), or
GL_RG16_EXT (supported only for plane 1 with
DXGI_FORMAT_P010 or DXGI_FORMAT_P016).
-------------------------------------------------------------------------- --------------------------------------------------------------------------
Table egl.restrictions - Restrictions on D3D resources that can be used Table egl.restrictions - Restrictions on D3D resources that can be used
...@@ -210,6 +230,8 @@ Issues ...@@ -210,6 +230,8 @@ Issues
Revision History Revision History
Version 7, 2021/01/12 - added support for NV12/P010/P016 planar formats.
Version 6, 2020/05/12 - added support for specifying texture offsets. Version 6, 2020/05/12 - added support for specifying texture offsets.
Version 5, 2019/09/06 - added support for creating EGLImage. Version 5, 2019/09/06 - added support for creating EGLImage.
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#define EGL_D3D_TEXTURE_ANGLE 0x33A3 #define EGL_D3D_TEXTURE_ANGLE 0x33A3
#define EGL_TEXTURE_OFFSET_X_ANGLE 0x3490 #define EGL_TEXTURE_OFFSET_X_ANGLE 0x3490
#define EGL_TEXTURE_OFFSET_Y_ANGLE 0x3491 #define EGL_TEXTURE_OFFSET_Y_ANGLE 0x3491
#define EGL_D3D11_TEXTURE_PLANE_ANGLE 0x3492
#endif /* EGL_ANGLE_d3d_texture_client_buffer */ #endif /* EGL_ANGLE_d3d_texture_client_buffer */
#ifndef EGL_ANGLE_software_display #ifndef EGL_ANGLE_software_display
......
...@@ -52,6 +52,9 @@ egl::Error ExternalImageSiblingImpl11::initialize(const egl::Display *display) ...@@ -52,6 +52,9 @@ egl::Error ExternalImageSiblingImpl11::initialize(const egl::Display *display)
mIsTexturable = (textureDesc.BindFlags & D3D11_BIND_SHADER_RESOURCE) && mIsTexturable = (textureDesc.BindFlags & D3D11_BIND_SHADER_RESOURCE) &&
(resourceUsage & DXGI_USAGE_SHADER_INPUT); (resourceUsage & DXGI_USAGE_SHADER_INPUT);
mYUV = (textureDesc.Format == DXGI_FORMAT_NV12 || textureDesc.Format == DXGI_FORMAT_P010 ||
textureDesc.Format == DXGI_FORMAT_P016);
return egl::NoError(); return egl::NoError();
} }
......
...@@ -1438,14 +1438,8 @@ egl::Error Renderer11::getD3DTextureInfo(const egl::Config *configuration, ...@@ -1438,14 +1438,8 @@ egl::Error Renderer11::getD3DTextureInfo(const egl::Config *configuration,
D3D11_TEXTURE2D_DESC desc = {}; D3D11_TEXTURE2D_DESC desc = {};
d3dTexture->GetDesc(&desc); d3dTexture->GetDesc(&desc);
if (width) EGLint imageWidth = static_cast<EGLint>(desc.Width);
{ EGLint imageHeight = static_cast<EGLint>(desc.Height);
*width = static_cast<EGLint>(desc.Width);
}
if (height)
{
*height = static_cast<EGLint>(desc.Height);
}
GLsizei sampleCount = static_cast<GLsizei>(desc.SampleDesc.Count); GLsizei sampleCount = static_cast<GLsizei>(desc.SampleDesc.Count);
if (configuration && (configuration->samples != sampleCount)) if (configuration && (configuration->samples != sampleCount))
...@@ -1459,63 +1453,123 @@ egl::Error Renderer11::getD3DTextureInfo(const egl::Config *configuration, ...@@ -1459,63 +1453,123 @@ egl::Error Renderer11::getD3DTextureInfo(const egl::Config *configuration,
return egl::EglBadParameter() << "Texture's sample count does not match."; return egl::EglBadParameter() << "Texture's sample count does not match.";
} }
} }
if (samples)
{
// EGL samples 0 corresponds to D3D11 sample count 1.
*samples = sampleCount != 1 ? sampleCount : 0;
}
// From table egl.restrictions in EGL_ANGLE_d3d_texture_client_buffer. const angle::Format *textureAngleFormat = nullptr;
switch (desc.Format) GLenum sizedInternalFormat = GL_NONE;
{
case DXGI_FORMAT_R8G8B8A8_UNORM:
case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
case DXGI_FORMAT_R8G8B8A8_TYPELESS:
case DXGI_FORMAT_B8G8R8A8_UNORM:
case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
case DXGI_FORMAT_B8G8R8A8_TYPELESS:
case DXGI_FORMAT_R16G16B16A16_FLOAT:
case DXGI_FORMAT_R32G32B32A32_FLOAT:
case DXGI_FORMAT_R10G10B10A2_UNORM:
break;
default: // From table egl.restrictions in EGL_ANGLE_d3d_texture_client_buffer.
if (desc.Format == DXGI_FORMAT_NV12 || desc.Format == DXGI_FORMAT_P010 ||
desc.Format == DXGI_FORMAT_P016)
{
if (!attribs.contains(EGL_D3D11_TEXTURE_PLANE_ANGLE))
{
return egl::EglBadParameter() return egl::EglBadParameter()
<< "Invalid client buffer texture format: " << desc.Format; << "EGL_D3D11_TEXTURE_PLANE_ANGLE must be specified for YUV textures.";
} }
const angle::Format *textureAngleFormat = &d3d11_angle::GetFormat(desc.Format); EGLint plane = attribs.getAsInt(EGL_D3D11_TEXTURE_PLANE_ANGLE);
ASSERT(textureAngleFormat);
GLenum sizedInternalFormat = textureAngleFormat->glInternalFormat; // P010 and P016 have the same memory layout, SRV/RTV format, etc.
const bool isNV12 = (desc.Format == DXGI_FORMAT_NV12);
if (plane == 0)
{
textureAngleFormat = isNV12 ? &angle::Format::Get(angle::FormatID::R8_UNORM)
: &angle::Format::Get(angle::FormatID::R16_UNORM);
}
else if (plane == 1)
{
textureAngleFormat = isNV12 ? &angle::Format::Get(angle::FormatID::R8G8_UNORM)
: &angle::Format::Get(angle::FormatID::R16G16_UNORM);
imageWidth /= 2;
imageHeight /= 2;
}
else
{
return egl::EglBadParameter() << "Invalid client buffer texture plane: " << plane;
}
ASSERT(textureAngleFormat);
if (attribs.contains(EGL_TEXTURE_INTERNAL_FORMAT_ANGLE)) sizedInternalFormat = textureAngleFormat->glInternalFormat;
if (attribs.contains(EGL_TEXTURE_INTERNAL_FORMAT_ANGLE))
{
const GLenum internalFormat =
static_cast<GLenum>(attribs.get(EGL_TEXTURE_INTERNAL_FORMAT_ANGLE));
if (internalFormat != sizedInternalFormat)
{
return egl::EglBadParameter()
<< "Invalid client buffer internal format: " << std::hex << internalFormat;
}
}
}
else
{ {
const GLenum internalFormat = switch (desc.Format)
static_cast<GLenum>(attribs.get(EGL_TEXTURE_INTERNAL_FORMAT_ANGLE));
switch (internalFormat)
{ {
case GL_RGBA: case DXGI_FORMAT_R8G8B8A8_UNORM:
case GL_BGRA_EXT: case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
case GL_RGB: case DXGI_FORMAT_R8G8B8A8_TYPELESS:
case DXGI_FORMAT_B8G8R8A8_UNORM:
case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
case DXGI_FORMAT_B8G8R8A8_TYPELESS:
case DXGI_FORMAT_R16G16B16A16_FLOAT:
case DXGI_FORMAT_R32G32B32A32_FLOAT:
case DXGI_FORMAT_R10G10B10A2_UNORM:
break; break;
default: default:
return egl::EglBadParameter() return egl::EglBadParameter()
<< "Invalid client buffer texture internal format: " << std::hex << "Invalid client buffer texture format: " << desc.Format;
<< internalFormat;
} }
const GLenum type = gl::GetSizedInternalFormatInfo(sizedInternalFormat).type; textureAngleFormat = &d3d11_angle::GetFormat(desc.Format);
ASSERT(textureAngleFormat);
const auto format = gl::Format(internalFormat, type); sizedInternalFormat = textureAngleFormat->glInternalFormat;
if (!format.valid())
if (attribs.contains(EGL_TEXTURE_INTERNAL_FORMAT_ANGLE))
{ {
return egl::EglBadParameter() const GLenum internalFormat =
<< "Invalid client buffer texture internal format: " << std::hex static_cast<GLenum>(attribs.get(EGL_TEXTURE_INTERNAL_FORMAT_ANGLE));
<< internalFormat; switch (internalFormat)
{
case GL_RGBA:
case GL_BGRA_EXT:
case GL_RGB:
break;
default:
return egl::EglBadParameter()
<< "Invalid client buffer texture internal format: " << std::hex
<< internalFormat;
}
const GLenum type = gl::GetSizedInternalFormatInfo(sizedInternalFormat).type;
const auto format = gl::Format(internalFormat, type);
if (!format.valid())
{
return egl::EglBadParameter()
<< "Invalid client buffer texture internal format: " << std::hex
<< internalFormat;
}
sizedInternalFormat = format.info->sizedInternalFormat;
} }
}
sizedInternalFormat = format.info->sizedInternalFormat; if (width)
{
*width = imageWidth;
}
if (height)
{
*height = imageHeight;
}
if (samples)
{
// EGL samples 0 corresponds to D3D11 sample count 1.
*samples = sampleCount != 1 ? sampleCount : 0;
} }
if (glFormat) if (glFormat)
......
...@@ -2888,6 +2888,16 @@ bool ValidateCreateImage(const ValidationContext *val, ...@@ -2888,6 +2888,16 @@ bool ValidateCreateImage(const ValidationContext *val,
} }
break; break;
case EGL_D3D11_TEXTURE_PLANE_ANGLE:
if (!displayExtensions.imageD3D11Texture)
{
val->setError(EGL_BAD_ATTRIBUTE,
"EGL_D3D11_TEXTURE_PLANE_ANGLE cannot be used without "
"EGL_ANGLE_image_d3d11_texture support.");
return false;
}
break;
case EGL_WIDTH: case EGL_WIDTH:
case EGL_HEIGHT: case EGL_HEIGHT:
if (target != EGL_LINUX_DMA_BUF_EXT) if (target != EGL_LINUX_DMA_BUF_EXT)
......
...@@ -4442,6 +4442,13 @@ bool ValidateEGLImageTargetTexture2DOES(const Context *context, ...@@ -4442,6 +4442,13 @@ bool ValidateEGLImageTargetTexture2DOES(const Context *context,
return false; return false;
} }
if (imageObject->isYUV() && type != TextureType::External)
{
context->validationError(GL_INVALID_OPERATION,
"Image is YUV, target must be TEXTURE_EXTERNAL_OES");
return false;
}
return true; return true;
} }
......
...@@ -117,6 +117,7 @@ class D3DTextureTest : public ANGLETest ...@@ -117,6 +117,7 @@ class D3DTextureTest : public ANGLETest
void testTearDown() override void testTearDown() override
{ {
glDeleteProgram(mTextureProgram); glDeleteProgram(mTextureProgram);
glDeleteProgram(mTextureProgramNoSampling);
if (mD3D11Device) if (mD3D11Device)
{ {
...@@ -1429,10 +1430,247 @@ TEST_P(D3DTextureTest, RGBEmulationTextureImage) ...@@ -1429,10 +1430,247 @@ TEST_P(D3DTextureTest, RGBEmulationTextureImage)
d3d11_texture->Release(); d3d11_texture->Release();
} }
class D3DTextureYUVTest : public D3DTextureTest
{
protected:
D3DTextureYUVTest() : D3DTextureTest() {}
void RunYUVTest(DXGI_FORMAT format)
{
ASSERT_TRUE(format == DXGI_FORMAT_NV12 || format == DXGI_FORMAT_P010 ||
format == DXGI_FORMAT_P016);
UINT formatSupport;
ANGLE_SKIP_TEST_IF(!valid() || !IsD3D11() ||
FAILED(mD3D11Device->CheckFormatSupport(format, &formatSupport)));
ASSERT_TRUE(formatSupport &
(D3D11_FORMAT_SUPPORT_TEXTURE2D | D3D11_FORMAT_SUPPORT_SHADER_SAMPLE));
constexpr char kVS[] =
R"(precision highp float;
attribute vec4 position;
varying vec2 texcoord;
void main()
{
gl_Position = position;
texcoord = (position.xy * 0.5) + 0.5;
texcoord.y = 1.0 - texcoord.y;
})";
constexpr char kTextureExternalOESFS[] =
R"(#extension GL_OES_EGL_image_external : require
precision highp float;
uniform samplerExternalOES tex;
varying vec2 texcoord;
void main()
{
gl_FragColor = texture2D(tex, texcoord);
})";
GLuint textureExternalOESProgram = CompileProgram(kVS, kTextureExternalOESFS);
ASSERT_NE(0u, textureExternalOESProgram) << "shader compilation failed.";
GLint textureExternalOESUniformLocation =
glGetUniformLocation(textureExternalOESProgram, "tex");
ASSERT_NE(-1, textureExternalOESUniformLocation);
EGLWindow *window = getEGLWindow();
EGLDisplay display = window->getDisplay();
window->makeCurrent();
const UINT bufferSize = 32;
EXPECT_TRUE(mD3D11Device != nullptr);
ID3D11Texture2D *d3d11_texture = nullptr;
CD3D11_TEXTURE2D_DESC desc(format, bufferSize, bufferSize, 1, 1,
D3D11_BIND_SHADER_RESOURCE);
const bool isNV12 = (format == DXGI_FORMAT_NV12);
const unsigned kYFillValue = isNV12 ? 0x12 : 0x1234;
const unsigned kUFillValue = isNV12 ? 0x23 : 0x2345;
const unsigned kVFillValue = isNV12 ? 0x34 : 0x3456;
std::vector<unsigned char> imageData;
if (isNV12)
{
imageData.resize(bufferSize * bufferSize * 3 / 2);
memset(imageData.data(), kYFillValue, bufferSize * bufferSize);
const size_t kUVOffset = bufferSize * bufferSize;
for (size_t i = 0; i < bufferSize * bufferSize / 2; i += 2)
{
imageData[kUVOffset + i] = kUFillValue;
imageData[kUVOffset + i + 1] = kVFillValue;
}
}
else
{
imageData.resize(bufferSize * bufferSize * 3);
const size_t kUVOffset = bufferSize * bufferSize * 2;
for (size_t i = 0; i < kUVOffset; i += 2)
{
imageData[i] = kYFillValue & 0xff;
imageData[i + 1] = (kYFillValue >> 8) & 0xff;
if (kUVOffset + i < imageData.size())
{
// Interleave U & V samples.
const unsigned fill = (i % 4 == 0) ? kUFillValue : kVFillValue;
imageData[kUVOffset + i] = fill & 0xff;
imageData[kUVOffset + i + 1] = (fill >> 8) & 0xff;
}
}
}
D3D11_SUBRESOURCE_DATA data = {};
data.pSysMem = static_cast<const void *>(imageData.data());
data.SysMemPitch = isNV12 ? bufferSize : bufferSize * 2;
EXPECT_TRUE(SUCCEEDED(mD3D11Device->CreateTexture2D(&desc, &data, &d3d11_texture)));
const EGLint yAttribs[] = {EGL_D3D11_TEXTURE_PLANE_ANGLE, 0,
EGL_TEXTURE_INTERNAL_FORMAT_ANGLE,
isNV12 ? GL_R8_EXT : GL_R16_EXT, EGL_NONE};
EGLImage yImage = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_D3D11_TEXTURE_ANGLE,
static_cast<EGLClientBuffer>(d3d11_texture), yAttribs);
ASSERT_EGL_SUCCESS();
ASSERT_NE(yImage, EGL_NO_IMAGE_KHR);
// Create and bind Y plane texture to image.
GLuint yTexture;
glGenTextures(1, &yTexture);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_EXTERNAL_OES, yTexture);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
ASSERT_GL_NO_ERROR();
glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, yImage);
ASSERT_GL_NO_ERROR();
GLuint rbo;
glGenRenderbuffers(1, &rbo);
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
glRenderbufferStorage(GL_RENDERBUFFER, isNV12 ? GL_RGBA8_OES : GL_RGBA16_EXT, bufferSize,
bufferSize);
ASSERT_GL_NO_ERROR();
GLuint fbo;
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
EXPECT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER),
static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE));
ASSERT_GL_NO_ERROR();
// Draw the Y plane using a shader.
glUseProgram(textureExternalOESProgram);
glUniform1i(textureExternalOESUniformLocation, 0);
ASSERT_GL_NO_ERROR();
glViewport(0, 0, bufferSize, bufferSize);
drawQuad(textureExternalOESProgram, "position", 1.0f);
ASSERT_GL_NO_ERROR();
if (isNV12)
{
EXPECT_PIXEL_EQ(static_cast<GLint>(bufferSize) / 2, static_cast<GLint>(bufferSize) / 2,
kYFillValue, 0, 0, 0xff);
}
else
{
EXPECT_PIXEL_16UI(static_cast<GLint>(bufferSize) / 2,
static_cast<GLint>(bufferSize) / 2, kYFillValue, 0, 0, 0xffff);
}
ASSERT_GL_NO_ERROR();
const EGLint uvAttribs[] = {EGL_D3D11_TEXTURE_PLANE_ANGLE, 1,
EGL_TEXTURE_INTERNAL_FORMAT_ANGLE,
isNV12 ? GL_RG8_EXT : GL_RG16_EXT, EGL_NONE};
EGLImage uvImage =
eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_D3D11_TEXTURE_ANGLE,
static_cast<EGLClientBuffer>(d3d11_texture), uvAttribs);
ASSERT_EGL_SUCCESS();
ASSERT_NE(uvImage, EGL_NO_IMAGE_KHR);
// Create and bind UV plane texture to image.
GLuint uvTexture;
glGenTextures(1, &uvTexture);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_EXTERNAL_OES, uvTexture);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
ASSERT_GL_NO_ERROR();
glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, uvImage);
ASSERT_GL_NO_ERROR();
// Draw the UV plane using a shader.
glUseProgram(textureExternalOESProgram);
glUniform1i(textureExternalOESUniformLocation, 0);
ASSERT_GL_NO_ERROR();
// Use only half of the framebuffer to match UV plane dimensions.
glViewport(0, 0, bufferSize / 2, bufferSize / 2);
drawQuad(textureExternalOESProgram, "position", 1.0f);
ASSERT_GL_NO_ERROR();
if (isNV12)
{
EXPECT_PIXEL_EQ(static_cast<GLint>(bufferSize) / 4, static_cast<GLint>(bufferSize) / 4,
kUFillValue, kVFillValue, 0, 0xff);
}
else
{
EXPECT_PIXEL_16UI(static_cast<GLint>(bufferSize) / 4,
static_cast<GLint>(bufferSize) / 4, kUFillValue, kVFillValue, 0,
0xffff);
}
ASSERT_GL_NO_ERROR();
glDeleteTextures(1, &uvTexture);
glDeleteTextures(1, &yTexture);
glDeleteFramebuffers(1, &fbo);
glDeleteRenderbuffers(1, &rbo);
d3d11_texture->Release();
}
};
TEST_P(D3DTextureYUVTest, NV12TextureImage)
{
RunYUVTest(DXGI_FORMAT_NV12);
}
// Reading back from RGBA16_EXT renderbuffer needs GL_EXT_texture_norm16 which is ES3 only.
class D3DTextureYUVTestES3 : public D3DTextureYUVTest
{
protected:
D3DTextureYUVTestES3() : D3DTextureYUVTest() {}
};
TEST_P(D3DTextureYUVTestES3, P010TextureImage)
{
RunYUVTest(DXGI_FORMAT_P010);
}
TEST_P(D3DTextureYUVTestES3, P016TextureImage)
{
RunYUVTest(DXGI_FORMAT_P016);
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these // Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against. // tests should be run against.
ANGLE_INSTANTIATE_TEST_ES2(D3DTextureTest); ANGLE_INSTANTIATE_TEST_ES2(D3DTextureTest);
ANGLE_INSTANTIATE_TEST_ES2(D3DTextureYUVTest);
ANGLE_INSTANTIATE_TEST_ES3(D3DTextureTestES3); ANGLE_INSTANTIATE_TEST_ES3(D3DTextureTestES3);
ANGLE_INSTANTIATE_TEST_ES3(D3DTextureYUVTestES3);
// D3D Debug device reports an error. http://anglebug.com/3513 // D3D Debug device reports an error. http://anglebug.com/3513
// ANGLE_INSTANTIATE_TEST(D3DTextureTestMS, ES2_D3D11()); // ANGLE_INSTANTIATE_TEST(D3DTextureTestMS, ES2_D3D11());
} // namespace angle } // namespace angle
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