1 //
2 // Copyright 2013 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 // PixelTransfer11.cpp:
8 //   Implementation for buffer-to-texture and texture-to-buffer copies.
9 //   Used to implement pixel transfers from unpack and to pack buffers.
10 //
11 
12 #include "libANGLE/renderer/d3d/d3d11/PixelTransfer11.h"
13 
14 #include "libANGLE/Buffer.h"
15 #include "libANGLE/Context.h"
16 #include "libANGLE/Texture.h"
17 #include "libANGLE/formatutils.h"
18 #include "libANGLE/renderer/d3d/d3d11/Buffer11.h"
19 #include "libANGLE/renderer/d3d/d3d11/Context11.h"
20 #include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h"
21 #include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
22 #include "libANGLE/renderer/d3d/d3d11/TextureStorage11.h"
23 #include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
24 #include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
25 #include "libANGLE/renderer/d3d/d3d11/texture_format_table.h"
26 #include "libANGLE/renderer/serial_utils.h"
27 
28 // Precompiled shaders
29 #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/buffertotexture11_gs.h"
30 #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/buffertotexture11_ps_4f.h"
31 #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/buffertotexture11_ps_4i.h"
32 #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/buffertotexture11_ps_4ui.h"
33 #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/buffertotexture11_vs.h"
34 
35 namespace rx
36 {
37 
PixelTransfer11(Renderer11 * renderer)38 PixelTransfer11::PixelTransfer11(Renderer11 *renderer)
39     : mRenderer(renderer),
40       mResourcesLoaded(false),
41       mBufferToTextureVS(),
42       mBufferToTextureGS(),
43       mParamsConstantBuffer(),
44       mCopyRasterizerState(),
45       mCopyDepthStencilState()
46 {}
47 
~PixelTransfer11()48 PixelTransfer11::~PixelTransfer11() {}
49 
loadResources(const gl::Context * context)50 angle::Result PixelTransfer11::loadResources(const gl::Context *context)
51 {
52     if (mResourcesLoaded)
53     {
54         return angle::Result::Continue;
55     }
56 
57     D3D11_RASTERIZER_DESC rasterDesc;
58     rasterDesc.FillMode              = D3D11_FILL_SOLID;
59     rasterDesc.CullMode              = D3D11_CULL_NONE;
60     rasterDesc.FrontCounterClockwise = FALSE;
61     rasterDesc.DepthBias             = 0;
62     rasterDesc.SlopeScaledDepthBias  = 0.0f;
63     rasterDesc.DepthBiasClamp        = 0.0f;
64     rasterDesc.DepthClipEnable       = TRUE;
65     rasterDesc.ScissorEnable         = FALSE;
66     rasterDesc.MultisampleEnable     = FALSE;
67     rasterDesc.AntialiasedLineEnable = FALSE;
68 
69     Context11 *context11 = GetImplAs<Context11>(context);
70 
71     ANGLE_TRY(mRenderer->allocateResource(context11, rasterDesc, &mCopyRasterizerState));
72 
73     D3D11_DEPTH_STENCIL_DESC depthStencilDesc;
74     depthStencilDesc.DepthEnable                  = true;
75     depthStencilDesc.DepthWriteMask               = D3D11_DEPTH_WRITE_MASK_ALL;
76     depthStencilDesc.DepthFunc                    = D3D11_COMPARISON_ALWAYS;
77     depthStencilDesc.StencilEnable                = FALSE;
78     depthStencilDesc.StencilReadMask              = D3D11_DEFAULT_STENCIL_READ_MASK;
79     depthStencilDesc.StencilWriteMask             = D3D11_DEFAULT_STENCIL_WRITE_MASK;
80     depthStencilDesc.FrontFace.StencilFailOp      = D3D11_STENCIL_OP_KEEP;
81     depthStencilDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
82     depthStencilDesc.FrontFace.StencilPassOp      = D3D11_STENCIL_OP_KEEP;
83     depthStencilDesc.FrontFace.StencilFunc        = D3D11_COMPARISON_ALWAYS;
84     depthStencilDesc.BackFace.StencilFailOp       = D3D11_STENCIL_OP_KEEP;
85     depthStencilDesc.BackFace.StencilDepthFailOp  = D3D11_STENCIL_OP_KEEP;
86     depthStencilDesc.BackFace.StencilPassOp       = D3D11_STENCIL_OP_KEEP;
87     depthStencilDesc.BackFace.StencilFunc         = D3D11_COMPARISON_ALWAYS;
88 
89     ANGLE_TRY(mRenderer->allocateResource(context11, depthStencilDesc, &mCopyDepthStencilState));
90 
91     D3D11_BUFFER_DESC constantBufferDesc   = {};
92     constantBufferDesc.ByteWidth           = roundUpPow2<UINT>(sizeof(CopyShaderParams), 32u);
93     constantBufferDesc.Usage               = D3D11_USAGE_DYNAMIC;
94     constantBufferDesc.BindFlags           = D3D11_BIND_CONSTANT_BUFFER;
95     constantBufferDesc.CPUAccessFlags      = D3D11_CPU_ACCESS_WRITE;
96     constantBufferDesc.MiscFlags           = 0;
97     constantBufferDesc.StructureByteStride = 0;
98 
99     ANGLE_TRY(mRenderer->allocateResource(context11, constantBufferDesc, &mParamsConstantBuffer));
100     mParamsConstantBuffer.setDebugName("PixelTransfer11 constant buffer");
101 
102     // init shaders
103     ANGLE_TRY(mRenderer->allocateResource(context11, ShaderData(g_VS_BufferToTexture),
104                                           &mBufferToTextureVS));
105     mBufferToTextureVS.setDebugName("BufferToTexture VS");
106 
107     ANGLE_TRY(mRenderer->allocateResource(context11, ShaderData(g_GS_BufferToTexture),
108                                           &mBufferToTextureGS));
109     mBufferToTextureGS.setDebugName("BufferToTexture GS");
110 
111     ANGLE_TRY(buildShaderMap(context));
112 
113     StructZero(&mParamsData);
114 
115     mResourcesLoaded = true;
116 
117     return angle::Result::Continue;
118 }
119 
setBufferToTextureCopyParams(const gl::Box & destArea,const gl::Extents & destSize,GLenum internalFormat,const gl::PixelUnpackState & unpack,unsigned int offset,CopyShaderParams * parametersOut)120 void PixelTransfer11::setBufferToTextureCopyParams(const gl::Box &destArea,
121                                                    const gl::Extents &destSize,
122                                                    GLenum internalFormat,
123                                                    const gl::PixelUnpackState &unpack,
124                                                    unsigned int offset,
125                                                    CopyShaderParams *parametersOut)
126 {
127     StructZero(parametersOut);
128 
129     float texelCenterX = 0.5f / static_cast<float>(destSize.width);
130     float texelCenterY = 0.5f / static_cast<float>(destSize.height);
131 
132     unsigned int bytesPerPixel  = gl::GetSizedInternalFormatInfo(internalFormat).pixelBytes;
133     unsigned int alignmentBytes = static_cast<unsigned int>(unpack.alignment);
134     unsigned int alignmentPixels =
135         (alignmentBytes <= bytesPerPixel ? 1 : alignmentBytes / bytesPerPixel);
136 
137     parametersOut->FirstPixelOffset = offset / bytesPerPixel;
138     parametersOut->PixelsPerRow =
139         static_cast<unsigned int>((unpack.rowLength > 0) ? unpack.rowLength : destArea.width);
140     parametersOut->RowStride    = roundUp(parametersOut->PixelsPerRow, alignmentPixels);
141     parametersOut->RowsPerSlice = static_cast<unsigned int>(destArea.height);
142     parametersOut->PositionOffset[0] =
143         texelCenterX + (destArea.x / float(destSize.width)) * 2.0f - 1.0f;
144     parametersOut->PositionOffset[1] =
145         texelCenterY + ((destSize.height - destArea.y - 1) / float(destSize.height)) * 2.0f - 1.0f;
146     parametersOut->PositionScale[0] = 2.0f / static_cast<float>(destSize.width);
147     parametersOut->PositionScale[1] = -2.0f / static_cast<float>(destSize.height);
148     parametersOut->FirstSlice       = destArea.z;
149 }
150 
copyBufferToTexture(const gl::Context * context,const gl::PixelUnpackState & unpack,gl::Buffer * unpackBuffer,unsigned int offset,RenderTargetD3D * destRenderTarget,GLenum destinationFormat,GLenum sourcePixelsType,const gl::Box & destArea)151 angle::Result PixelTransfer11::copyBufferToTexture(const gl::Context *context,
152                                                    const gl::PixelUnpackState &unpack,
153                                                    gl::Buffer *unpackBuffer,
154                                                    unsigned int offset,
155                                                    RenderTargetD3D *destRenderTarget,
156                                                    GLenum destinationFormat,
157                                                    GLenum sourcePixelsType,
158                                                    const gl::Box &destArea)
159 {
160     ASSERT(unpackBuffer);
161 
162     ANGLE_TRY(loadResources(context));
163 
164     gl::Extents destSize = destRenderTarget->getExtents();
165 
166     ASSERT(destArea.x >= 0 && destArea.x + destArea.width <= destSize.width && destArea.y >= 0 &&
167            destArea.y + destArea.height <= destSize.height && destArea.z >= 0 &&
168            destArea.z + destArea.depth <= destSize.depth);
169 
170     ASSERT(mRenderer->supportsFastCopyBufferToTexture(destinationFormat));
171 
172     const d3d11::PixelShader *pixelShader = findBufferToTexturePS(destinationFormat);
173     ASSERT(pixelShader);
174 
175     // The SRV must be in the proper read format, which may be different from the destination format
176     // EG: for half float data, we can load full precision floats with implicit conversion
177     GLenum unsizedFormat = gl::GetUnsizedFormat(destinationFormat);
178     const gl::InternalFormat &sourceglFormatInfo =
179         gl::GetInternalFormatInfo(unsizedFormat, sourcePixelsType);
180 
181     const d3d11::Format &sourceFormatInfo = d3d11::Format::Get(
182         sourceglFormatInfo.sizedInternalFormat, mRenderer->getRenderer11DeviceCaps());
183     DXGI_FORMAT srvFormat = sourceFormatInfo.srvFormat;
184     ASSERT(srvFormat != DXGI_FORMAT_UNKNOWN);
185     Buffer11 *bufferStorage11                  = GetAs<Buffer11>(unpackBuffer->getImplementation());
186     const d3d11::ShaderResourceView *bufferSRV = nullptr;
187     ANGLE_TRY(bufferStorage11->getSRV(context, srvFormat, &bufferSRV));
188     ASSERT(bufferSRV != nullptr);
189 
190     const d3d11::RenderTargetView &textureRTV =
191         GetAs<RenderTarget11>(destRenderTarget)->getRenderTargetView();
192     ASSERT(textureRTV.valid());
193 
194     CopyShaderParams shaderParams;
195     setBufferToTextureCopyParams(destArea, destSize, sourceglFormatInfo.sizedInternalFormat, unpack,
196                                  offset, &shaderParams);
197 
198     ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
199 
200     // Are we doing a 2D or 3D copy?
201     const auto *geometryShader   = ((destSize.depth > 1) ? &mBufferToTextureGS : nullptr);
202     StateManager11 *stateManager = mRenderer->getStateManager();
203 
204     stateManager->setDrawShaders(&mBufferToTextureVS, geometryShader, pixelShader);
205     stateManager->setShaderResource(gl::ShaderType::Fragment, 0, bufferSRV);
206     stateManager->setInputLayout(nullptr);
207     stateManager->setPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
208 
209     stateManager->setSingleVertexBuffer(nullptr, 0, 0);
210     stateManager->setSimpleBlendState(nullptr);
211     stateManager->setDepthStencilState(&mCopyDepthStencilState, 0xFFFFFFFF);
212     stateManager->setRasterizerState(&mCopyRasterizerState);
213 
214     stateManager->setRenderTarget(textureRTV.get(), nullptr);
215 
216     if (!StructEquals(mParamsData, shaderParams))
217     {
218         d3d11::SetBufferData(deviceContext, mParamsConstantBuffer.get(), shaderParams);
219         mParamsData = shaderParams;
220     }
221 
222     stateManager->setVertexConstantBuffer(0, &mParamsConstantBuffer);
223 
224     // Set the viewport
225     stateManager->setSimpleViewport(destSize);
226 
227     UINT numPixels = (destArea.width * destArea.height * destArea.depth);
228     deviceContext->Draw(numPixels, 0);
229 
230     return angle::Result::Continue;
231 }
232 
buildShaderMap(const gl::Context * context)233 angle::Result PixelTransfer11::buildShaderMap(const gl::Context *context)
234 {
235     d3d11::PixelShader bufferToTextureFloat;
236     d3d11::PixelShader bufferToTextureInt;
237     d3d11::PixelShader bufferToTextureUint;
238 
239     Context11 *context11 = GetImplAs<Context11>(context);
240 
241     ANGLE_TRY(mRenderer->allocateResource(context11, ShaderData(g_PS_BufferToTexture_4F),
242                                           &bufferToTextureFloat));
243     ANGLE_TRY(mRenderer->allocateResource(context11, ShaderData(g_PS_BufferToTexture_4I),
244                                           &bufferToTextureInt));
245     ANGLE_TRY(mRenderer->allocateResource(context11, ShaderData(g_PS_BufferToTexture_4UI),
246                                           &bufferToTextureUint));
247 
248     bufferToTextureFloat.setDebugName("BufferToTexture RGBA ps");
249     bufferToTextureInt.setDebugName("BufferToTexture RGBA-I ps");
250     bufferToTextureUint.setDebugName("BufferToTexture RGBA-UI ps");
251 
252     mBufferToTexturePSMap[GL_FLOAT]        = std::move(bufferToTextureFloat);
253     mBufferToTexturePSMap[GL_INT]          = std::move(bufferToTextureInt);
254     mBufferToTexturePSMap[GL_UNSIGNED_INT] = std::move(bufferToTextureUint);
255 
256     return angle::Result::Continue;
257 }
258 
findBufferToTexturePS(GLenum internalFormat) const259 const d3d11::PixelShader *PixelTransfer11::findBufferToTexturePS(GLenum internalFormat) const
260 {
261     GLenum componentType = gl::GetSizedInternalFormatInfo(internalFormat).componentType;
262     if (componentType == GL_SIGNED_NORMALIZED || componentType == GL_UNSIGNED_NORMALIZED)
263     {
264         componentType = GL_FLOAT;
265     }
266 
267     auto shaderMapIt = mBufferToTexturePSMap.find(componentType);
268     return (shaderMapIt == mBufferToTexturePSMap.end() ? nullptr : &shaderMapIt->second);
269 }
270 
271 }  // namespace rx
272