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::Error(EGL_BAD_PARAMETER, "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::Error(EGL_BAD_PARAMETER, "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::Error(EGL_BAD_PARAMETER, "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::Error(EGL_BAD_PARAMETER,
86 "YUV 4:2:0 textures must have even width and height.");
87 }
88 if (planeIndex > 0)
89 {
90 out->width /= 2;
91 out->height /= 2;
92 }
93
94 out->internalFormat = 0;
95 if (planeIndex < planeFormats.size())
96 {
97 out->internalFormat = planeFormats[planeIndex];
98 }
99 if (!out->internalFormat)
100 return egl::Error(EGL_BAD_PARAMETER, "Plane out of range");
101
102 return egl::NoError();
103 }
104
105 } // namespace
106
StreamProducerD3DTexture(Renderer11 * renderer)107 StreamProducerD3DTexture::StreamProducerD3DTexture(Renderer11 *renderer)
108 : mRenderer(renderer), mTexture(nullptr), mArraySlice(0), mPlaneOffset(0)
109 {}
110
~StreamProducerD3DTexture()111 StreamProducerD3DTexture::~StreamProducerD3DTexture()
112 {
113 SafeRelease(mTexture);
114 }
115
validateD3DTexture(const void * pointer,const egl::AttributeMap & attributes) const116 egl::Error StreamProducerD3DTexture::validateD3DTexture(const void *pointer,
117 const egl::AttributeMap &attributes) const
118 {
119 // We must remove the const qualifier because "GetDevice" and "GetDesc" are non-const in D3D11.
120 ID3D11Texture2D *textureD3D = static_cast<ID3D11Texture2D *>(const_cast<void *>(pointer));
121
122 // Check that the texture originated from our device
123 angle::ComPtr<ID3D11Device> device;
124 textureD3D->GetDevice(&device);
125 if (device.Get() != mRenderer->getDevice())
126 {
127 return egl::Error(EGL_BAD_PARAMETER, "Texture not created on ANGLE D3D device");
128 }
129
130 const auto planeId = static_cast<UINT>(attributes.get(EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG, 0));
131 egl::Stream::GLTextureDescription unused;
132 return GetGLDescFromTex(textureD3D, planeId, &unused);
133 }
134
postD3DTexture(void * pointer,const egl::AttributeMap & attributes)135 void StreamProducerD3DTexture::postD3DTexture(void *pointer, const egl::AttributeMap &attributes)
136 {
137 ASSERT(pointer != nullptr);
138 ID3D11Texture2D *textureD3D = static_cast<ID3D11Texture2D *>(pointer);
139
140 // Release the previous texture if there is one
141 SafeRelease(mTexture);
142
143 mTexture = textureD3D;
144 mTexture->AddRef();
145 mPlaneOffset = static_cast<UINT>(attributes.get(EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG, 0));
146 mArraySlice = static_cast<UINT>(attributes.get(EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE, 0));
147 }
148
getGLFrameDescription(int planeIndex)149 egl::Stream::GLTextureDescription StreamProducerD3DTexture::getGLFrameDescription(int planeIndex)
150 {
151 const auto planeOffsetIndex = static_cast<UINT>(planeIndex + mPlaneOffset);
152 egl::Stream::GLTextureDescription ret;
153 ANGLE_SWALLOW_ERR(GetGLDescFromTex(mTexture, planeOffsetIndex, &ret));
154 return ret;
155 }
156
getD3DTexture()157 ID3D11Texture2D *StreamProducerD3DTexture::getD3DTexture()
158 {
159 return mTexture;
160 }
161
getArraySlice()162 UINT StreamProducerD3DTexture::getArraySlice()
163 {
164 return mArraySlice;
165 }
166
167 } // namespace rx
168