blob: 24fa9ff2c8e9b7b920f8eee7658d31a54213887b [file] [log] [blame]
//
// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// StreamProducerD3DTexture.cpp: Implements the stream producer for D3D11 textures
#include "libANGLE/renderer/d3d/d3d11/StreamProducerD3DTexture.h"
#include "common/utilities.h"
#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
#include <array>
namespace rx
{
namespace
{
egl::Error GetGLDescFromTex(ID3D11Texture2D *const tex,
const UINT planeIndex,
egl::Stream::GLTextureDescription *const out)
{
if (!tex)
return egl::EglBadParameter() << "Texture is null";
D3D11_TEXTURE2D_DESC desc;
tex->GetDesc(&desc);
if (desc.Width < 1 || desc.Height < 1)
return egl::EglBadParameter() << "Width or height < 1";
out->width = desc.Width;
out->height = desc.Height;
out->mipLevels = 0;
std::array<uint32_t, 2> planeFormats = {};
switch (desc.Format)
{
case DXGI_FORMAT_NV12:
planeFormats = {GL_R8, GL_RG8};
break;
case DXGI_FORMAT_P010:
case DXGI_FORMAT_P016:
planeFormats = {GL_R16_EXT, GL_RG16_EXT};
break;
case DXGI_FORMAT_R8_UNORM:
planeFormats = {GL_R8};
break;
case DXGI_FORMAT_R8G8_UNORM:
planeFormats[0] = GL_RG8;
break;
case DXGI_FORMAT_R8G8B8A8_UNORM:
planeFormats[0] = GL_RGBA8;
break;
case DXGI_FORMAT_B8G8R8A8_UNORM:
planeFormats[0] = GL_BGRA8_EXT;
break;
case DXGI_FORMAT_R16_UNORM:
planeFormats[0] = GL_R16_EXT;
break;
case DXGI_FORMAT_R16G16_UNORM:
planeFormats[0] = GL_RG16_EXT;
break;
case DXGI_FORMAT_R16G16B16A16_UNORM:
planeFormats[0] = GL_RGBA16_EXT;
break;
default:
return egl::EglBadParameter() << "Unsupported format";
}
if (planeFormats[1]) // If we have YUV planes, expect 4:2:0.
{
if ((desc.Width % 2) != 0 || (desc.Height % 2) != 0)
return egl::EglBadParameter() << "YUV 4:2:0 textures must have even width and height.";
}
if (planeIndex > 0)
{
out->width /= 2;
out->height /= 2;
}
out->internalFormat = 0;
if (planeIndex < planeFormats.size())
{
out->internalFormat = planeFormats[planeIndex];
}
if (!out->internalFormat)
return egl::EglBadParameter() << "Plane out of range";
return egl::NoError();
}
} // namespace
StreamProducerD3DTexture::StreamProducerD3DTexture(Renderer11 *renderer)
: mRenderer(renderer), mTexture(nullptr), mArraySlice(0), mPlaneOffset(0)
{}
StreamProducerD3DTexture::~StreamProducerD3DTexture()
{
SafeRelease(mTexture);
}
egl::Error StreamProducerD3DTexture::validateD3DTexture(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::EglBadParameter() << "Texture not created on ANGLE D3D device";
}
const auto planeId = static_cast<UINT>(attributes.get(EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG, 0));
egl::Stream::GLTextureDescription unused;
return GetGLDescFromTex(textureD3D, planeId, &unused);
}
void StreamProducerD3DTexture::postD3DTexture(void *pointer, const egl::AttributeMap &attributes)
{
ASSERT(pointer != nullptr);
ID3D11Texture2D *textureD3D = static_cast<ID3D11Texture2D *>(pointer);
// Release the previous texture if there is one
SafeRelease(mTexture);
mTexture = textureD3D;
mTexture->AddRef();
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 StreamProducerD3DTexture::getGLFrameDescription(int planeIndex)
{
const auto planeOffsetIndex = static_cast<UINT>(planeIndex + mPlaneOffset);
egl::Stream::GLTextureDescription ret;
ANGLE_SWALLOW_ERR(GetGLDescFromTex(mTexture, planeOffsetIndex, &ret));
return ret;
}
ID3D11Texture2D *StreamProducerD3DTexture::getD3DTexture()
{
return mTexture;
}
UINT StreamProducerD3DTexture::getArraySlice()
{
return mArraySlice;
}
} // namespace rx