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