Imported Upstream version 2.81
[platform/upstream/libbullet.git] / src / BulletMultiThreaded / GpuSoftBodySolvers / DX11 / btSoftBodySolverBuffer_DX11.h
1 /*\r
2 Bullet Continuous Collision Detection and Physics Library\r
3 Copyright (c) 2003-2006 Erwin Coumans  http://continuousphysics.com/Bullet/\r
4 \r
5 This software is provided 'as-is', without any express or implied warranty.\r
6 In no event will the authors be held liable for any damages arising from the use of this software.\r
7 Permission is granted to anyone to use this software for any purpose, \r
8 including commercial applications, and to alter it and redistribute it freely, \r
9 subject to the following restrictions:\r
10 \r
11 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.\r
12 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.\r
13 3. This notice may not be removed or altered from any source distribution.\r
14 */\r
15 #ifndef BT_SOFT_BODY_SOLVER_BUFFER_DX11_H\r
16 #define BT_SOFT_BODY_SOLVER_BUFFER_DX11_H\r
17 \r
18 // DX11 support\r
19 #include <windows.h>\r
20 #include <crtdbg.h>\r
21 #include <d3d11.h>\r
22 #include <d3dx11.h>\r
23 #include <d3dcompiler.h>\r
24 \r
25 #ifndef SAFE_RELEASE\r
26 #define SAFE_RELEASE(p)      { if(p) { (p)->Release(); (p)=NULL; } }\r
27 #endif\r
28 \r
29 /**\r
30  * DX11 Buffer that tracks a host buffer on use to ensure size-correctness.\r
31  */\r
32 template <typename ElementType> class btDX11Buffer\r
33 {\r
34 protected:\r
35         ID3D11Device*                           m_d3dDevice;\r
36         ID3D11DeviceContext*            m_d3dDeviceContext;\r
37 \r
38         ID3D11Buffer*               m_Buffer;\r
39         ID3D11ShaderResourceView*   m_SRV;\r
40         ID3D11UnorderedAccessView*  m_UAV;\r
41         btAlignedObjectArray< ElementType >*    m_CPUBuffer;\r
42 \r
43         // TODO: Separate this from the main class\r
44         // as read back buffers can be shared between buffers\r
45         ID3D11Buffer*               m_readBackBuffer;\r
46 \r
47         int m_gpuSize;\r
48         bool m_onGPU;\r
49 \r
50         bool m_readOnlyOnGPU;\r
51         \r
52         bool createBuffer( ID3D11Buffer *preexistingBuffer = 0)\r
53         {\r
54                 HRESULT hr = S_OK;\r
55 \r
56                 // Create all CS buffers\r
57                 if( preexistingBuffer )\r
58                 {\r
59                         m_Buffer = preexistingBuffer;\r
60                 } else {\r
61                         D3D11_BUFFER_DESC buffer_desc;\r
62                         ZeroMemory(&buffer_desc, sizeof(buffer_desc));          \r
63                         buffer_desc.Usage = D3D11_USAGE_DEFAULT;\r
64                         if( m_readOnlyOnGPU )\r
65                                 buffer_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;\r
66                         else\r
67                                 buffer_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS;\r
68                         buffer_desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;\r
69                         \r
70                         buffer_desc.ByteWidth = m_CPUBuffer->size() * sizeof(ElementType);\r
71                         // At a minimum the buffer must exist\r
72                         if( buffer_desc.ByteWidth == 0 )\r
73                                 buffer_desc.ByteWidth = sizeof(ElementType);\r
74                         buffer_desc.StructureByteStride = sizeof(ElementType);\r
75                         hr = m_d3dDevice->CreateBuffer(&buffer_desc, NULL, &m_Buffer);\r
76                         if( FAILED( hr ) )\r
77                         return (hr==S_OK);\r
78                 } \r
79 \r
80                 if( m_readOnlyOnGPU )\r
81                 {\r
82                         D3D11_SHADER_RESOURCE_VIEW_DESC srvbuffer_desc;\r
83                         ZeroMemory(&srvbuffer_desc, sizeof(srvbuffer_desc));\r
84                         srvbuffer_desc.Format = DXGI_FORMAT_UNKNOWN;\r
85                         srvbuffer_desc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;\r
86 \r
87                         srvbuffer_desc.Buffer.ElementWidth = m_CPUBuffer->size();\r
88                         if( srvbuffer_desc.Buffer.ElementWidth == 0 )\r
89                                 srvbuffer_desc.Buffer.ElementWidth = 1;\r
90                         hr = m_d3dDevice->CreateShaderResourceView(m_Buffer, &srvbuffer_desc, &m_SRV);\r
91                         if( FAILED( hr ) )\r
92                                 return (hr==S_OK);\r
93                 } else {\r
94                         // Create SRV\r
95                         D3D11_SHADER_RESOURCE_VIEW_DESC srvbuffer_desc;\r
96                         ZeroMemory(&srvbuffer_desc, sizeof(srvbuffer_desc));\r
97                         srvbuffer_desc.Format = DXGI_FORMAT_UNKNOWN;\r
98                         srvbuffer_desc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;\r
99 \r
100                         srvbuffer_desc.Buffer.ElementWidth = m_CPUBuffer->size();\r
101                         if( srvbuffer_desc.Buffer.ElementWidth == 0 )\r
102                                 srvbuffer_desc.Buffer.ElementWidth = 1;\r
103                         hr = m_d3dDevice->CreateShaderResourceView(m_Buffer, &srvbuffer_desc, &m_SRV);\r
104                         if( FAILED( hr ) )\r
105                                 return (hr==S_OK);\r
106 \r
107                         // Create UAV\r
108                         D3D11_UNORDERED_ACCESS_VIEW_DESC uavbuffer_desc;\r
109                         ZeroMemory(&uavbuffer_desc, sizeof(uavbuffer_desc));\r
110                         uavbuffer_desc.Format = DXGI_FORMAT_UNKNOWN;\r
111                         uavbuffer_desc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;\r
112 \r
113                         uavbuffer_desc.Buffer.NumElements = m_CPUBuffer->size();\r
114                         if( uavbuffer_desc.Buffer.NumElements == 0 )\r
115                                 uavbuffer_desc.Buffer.NumElements = 1;\r
116                         hr = m_d3dDevice->CreateUnorderedAccessView(m_Buffer, &uavbuffer_desc, &m_UAV);\r
117                         if( FAILED( hr ) )\r
118                                 return (hr==S_OK);\r
119 \r
120                         // Create read back buffer\r
121                         D3D11_BUFFER_DESC readback_buffer_desc;\r
122                         ZeroMemory(&readback_buffer_desc, sizeof(readback_buffer_desc));\r
123 \r
124                         readback_buffer_desc.ByteWidth = m_CPUBuffer->size() * sizeof(ElementType);\r
125                         readback_buffer_desc.Usage = D3D11_USAGE_STAGING;\r
126                         readback_buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;\r
127                         readback_buffer_desc.StructureByteStride = sizeof(ElementType);\r
128                         hr = m_d3dDevice->CreateBuffer(&readback_buffer_desc, NULL, &m_readBackBuffer);\r
129                         if( FAILED( hr ) )\r
130                                 return (hr==S_OK);\r
131                 }\r
132 \r
133                 m_gpuSize = m_CPUBuffer->size();\r
134                 return true;\r
135         }\r
136 \r
137 \r
138 \r
139 public:\r
140         btDX11Buffer( ID3D11Device *d3dDevice, ID3D11DeviceContext *d3dDeviceContext, btAlignedObjectArray< ElementType > *CPUBuffer, bool readOnly )\r
141         {\r
142                 m_d3dDevice = d3dDevice;\r
143                 m_d3dDeviceContext = d3dDeviceContext;\r
144                 m_Buffer = 0;\r
145                 m_SRV = 0;\r
146                 m_UAV = 0;\r
147                 m_readBackBuffer = 0;\r
148 \r
149                 m_CPUBuffer = CPUBuffer;\r
150 \r
151                 m_gpuSize = 0;\r
152                 m_onGPU = false;\r
153 \r
154                 m_readOnlyOnGPU = readOnly;\r
155         }\r
156 \r
157         virtual ~btDX11Buffer()\r
158         {\r
159                 SAFE_RELEASE(m_Buffer);\r
160                 SAFE_RELEASE(m_SRV);\r
161                 SAFE_RELEASE(m_UAV);\r
162                 SAFE_RELEASE(m_readBackBuffer);\r
163         }\r
164 \r
165         ID3D11ShaderResourceView* &getSRV()\r
166         {\r
167                 return m_SRV;\r
168         }\r
169 \r
170         ID3D11UnorderedAccessView* &getUAV()\r
171         {\r
172                 return m_UAV;\r
173         }\r
174 \r
175         ID3D11Buffer* &getBuffer()\r
176         {\r
177                 return m_Buffer;\r
178         }\r
179 \r
180         /**\r
181          * Move the data to the GPU if it is not there already.\r
182          */\r
183         bool moveToGPU()\r
184         {\r
185                 // Reallocate if GPU size is too small\r
186                 if( (m_CPUBuffer->size() > m_gpuSize ) )\r
187                         m_onGPU = false;\r
188                 if( !m_onGPU && m_CPUBuffer->size() > 0 )\r
189                 {\r
190                         // If the buffer doesn't exist or the CPU-side buffer has changed size, create\r
191                         // We should really delete the old one, too, but let's leave that for later\r
192                         if( !m_Buffer || (m_CPUBuffer->size() != m_gpuSize) )\r
193                         {\r
194                                 SAFE_RELEASE(m_Buffer);\r
195                                 SAFE_RELEASE(m_SRV);\r
196                                 SAFE_RELEASE(m_UAV);\r
197                                 SAFE_RELEASE(m_readBackBuffer);\r
198                                 if( !createBuffer() )\r
199                                 {\r
200                                         btAssert("Buffer creation failed.");\r
201                                         return false;\r
202                                 }\r
203                         }\r
204 \r
205                         if( m_gpuSize > 0 )\r
206                         {\r
207                                 D3D11_BOX destRegion;\r
208                                 destRegion.left = 0;\r
209                                 destRegion.front = 0;\r
210                                 destRegion.top = 0;\r
211                                 destRegion.bottom = 1;\r
212                                 destRegion.back = 1;\r
213                                 destRegion.right = (m_CPUBuffer->size())*sizeof(ElementType);\r
214                                 m_d3dDeviceContext->UpdateSubresource(m_Buffer, 0, &destRegion, &((*m_CPUBuffer)[0]), 0, 0);\r
215 \r
216                                 m_onGPU = true;\r
217                         }\r
218 \r
219                 }\r
220 \r
221                 return true;\r
222         }\r
223 \r
224         /**\r
225          * Move the data back from the GPU if it is on there and isn't read only.\r
226          */\r
227         bool moveFromGPU()\r
228         {\r
229                 if( m_CPUBuffer->size() > 0 )\r
230                 {\r
231                         if( m_onGPU && !m_readOnlyOnGPU )\r
232                         {\r
233                                 // Copy back\r
234                                 D3D11_MAPPED_SUBRESOURCE MappedResource = {0}; \r
235                                 //m_pd3dImmediateContext->CopyResource(m_phAngVelReadBackBuffer, m_phAngVel);\r
236 \r
237                                 D3D11_BOX destRegion;   \r
238                                 destRegion.left = 0;\r
239                                 destRegion.front = 0;\r
240                                 destRegion.top = 0;\r
241                                 destRegion.bottom = 1;\r
242                                 destRegion.back = 1;\r
243 \r
244                                 destRegion.right = (m_CPUBuffer->size())*sizeof(ElementType);\r
245                                 m_d3dDeviceContext->CopySubresourceRegion(\r
246                                         m_readBackBuffer,\r
247                                         0,\r
248                                         0,\r
249                                         0,\r
250                                         0 ,\r
251                                         m_Buffer,\r
252                                         0,\r
253                                         &destRegion\r
254                                         );\r
255 \r
256                                 m_d3dDeviceContext->Map(m_readBackBuffer, 0, D3D11_MAP_READ, 0, &MappedResource);   \r
257                                 //memcpy(m_hAngVel, MappedResource.pData, (m_maxObjs * sizeof(float) ));\r
258                                 memcpy(&((*m_CPUBuffer)[0]), MappedResource.pData, ((m_CPUBuffer->size()) * sizeof(ElementType) ));             \r
259                                 m_d3dDeviceContext->Unmap(m_readBackBuffer, 0);\r
260 \r
261                                 m_onGPU = false;\r
262                         }\r
263                 }\r
264 \r
265                 return true;\r
266         }\r
267 \r
268 \r
269         /**\r
270          * Copy the data back from the GPU without changing its state to be CPU-side.\r
271          * Useful if we just want to view it on the host for visualization.\r
272          */\r
273         bool copyFromGPU()\r
274         {\r
275                 if( m_CPUBuffer->size() > 0 )\r
276                 {\r
277                         if( m_onGPU && !m_readOnlyOnGPU )\r
278                         {\r
279                                 // Copy back\r
280                                 D3D11_MAPPED_SUBRESOURCE MappedResource = {0}; \r
281 \r
282                                 D3D11_BOX destRegion;   \r
283                                 destRegion.left = 0;\r
284                                 destRegion.front = 0;\r
285                                 destRegion.top = 0;\r
286                                 destRegion.bottom = 1;\r
287                                 destRegion.back = 1;\r
288 \r
289                                 destRegion.right = (m_CPUBuffer->size())*sizeof(ElementType);\r
290                                 m_d3dDeviceContext->CopySubresourceRegion(\r
291                                         m_readBackBuffer,\r
292                                         0,\r
293                                         0,\r
294                                         0,\r
295                                         0 ,\r
296                                         m_Buffer,\r
297                                         0,\r
298                                         &destRegion\r
299                                         );\r
300 \r
301                                 m_d3dDeviceContext->Map(m_readBackBuffer, 0, D3D11_MAP_READ, 0, &MappedResource);   \r
302                                 //memcpy(m_hAngVel, MappedResource.pData, (m_maxObjs * sizeof(float) ));\r
303                                 memcpy(&((*m_CPUBuffer)[0]), MappedResource.pData, ((m_CPUBuffer->size()) * sizeof(ElementType) ));             \r
304                                 m_d3dDeviceContext->Unmap(m_readBackBuffer, 0);\r
305                         }\r
306                 }\r
307 \r
308                 return true;\r
309         }\r
310 \r
311         /**\r
312          * Call if data has changed on the CPU.\r
313          * Can then trigger a move to the GPU as necessary.\r
314          */\r
315         virtual void changedOnCPU()\r
316         {\r
317                 m_onGPU = false;\r
318         }\r
319 }; // class btDX11Buffer\r
320 \r
321 \r
322 \r
323 #endif // #ifndef BT_SOFT_BODY_SOLVER_BUFFER_DX11_H