1 //
2 // Copyright 2016 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 // StreamProducerD3DTexture.cpp: Implements the stream producer for D3D11 textures
8
9 #include "libANGLE/renderer/d3d/d3d11/StreamProducerD3DTexture.h"
10
11 #include "common/utilities.h"
12 #include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
13 #include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
14
15 #include <array>
16
17 namespace rx
18 {
19
20 namespace
21 {
22
GetGLDescFromTex(ID3D11Texture2D * const tex,const UINT planeIndex,egl::Stream::GLTextureDescription * const out)23 egl::Error GetGLDescFromTex(ID3D11Texture2D *const tex,
24 const UINT planeIndex,
25 egl::Stream::GLTextureDescription *const out)
26 {
27 if (!tex)
28 return egl::EglBadParameter() << "Texture is null";
29
30 D3D11_TEXTURE2D_DESC desc;
31 tex->GetDesc(&desc);
32
33 if (desc.Width < 1 || desc.Height < 1)
34 return egl::EglBadParameter() << "Width or height < 1";
35
36 out->width = desc.Width;
37 out->height = desc.Height;
38 out->mipLevels = 0;
39
40 std::array<uint32_t, 2> planeFormats = {};
41 switch (desc.Format)
42 {
43 case DXGI_FORMAT_NV12:
44 planeFormats = {GL_R8, GL_RG8};
45 break;
46
47 case DXGI_FORMAT_P010:
48 case DXGI_FORMAT_P016:
49 planeFormats = {GL_R16_EXT, GL_RG16_EXT};
50 break;
51
52 case DXGI_FORMAT_R8_UNORM:
53 planeFormats = {GL_R8};
54 break;
55 case DXGI_FORMAT_R8G8_UNORM:
56 planeFormats[0] = GL_RG8;
57 break;
58 case DXGI_FORMAT_R8G8B8A8_UNORM:
59 planeFormats[0] = GL_RGBA8;
60 break;
61 case DXGI_FORMAT_B8G8R8A8_UNORM:
62 planeFormats[0] = GL_BGRA8_EXT;
63 break;
64
65 case DXGI_FORMAT_R16_UNORM:
66 planeFormats[0] = GL_R16_EXT;
67 break;
68 case DXGI_FORMAT_R16G16_UNORM:
69 planeFormats[0] = GL_RG16_EXT;
70 break;
71 case DXGI_FORMAT_R16G16B16A16_UNORM:
72 planeFormats[0] = GL_RGBA16_EXT;
73 break;
74 case DXGI_FORMAT_R16G16B16A16_FLOAT:
75 planeFormats[0] = GL_RGBA16F;
76 break;
77
78 default:
79 return egl::EglBadParameter() << "Unsupported format";
80 }
81
82 if (planeFormats[1]) // If we have YUV planes, expect 4:2:0.
83 {
84 if ((desc.Width % 2) != 0 || (desc.Height % 2) != 0)
85 return egl::EglBadParameter() << "YUV 4:2:0 textures must have even width and height.";
86 }
87 if (planeIndex > 0)
88 {
89 out->width /= 2;
90 out->height /= 2;
91 }
92
93 out->internalFormat = 0;
94 if (planeIndex < planeFormats.size())
95 {
96 out->internalFormat = planeFormats[planeIndex];
97 }
98 if (!out->internalFormat)
99 return egl::EglBadParameter() << "Plane out of range";
100
101 return egl::NoError();
102 }
103
104 } // namespace
105
StreamProducerD3DTexture(Renderer11 * renderer)106 StreamProducerD3DTexture::StreamProducerD3DTexture(Renderer11 *renderer)
107 : mRenderer(renderer), mTexture(nullptr), mArraySlice(0), mPlaneOffset(0)
108 {}
109
~StreamProducerD3DTexture()110 StreamProducerD3DTexture::~StreamProducerD3DTexture()
111 {
112 SafeRelease(mTexture);
113 }
114
validateD3DTexture(const void * pointer,const egl::AttributeMap & attributes) const115 egl::Error StreamProducerD3DTexture::validateD3DTexture(const void *pointer,
116 const egl::AttributeMap &attributes) const
117 {
118 // We must remove the const qualifier because "GetDevice" and "GetDesc" are non-const in D3D11.
119 ID3D11Texture2D *textureD3D = static_cast<ID3D11Texture2D *>(const_cast<void *>(pointer));
120
121 // Check that the texture originated from our device
122 ID3D11Device *device;
123 textureD3D->GetDevice(&device);
124 if (device != mRenderer->getDevice())
125 {
126 return egl::EglBadParameter() << "Texture not created on ANGLE D3D device";
127 }
128
129 const auto planeId = static_cast<UINT>(attributes.get(EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG, 0));
130 egl::Stream::GLTextureDescription unused;
131 return GetGLDescFromTex(textureD3D, planeId, &unused);
132 }
133
postD3DTexture(void * pointer,const egl::AttributeMap & attributes)134 void StreamProducerD3DTexture::postD3DTexture(void *pointer, const egl::AttributeMap &attributes)
135 {
136 ASSERT(pointer != nullptr);
137 ID3D11Texture2D *textureD3D = static_cast<ID3D11Texture2D *>(pointer);
138
139 // Release the previous texture if there is one
140 SafeRelease(mTexture);
141
142 mTexture = textureD3D;
143 mTexture->AddRef();
144 mPlaneOffset = static_cast<UINT>(attributes.get(EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG, 0));
145 mArraySlice = static_cast<UINT>(attributes.get(EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE, 0));
146 }
147
getGLFrameDescription(int planeIndex)148 egl::Stream::GLTextureDescription StreamProducerD3DTexture::getGLFrameDescription(int planeIndex)
149 {
150 const auto planeOffsetIndex = static_cast<UINT>(planeIndex + mPlaneOffset);
151 egl::Stream::GLTextureDescription ret;
152 ANGLE_SWALLOW_ERR(GetGLDescFromTex(mTexture, planeOffsetIndex, &ret));
153 return ret;
154 }
155
getD3DTexture()156 ID3D11Texture2D *StreamProducerD3DTexture::getD3DTexture()
157 {
158 return mTexture;
159 }
160
getArraySlice()161 UINT StreamProducerD3DTexture::getArraySlice()
162 {
163 return mArraySlice;
164 }
165
166 } // namespace rx
167