Bug 1322746 - Add NV12 rgb color consumer for ID3D11Texture2D to EGLStream support to ANGLE. - r=jerry
MozReview-Commit-ID: APdX8RFyYD7
--- a/gfx/angle/src/libANGLE/Stream.cpp
+++ b/gfx/angle/src/libANGLE/Stream.cpp
@@ -120,17 +120,17 @@ Error Stream::createConsumerGLTextureExt
const auto &glState = context->getGLState();
EGLenum bufferType = attributes.getAsInt(EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER);
if (bufferType == EGL_RGB_BUFFER)
{
mPlanes[0].texture = glState.getTargetTexture(GL_TEXTURE_EXTERNAL_OES);
ASSERT(mPlanes[0].texture != nullptr);
mPlanes[0].texture->bindStream(this);
mConsumerType = ConsumerType::GLTextureRGB;
- mPlaneCount = 1;
+ mPlaneCount = 1;
}
else
{
mPlaneCount = attributes.getAsInt(EGL_YUV_NUMBER_OF_PLANES_EXT, 2);
ASSERT(mPlaneCount <= 3);
for (EGLint i = 0; i < mPlaneCount; i++)
{
// Fetch all the textures
@@ -158,28 +158,29 @@ Error Stream::createConsumerGLTextureExt
mState = EGL_STREAM_STATE_CONNECTING_KHR;
return Error(EGL_SUCCESS);
}
Error Stream::createProducerD3D11TextureNV12(const AttributeMap &attributes)
{
ASSERT(mState == EGL_STREAM_STATE_CONNECTING_KHR);
- ASSERT(mConsumerType == ConsumerType::GLTextureYUV);
+ ASSERT(mConsumerType == ConsumerType::GLTextureRGB ||
+ mConsumerType == ConsumerType::GLTextureYUV);
ASSERT(mProducerType == ProducerType::NoProducer);
- ASSERT(mPlaneCount == 2);
mProducerImplementation = mDisplay->getImplementation()->createStreamProducerD3DTextureNV12(
mConsumerType, attributes);
mProducerType = ProducerType::D3D11TextureNV12;
mState = EGL_STREAM_STATE_EMPTY_KHR;
return Error(EGL_SUCCESS);
}
+
// Called when the consumer of this stream starts using the stream
Error Stream::consumerAcquire()
{
ASSERT(mState == EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR ||
mState == EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR);
ASSERT(mConsumerType == ConsumerType::GLTextureRGB ||
mConsumerType == ConsumerType::GLTextureYUV);
ASSERT(mProducerType == ProducerType::D3D11TextureNV12);
@@ -221,24 +222,24 @@ Error Stream::consumerRelease()
}
bool Stream::isConsumerBoundToContext(const gl::Context *context) const
{
ASSERT(context != nullptr);
return (context == mContext);
}
-Error Stream::validateD3D11NV12Texture(void *texture) const
+Error Stream::validateD3D11NV12Texture(void *texture, const AttributeMap &attributes) const
{
ASSERT(mConsumerType == ConsumerType::GLTextureRGB ||
mConsumerType == ConsumerType::GLTextureYUV);
ASSERT(mProducerType == ProducerType::D3D11TextureNV12);
ASSERT(mProducerImplementation != nullptr);
- return mProducerImplementation->validateD3DNV12Texture(texture);
+ return mProducerImplementation->validateD3DNV12Texture(texture, attributes);
}
Error Stream::postD3D11NV12Texture(void *texture, const AttributeMap &attributes)
{
ASSERT(mConsumerType == ConsumerType::GLTextureRGB ||
mConsumerType == ConsumerType::GLTextureYUV);
ASSERT(mProducerType == ProducerType::D3D11TextureNV12);
--- a/gfx/angle/src/libANGLE/Stream.h
+++ b/gfx/angle/src/libANGLE/Stream.h
@@ -90,17 +90,17 @@ class Stream final : angle::NonCopyable
Error consumerAcquire();
Error consumerRelease();
// Some consumers are bound to GL contexts. This validates that a given context is bound to the
// stream's consumer
bool isConsumerBoundToContext(const gl::Context *context) const;
// Producer methods
- Error validateD3D11NV12Texture(void *texture) const;
+ Error validateD3D11NV12Texture(void *texture, const AttributeMap &attributes) const;
Error postD3D11NV12Texture(void *texture, const AttributeMap &attributes);
private:
// Associated display
Display *mDisplay;
// Producer Implementation
rx::StreamProducerImpl *mProducerImplementation;
--- a/gfx/angle/src/libANGLE/renderer/StreamProducerImpl.h
+++ b/gfx/angle/src/libANGLE/renderer/StreamProducerImpl.h
@@ -18,17 +18,17 @@ namespace rx
class StreamProducerImpl : angle::NonCopyable
{
public:
explicit StreamProducerImpl() {}
virtual ~StreamProducerImpl() {}
// Validates the ability for the producer to accept an arbitrary pointer to a frame. All
// pointers should be validated through this function before being used to produce a frame.
- virtual egl::Error validateD3DNV12Texture(void *pointer) const = 0;
+ virtual egl::Error validateD3DNV12Texture(void *pointer, const egl::AttributeMap &attributes) const = 0;
// Constructs a frame from an arbitrary external pointer that points to producer specific frame
// data. Replaces the internal frame with the new one.
virtual void postD3DNV12Texture(void *pointer, const egl::AttributeMap &attributes) = 0;
// Returns an OpenGL texture interpretation of some frame attributes for the purpose of
// constructing an OpenGL texture from a frame. Depending on the producer and consumer, some
// frames may have multiple "planes" with different OpenGL texture representations.
--- a/gfx/angle/src/libANGLE/renderer/d3d/d3d11/StreamProducerNV12.cpp
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d11/StreamProducerNV12.cpp
@@ -10,88 +10,129 @@
#include "common/utilities.h"
#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
namespace rx
{
+static egl::Stream::GLTextureDescription getGLDescFromTex(ID3D11Texture2D* tex,
+ UINT planeIndex)
+{
+ egl::Stream::GLTextureDescription ret = { 0 };
+ if (!tex)
+ return ret;
+
+ D3D11_TEXTURE2D_DESC desc;
+ tex->GetDesc(&desc);
+
+ ret.width = desc.Width;
+ ret.height = desc.Height;
+ ret.mipLevels = 0;
+
+ if (desc.Width < 1 || desc.Height < 1) {
+ return ret;
+ }
+
+ UINT maxPlaneIndex = 0;
+ switch (desc.Format) {
+ case DXGI_FORMAT_NV12:
+ // The UV plane of NV12 textures has half the width/height of the Y plane.
+ if ((desc.Width % 2) != 0 || (desc.Height % 2) != 0)
+ {
+ break; // Bad width/height.
+ }
+ maxPlaneIndex = 1;
+ if (planeIndex == 0)
+ {
+ ret.internalFormat = GL_R8;
+ }
+ else
+ {
+ ret.internalFormat = GL_RG8;
+ ret.width /= 2;
+ ret.height /= 2;
+ }
+ break;
+
+ case DXGI_FORMAT_R8_UNORM:
+ ret.internalFormat = GL_R8;
+ break;
+ case DXGI_FORMAT_R8G8_UNORM:
+ ret.internalFormat = GL_RG8;
+ break;
+ case DXGI_FORMAT_R8G8B8A8_UNORM:
+ ret.internalFormat = GL_RGBA8;
+ break;
+
+ default:
+ ret.internalFormat = 0;
+ break;
+ }
+
+ if (planeIndex > maxPlaneIndex)
+ {
+ // Just kidding, there's no plane out there.
+ ret.internalFormat = 0;
+ }
+
+ return ret;
+}
+
+
StreamProducerNV12::StreamProducerNV12(Renderer11 *renderer)
- : mRenderer(renderer), mTexture(nullptr), mArraySlice(0), mTextureWidth(0), mTextureHeight(0)
+ : mRenderer(renderer), mTexture(nullptr), mArraySlice(0), mPlaneOffset(0)
{
}
StreamProducerNV12::~StreamProducerNV12()
{
SafeRelease(mTexture);
}
-egl::Error StreamProducerNV12::validateD3DNV12Texture(void *pointer) const
+egl::Error StreamProducerNV12::validateD3DNV12Texture(void *pointer, const egl::AttributeMap &attributes) const
{
ID3D11Texture2D *textureD3D = static_cast<ID3D11Texture2D *>(pointer);
// Check that the texture originated from our device
ID3D11Device *device;
textureD3D->GetDevice(&device);
if (device != mRenderer->getDevice())
{
return egl::Error(EGL_BAD_PARAMETER, "Texture not created on ANGLE D3D device");
}
- // Get the description and validate it
- D3D11_TEXTURE2D_DESC desc;
- textureD3D->GetDesc(&desc);
- if (desc.Format != DXGI_FORMAT_NV12)
+ const auto planeId = static_cast<UINT>(attributes.get(EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG, 0));
+ const auto glDesc = getGLDescFromTex(textureD3D, planeId);
+ if (!glDesc.internalFormat)
{
- return egl::Error(EGL_BAD_PARAMETER, "Texture format not DXGI_FORMAT_NV12");
+ return egl::Error(EGL_BAD_PARAMETER, "Unsupported texture format or plane");
}
- if (desc.Width < 1 || desc.Height < 1)
- {
- return egl::Error(EGL_BAD_PARAMETER, "Texture is of size 0");
- }
- if ((desc.Width % 2) != 0 || (desc.Height % 2) != 0)
- {
- return egl::Error(EGL_BAD_PARAMETER, "Texture dimensions are not even");
- }
+
return egl::Error(EGL_SUCCESS);
}
void StreamProducerNV12::postD3DNV12Texture(void *pointer, const egl::AttributeMap &attributes)
{
ASSERT(pointer != nullptr);
ID3D11Texture2D *textureD3D = static_cast<ID3D11Texture2D *>(pointer);
- // Check that the texture originated from our device
- ID3D11Device *device;
- textureD3D->GetDevice(&device);
-
- // Get the description
- D3D11_TEXTURE2D_DESC desc;
- textureD3D->GetDesc(&desc);
-
// Release the previous texture if there is one
SafeRelease(mTexture);
mTexture = textureD3D;
mTexture->AddRef();
- mTextureWidth = desc.Width;
- mTextureHeight = desc.Height;
- mArraySlice = static_cast<UINT>(attributes.get(EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE, 0));
+ mPlaneOffset = static_cast<UINT>(attributes.get(EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG, 0));
+ mArraySlice = static_cast<UINT>(attributes.get(EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE, 0));
}
egl::Stream::GLTextureDescription StreamProducerNV12::getGLFrameDescription(int planeIndex)
{
- // The UV plane of NV12 textures has half the width/height of the Y plane
- egl::Stream::GLTextureDescription desc;
- desc.width = (planeIndex == 0) ? mTextureWidth : (mTextureWidth / 2);
- desc.height = (planeIndex == 0) ? mTextureHeight : (mTextureHeight / 2);
- desc.internalFormat = (planeIndex == 0) ? GL_R8 : GL_RG8;
- desc.mipLevels = 0;
- return desc;
+ return getGLDescFromTex(mTexture, static_cast<UINT>(planeIndex + mPlaneOffset));
}
ID3D11Texture2D *StreamProducerNV12::getD3DTexture()
{
return mTexture;
}
UINT StreamProducerNV12::getArraySlice()
--- a/gfx/angle/src/libANGLE/renderer/d3d/d3d11/StreamProducerNV12.h
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d11/StreamProducerNV12.h
@@ -16,29 +16,28 @@ namespace rx
class Renderer11;
class StreamProducerNV12 : public StreamProducerImpl
{
public:
StreamProducerNV12(Renderer11 *renderer);
~StreamProducerNV12() override;
- egl::Error validateD3DNV12Texture(void *pointer) const override;
+ egl::Error validateD3DNV12Texture(void *pointer, const egl::AttributeMap &attributes) const override;
void postD3DNV12Texture(void *pointer, const egl::AttributeMap &attributes) override;
egl::Stream::GLTextureDescription getGLFrameDescription(int planeIndex) override;
// Gets a pointer to the internal D3D texture
ID3D11Texture2D *getD3DTexture();
// Gets the slice index for the D3D texture that the frame is in
UINT getArraySlice();
private:
Renderer11 *mRenderer;
ID3D11Texture2D *mTexture;
UINT mArraySlice;
- UINT mTextureWidth;
- UINT mTextureHeight;
+ UINT mPlaneOffset;
};
} // namespace rx
#endif // LIBANGLE_RENDERER_D3D_D3D11_STREAM11_H_
--- a/gfx/angle/src/libANGLE/validationEGL.cpp
+++ b/gfx/angle/src/libANGLE/validationEGL.cpp
@@ -1510,19 +1510,32 @@ Error ValidateCreateStreamProducerD3DTex
return Error(EGL_BAD_ATTRIBUTE, "Invalid attribute");
}
if (stream->getState() != EGL_STREAM_STATE_CONNECTING_KHR)
{
return Error(EGL_BAD_STATE_KHR, "Stream not in connecting state");
}
- if (stream->getConsumerType() != Stream::ConsumerType::GLTextureYUV ||
- stream->getPlaneCount() != 2)
- {
+ switch (stream->getConsumerType()) {
+ case Stream::ConsumerType::GLTextureYUV:
+ if (stream->getPlaneCount() != 2)
+ {
+ return Error(EGL_BAD_MATCH, "Incompatible stream consumer type");
+ }
+ break;
+
+ case Stream::ConsumerType::GLTextureRGB:
+ if (stream->getPlaneCount() != 1)
+ {
+ return Error(EGL_BAD_MATCH, "Incompatible stream consumer type");
+ }
+ break;
+
+ default:
return Error(EGL_BAD_MATCH, "Incompatible stream consumer type");
}
return Error(EGL_SUCCESS);
}
Error ValidateStreamPostD3DTextureNV12ANGLE(const Display *display,
const Stream *stream,
@@ -1547,16 +1560,22 @@ Error ValidateStreamPostD3DTextureNV12AN
switch (attribute)
{
case EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE:
if (value < 0)
{
return Error(EGL_BAD_PARAMETER, "Invalid subresource index");
}
break;
+ case EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG:
+ if (value < 0)
+ {
+ return Error(EGL_BAD_PARAMETER, "Invalid plane offset");
+ }
+ break;
default:
return Error(EGL_BAD_ATTRIBUTE, "Invalid attribute");
}
}
if (stream->getState() != EGL_STREAM_STATE_EMPTY_KHR &&
stream->getState() != EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR &&
stream->getState() != EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR)
@@ -1569,17 +1588,17 @@ Error ValidateStreamPostD3DTextureNV12AN
return Error(EGL_BAD_MATCH, "Incompatible stream producer");
}
if (texture == nullptr)
{
return egl::Error(EGL_BAD_PARAMETER, "Texture is null");
}
- return stream->validateD3D11NV12Texture(texture);
+ return stream->validateD3D11NV12Texture(texture, attribs);
}
Error ValidateSwapBuffersWithDamageEXT(const Display *display,
const Surface *surface,
EGLint *rects,
EGLint n_rects)
{
Error error = ValidateSurface(display, surface);