|
1 #include "precompiled.h" |
|
2 // |
|
3 // Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. |
|
4 // Use of this source code is governed by a BSD-style license that can be |
|
5 // found in the LICENSE file. |
|
6 // |
|
7 |
|
8 // BufferStorage11.cpp Defines the BufferStorage11 class. |
|
9 |
|
10 #include "libGLESv2/renderer/BufferStorage11.h" |
|
11 #include "libGLESv2/main.h" |
|
12 #include "libGLESv2/renderer/Renderer11.h" |
|
13 |
|
14 namespace rx |
|
15 { |
|
16 |
|
17 BufferStorage11::BufferStorage11(Renderer11 *renderer) |
|
18 { |
|
19 mRenderer = renderer; |
|
20 |
|
21 mStagingBuffer = NULL; |
|
22 mStagingBufferSize = 0; |
|
23 |
|
24 mBuffer = NULL; |
|
25 mBufferSize = 0; |
|
26 |
|
27 mSize = 0; |
|
28 |
|
29 mResolvedData = NULL; |
|
30 mResolvedDataSize = 0; |
|
31 mResolvedDataValid = false; |
|
32 |
|
33 mReadUsageCount = 0; |
|
34 mWriteUsageCount = 0; |
|
35 } |
|
36 |
|
37 BufferStorage11::~BufferStorage11() |
|
38 { |
|
39 if (mStagingBuffer) |
|
40 { |
|
41 mStagingBuffer->Release(); |
|
42 mStagingBuffer = NULL; |
|
43 } |
|
44 |
|
45 if (mBuffer) |
|
46 { |
|
47 mBuffer->Release(); |
|
48 mBuffer = NULL; |
|
49 } |
|
50 |
|
51 if (mResolvedData) |
|
52 { |
|
53 free(mResolvedData); |
|
54 mResolvedData = NULL; |
|
55 } |
|
56 } |
|
57 |
|
58 BufferStorage11 *BufferStorage11::makeBufferStorage11(BufferStorage *bufferStorage) |
|
59 { |
|
60 ASSERT(HAS_DYNAMIC_TYPE(BufferStorage11*, bufferStorage)); |
|
61 return static_cast<BufferStorage11*>(bufferStorage); |
|
62 } |
|
63 |
|
64 void *BufferStorage11::getData() |
|
65 { |
|
66 if (!mResolvedDataValid) |
|
67 { |
|
68 ID3D11Device *device = mRenderer->getDevice(); |
|
69 ID3D11DeviceContext *context = mRenderer->getDeviceContext(); |
|
70 HRESULT result; |
|
71 |
|
72 if (!mStagingBuffer || mStagingBufferSize < mBufferSize) |
|
73 { |
|
74 if (mStagingBuffer) |
|
75 { |
|
76 mStagingBuffer->Release(); |
|
77 mStagingBuffer = NULL; |
|
78 mStagingBufferSize = 0; |
|
79 } |
|
80 |
|
81 D3D11_BUFFER_DESC bufferDesc; |
|
82 bufferDesc.ByteWidth = mSize; |
|
83 bufferDesc.Usage = D3D11_USAGE_STAGING; |
|
84 bufferDesc.BindFlags = 0; |
|
85 bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; |
|
86 bufferDesc.MiscFlags = 0; |
|
87 bufferDesc.StructureByteStride = 0; |
|
88 |
|
89 result = device->CreateBuffer(&bufferDesc, NULL, &mStagingBuffer); |
|
90 if (FAILED(result)) |
|
91 { |
|
92 return gl::error(GL_OUT_OF_MEMORY, (void*)NULL); |
|
93 } |
|
94 |
|
95 mStagingBufferSize = bufferDesc.ByteWidth; |
|
96 } |
|
97 |
|
98 if (!mResolvedData || mResolvedDataSize < mBufferSize) |
|
99 { |
|
100 free(mResolvedData); |
|
101 mResolvedData = malloc(mSize); |
|
102 mResolvedDataSize = mSize; |
|
103 } |
|
104 |
|
105 D3D11_BOX srcBox; |
|
106 srcBox.left = 0; |
|
107 srcBox.right = mSize; |
|
108 srcBox.top = 0; |
|
109 srcBox.bottom = 1; |
|
110 srcBox.front = 0; |
|
111 srcBox.back = 1; |
|
112 |
|
113 context->CopySubresourceRegion(mStagingBuffer, 0, 0, 0, 0, mBuffer, 0, &srcBox); |
|
114 |
|
115 D3D11_MAPPED_SUBRESOURCE mappedResource; |
|
116 result = context->Map(mStagingBuffer, 0, D3D11_MAP_READ, 0, &mappedResource); |
|
117 if (FAILED(result)) |
|
118 { |
|
119 return gl::error(GL_OUT_OF_MEMORY, (void*)NULL); |
|
120 } |
|
121 |
|
122 memcpy(mResolvedData, mappedResource.pData, mSize); |
|
123 |
|
124 context->Unmap(mStagingBuffer, 0); |
|
125 |
|
126 mResolvedDataValid = true; |
|
127 } |
|
128 |
|
129 mReadUsageCount = 0; |
|
130 |
|
131 return mResolvedData; |
|
132 } |
|
133 |
|
134 void BufferStorage11::setData(const void* data, unsigned int size, unsigned int offset) |
|
135 { |
|
136 ID3D11Device *device = mRenderer->getDevice(); |
|
137 ID3D11DeviceContext *context = mRenderer->getDeviceContext(); |
|
138 HRESULT result; |
|
139 |
|
140 unsigned int requiredBufferSize = size + offset; |
|
141 unsigned int requiredStagingSize = size; |
|
142 bool directInitialization = offset == 0 && (!mBuffer || mBufferSize < size + offset); |
|
143 |
|
144 if (!directInitialization) |
|
145 { |
|
146 if (!mStagingBuffer || mStagingBufferSize < requiredStagingSize) |
|
147 { |
|
148 if (mStagingBuffer) |
|
149 { |
|
150 mStagingBuffer->Release(); |
|
151 mStagingBuffer = NULL; |
|
152 mStagingBufferSize = 0; |
|
153 } |
|
154 |
|
155 D3D11_BUFFER_DESC bufferDesc; |
|
156 bufferDesc.ByteWidth = size; |
|
157 bufferDesc.Usage = D3D11_USAGE_STAGING; |
|
158 bufferDesc.BindFlags = 0; |
|
159 bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; |
|
160 bufferDesc.MiscFlags = 0; |
|
161 bufferDesc.StructureByteStride = 0; |
|
162 |
|
163 if (data) |
|
164 { |
|
165 D3D11_SUBRESOURCE_DATA initialData; |
|
166 initialData.pSysMem = data; |
|
167 initialData.SysMemPitch = size; |
|
168 initialData.SysMemSlicePitch = 0; |
|
169 |
|
170 result = device->CreateBuffer(&bufferDesc, &initialData, &mStagingBuffer); |
|
171 } |
|
172 else |
|
173 { |
|
174 result = device->CreateBuffer(&bufferDesc, NULL, &mStagingBuffer); |
|
175 } |
|
176 |
|
177 if (FAILED(result)) |
|
178 { |
|
179 return gl::error(GL_OUT_OF_MEMORY); |
|
180 } |
|
181 |
|
182 mStagingBufferSize = size; |
|
183 } |
|
184 else if (data) |
|
185 { |
|
186 D3D11_MAPPED_SUBRESOURCE mappedResource; |
|
187 result = context->Map(mStagingBuffer, 0, D3D11_MAP_WRITE, 0, &mappedResource); |
|
188 if (FAILED(result)) |
|
189 { |
|
190 return gl::error(GL_OUT_OF_MEMORY); |
|
191 } |
|
192 |
|
193 memcpy(mappedResource.pData, data, size); |
|
194 |
|
195 context->Unmap(mStagingBuffer, 0); |
|
196 } |
|
197 } |
|
198 |
|
199 if (!mBuffer || mBufferSize < size + offset) |
|
200 { |
|
201 D3D11_BUFFER_DESC bufferDesc; |
|
202 bufferDesc.ByteWidth = requiredBufferSize; |
|
203 bufferDesc.Usage = D3D11_USAGE_DEFAULT; |
|
204 bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER | D3D11_BIND_INDEX_BUFFER; |
|
205 bufferDesc.CPUAccessFlags = 0; |
|
206 bufferDesc.MiscFlags = 0; |
|
207 bufferDesc.StructureByteStride = 0; |
|
208 |
|
209 if (directInitialization) |
|
210 { |
|
211 // Since the data will fill the entire buffer (being larger than the initial size and having |
|
212 // no offset), the buffer can be initialized with the data so no staging buffer is required |
|
213 |
|
214 // No longer need the old buffer |
|
215 if (mBuffer) |
|
216 { |
|
217 mBuffer->Release(); |
|
218 mBuffer = NULL; |
|
219 mBufferSize = 0; |
|
220 } |
|
221 |
|
222 if (data) |
|
223 { |
|
224 D3D11_SUBRESOURCE_DATA initialData; |
|
225 initialData.pSysMem = data; |
|
226 initialData.SysMemPitch = size; |
|
227 initialData.SysMemSlicePitch = 0; |
|
228 |
|
229 result = device->CreateBuffer(&bufferDesc, &initialData, &mBuffer); |
|
230 } |
|
231 else |
|
232 { |
|
233 result = device->CreateBuffer(&bufferDesc, NULL, &mBuffer); |
|
234 } |
|
235 |
|
236 if (FAILED(result)) |
|
237 { |
|
238 return gl::error(GL_OUT_OF_MEMORY); |
|
239 } |
|
240 } |
|
241 else if (mBuffer && offset > 0) |
|
242 { |
|
243 // If offset is greater than zero and the buffer is non-null, need to preserve the data from |
|
244 // the old buffer up to offset |
|
245 ID3D11Buffer *newBuffer = NULL; |
|
246 |
|
247 result = device->CreateBuffer(&bufferDesc, NULL, &newBuffer); |
|
248 if (FAILED(result)) |
|
249 { |
|
250 return gl::error(GL_OUT_OF_MEMORY); |
|
251 } |
|
252 |
|
253 D3D11_BOX srcBox; |
|
254 srcBox.left = 0; |
|
255 srcBox.right = std::min(offset, mBufferSize); |
|
256 srcBox.top = 0; |
|
257 srcBox.bottom = 1; |
|
258 srcBox.front = 0; |
|
259 srcBox.back = 1; |
|
260 |
|
261 context->CopySubresourceRegion(newBuffer, 0, 0, 0, 0, mBuffer, 0, &srcBox); |
|
262 |
|
263 mBuffer->Release(); |
|
264 mBuffer = newBuffer; |
|
265 } |
|
266 else |
|
267 { |
|
268 // Simple case, nothing needs to be copied from the old buffer to the new one, just create |
|
269 // a new buffer |
|
270 |
|
271 // No longer need the old buffer |
|
272 if (mBuffer) |
|
273 { |
|
274 mBuffer->Release(); |
|
275 mBuffer = NULL; |
|
276 mBufferSize = 0; |
|
277 } |
|
278 |
|
279 // Create a new buffer for data storage |
|
280 result = device->CreateBuffer(&bufferDesc, NULL, &mBuffer); |
|
281 if (FAILED(result)) |
|
282 { |
|
283 return gl::error(GL_OUT_OF_MEMORY); |
|
284 } |
|
285 } |
|
286 |
|
287 updateSerial(); |
|
288 mBufferSize = bufferDesc.ByteWidth; |
|
289 } |
|
290 |
|
291 if (!directInitialization) |
|
292 { |
|
293 ASSERT(mStagingBuffer && mStagingBufferSize >= requiredStagingSize); |
|
294 |
|
295 // Data is already put into the staging buffer, copy it over to the data buffer |
|
296 D3D11_BOX srcBox; |
|
297 srcBox.left = 0; |
|
298 srcBox.right = size; |
|
299 srcBox.top = 0; |
|
300 srcBox.bottom = 1; |
|
301 srcBox.front = 0; |
|
302 srcBox.back = 1; |
|
303 |
|
304 context->CopySubresourceRegion(mBuffer, 0, offset, 0, 0, mStagingBuffer, 0, &srcBox); |
|
305 } |
|
306 |
|
307 mSize = std::max(mSize, offset + size); |
|
308 |
|
309 mWriteUsageCount = 0; |
|
310 |
|
311 mResolvedDataValid = false; |
|
312 } |
|
313 |
|
314 void BufferStorage11::clear() |
|
315 { |
|
316 mResolvedDataValid = false; |
|
317 mSize = 0; |
|
318 } |
|
319 |
|
320 unsigned int BufferStorage11::getSize() const |
|
321 { |
|
322 return mSize; |
|
323 } |
|
324 |
|
325 bool BufferStorage11::supportsDirectBinding() const |
|
326 { |
|
327 return true; |
|
328 } |
|
329 |
|
330 void BufferStorage11::markBufferUsage() |
|
331 { |
|
332 mReadUsageCount++; |
|
333 mWriteUsageCount++; |
|
334 |
|
335 static const unsigned int usageLimit = 5; |
|
336 |
|
337 if (mReadUsageCount > usageLimit && mResolvedData) |
|
338 { |
|
339 free(mResolvedData); |
|
340 mResolvedData = NULL; |
|
341 mResolvedDataSize = 0; |
|
342 mResolvedDataValid = false; |
|
343 } |
|
344 |
|
345 if (mReadUsageCount > usageLimit && mWriteUsageCount > usageLimit && mStagingBuffer) |
|
346 { |
|
347 mStagingBuffer->Release(); |
|
348 mStagingBuffer = NULL; |
|
349 mStagingBufferSize = 0; |
|
350 } |
|
351 } |
|
352 |
|
353 ID3D11Buffer *BufferStorage11::getBuffer() const |
|
354 { |
|
355 return mBuffer; |
|
356 } |
|
357 |
|
358 } |