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