blob: 7c70880315f4dbc82cc5cbe6e77d8b4d71289bf3 [file] [log] [blame]
shannon.woods@transgaming.combdf2d802013-02-28 23:16:20 +00001#include "precompiled.h"
shannon.woods@transgaming.com70c856f2013-02-28 23:07:53 +00002//
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"
shannon.woods@transgaming.com486d9e92013-02-28 23:15:41 +000012#include "libGLESv2/renderer/Renderer11.h"
shannon.woods@transgaming.com70c856f2013-02-28 23:07:53 +000013
14namespace rx
15{
16
17BufferStorage11::BufferStorage11(Renderer11 *renderer)
18{
19 mRenderer = renderer;
20
21 mStagingBuffer = NULL;
22 mStagingBufferSize = 0;
23
shannon.woods@transgaming.com70c856f2013-02-28 23:07:53 +000024 mSize = 0;
25
26 mResolvedData = NULL;
27 mResolvedDataSize = 0;
28 mResolvedDataValid = false;
29
30 mReadUsageCount = 0;
31 mWriteUsageCount = 0;
32}
33
34BufferStorage11::~BufferStorage11()
35{
shannonwoods@chromium.org675526e2013-05-30 00:04:49 +000036 SafeRelease(mStagingBuffer);
shannon.woods@transgaming.com70c856f2013-02-28 23:07:53 +000037
38 if (mResolvedData)
39 {
40 free(mResolvedData);
41 mResolvedData = NULL;
42 }
shannonwoods@chromium.org675526e2013-05-30 00:04:49 +000043
44 for (DirectBufferList::iterator it = mDirectBuffers.begin(); it != mDirectBuffers.end(); it++)
45 {
46 delete *it;
47 }
shannon.woods@transgaming.com70c856f2013-02-28 23:07:53 +000048}
49
50BufferStorage11 *BufferStorage11::makeBufferStorage11(BufferStorage *bufferStorage)
51{
52 ASSERT(HAS_DYNAMIC_TYPE(BufferStorage11*, bufferStorage));
53 return static_cast<BufferStorage11*>(bufferStorage);
54}
55
56void *BufferStorage11::getData()
57{
shannonwoods@chromium.org675526e2013-05-30 00:04:49 +000058 ASSERT(mStagingBuffer);
59
shannon.woods@transgaming.com70c856f2013-02-28 23:07:53 +000060 if (!mResolvedDataValid)
61 {
62 ID3D11Device *device = mRenderer->getDevice();
63 ID3D11DeviceContext *context = mRenderer->getDeviceContext();
64 HRESULT result;
65
shannonwoods@chromium.org675526e2013-05-30 00:04:49 +000066 if (!mResolvedData || mResolvedDataSize < mStagingBufferSize)
shannon.woods@transgaming.com70c856f2013-02-28 23:07:53 +000067 {
68 free(mResolvedData);
69 mResolvedData = malloc(mSize);
70 mResolvedDataSize = mSize;
71 }
72
shannon.woods@transgaming.com70c856f2013-02-28 23:07:53 +000073 D3D11_MAPPED_SUBRESOURCE mappedResource;
74 result = context->Map(mStagingBuffer, 0, D3D11_MAP_READ, 0, &mappedResource);
75 if (FAILED(result))
76 {
77 return gl::error(GL_OUT_OF_MEMORY, (void*)NULL);
78 }
79
80 memcpy(mResolvedData, mappedResource.pData, mSize);
81
82 context->Unmap(mStagingBuffer, 0);
83
84 mResolvedDataValid = true;
85 }
86
87 mReadUsageCount = 0;
88
89 return mResolvedData;
90}
91
92void BufferStorage11::setData(const void* data, unsigned int size, unsigned int offset)
93{
94 ID3D11Device *device = mRenderer->getDevice();
95 ID3D11DeviceContext *context = mRenderer->getDeviceContext();
96 HRESULT result;
97
shannonwoods@chromium.org675526e2013-05-30 00:04:49 +000098 const unsigned int requiredStagingBufferSize = size + offset;
99 const bool createStagingBuffer = !mStagingBuffer || mStagingBufferSize < requiredStagingBufferSize;
shannon.woods@transgaming.com70c856f2013-02-28 23:07:53 +0000100
shannonwoods@chromium.org675526e2013-05-30 00:04:49 +0000101 if (createStagingBuffer)
shannon.woods@transgaming.com70c856f2013-02-28 23:07:53 +0000102 {
103 D3D11_BUFFER_DESC bufferDesc;
shannonwoods@chromium.org675526e2013-05-30 00:04:49 +0000104 bufferDesc.ByteWidth = requiredStagingBufferSize;
105 bufferDesc.Usage = D3D11_USAGE_STAGING;
106 bufferDesc.BindFlags = 0;
107 bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
shannon.woods@transgaming.com70c856f2013-02-28 23:07:53 +0000108 bufferDesc.MiscFlags = 0;
109 bufferDesc.StructureByteStride = 0;
110
shannonwoods@chromium.org675526e2013-05-30 00:04:49 +0000111 HRESULT result;
112 ID3D11Device *device = mRenderer->getDevice();
113 ID3D11DeviceContext *context = mRenderer->getDeviceContext();
114 ID3D11Buffer *newStagingBuffer;
115
116 if (data && offset == 0)
shannon.woods@transgaming.com70c856f2013-02-28 23:07:53 +0000117 {
shannonwoods@chromium.org675526e2013-05-30 00:04:49 +0000118 D3D11_SUBRESOURCE_DATA initialData;
119 initialData.pSysMem = data;
120 initialData.SysMemPitch = requiredStagingBufferSize;
121 initialData.SysMemSlicePitch = 0;
shannon.woods@transgaming.com70c856f2013-02-28 23:07:53 +0000122
shannonwoods@chromium.org675526e2013-05-30 00:04:49 +0000123 result = device->CreateBuffer(&bufferDesc, &initialData, &newStagingBuffer);
shannon.woods@transgaming.com70c856f2013-02-28 23:07:53 +0000124 }
shannonwoods@chromium.org675526e2013-05-30 00:04:49 +0000125 else
126 {
127 result = device->CreateBuffer(&bufferDesc, NULL, &newStagingBuffer);
128 }
129
130 if (FAILED(result))
131 {
132 mStagingBufferSize = 0;
133 return gl::error(GL_OUT_OF_MEMORY);
134 }
135
136 mStagingBufferSize = requiredStagingBufferSize;
137
138 if (mStagingBuffer && offset > 0)
shannon.woods@transgaming.com70c856f2013-02-28 23:07:53 +0000139 {
140 // If offset is greater than zero and the buffer is non-null, need to preserve the data from
141 // the old buffer up to offset
shannon.woods@transgaming.com70c856f2013-02-28 23:07:53 +0000142 D3D11_BOX srcBox;
143 srcBox.left = 0;
shannonwoods@chromium.org675526e2013-05-30 00:04:49 +0000144 srcBox.right = std::min(offset, requiredStagingBufferSize);
shannon.woods@transgaming.com70c856f2013-02-28 23:07:53 +0000145 srcBox.top = 0;
146 srcBox.bottom = 1;
147 srcBox.front = 0;
148 srcBox.back = 1;
149
shannonwoods@chromium.org675526e2013-05-30 00:04:49 +0000150 context->CopySubresourceRegion(newStagingBuffer, 0, 0, 0, 0, mStagingBuffer, 0, &srcBox);
shannon.woods@transgaming.com70c856f2013-02-28 23:07:53 +0000151 }
152
shannonwoods@chromium.org675526e2013-05-30 00:04:49 +0000153 SafeRelease(mStagingBuffer);
154 mStagingBuffer = newStagingBuffer;
shannon.woods@transgaming.com70c856f2013-02-28 23:07:53 +0000155 }
156
shannonwoods@chromium.org675526e2013-05-30 00:04:49 +0000157 if (offset != 0 || !createStagingBuffer)
shannon.woods@transgaming.com70c856f2013-02-28 23:07:53 +0000158 {
shannonwoods@chromium.org675526e2013-05-30 00:04:49 +0000159 D3D11_MAPPED_SUBRESOURCE mappedResource;
160 result = context->Map(mStagingBuffer, 0, D3D11_MAP_WRITE, 0, &mappedResource);
161 if (FAILED(result))
162 {
163 return gl::error(GL_OUT_OF_MEMORY);
164 }
shannon.woods@transgaming.com70c856f2013-02-28 23:07:53 +0000165
shannonwoods@chromium.org675526e2013-05-30 00:04:49 +0000166 unsigned char *offsetBufferPointer = reinterpret_cast<unsigned char *>(mappedResource.pData) + offset;
167 memcpy(offsetBufferPointer, data, size);
shannon.woods@transgaming.com70c856f2013-02-28 23:07:53 +0000168
shannonwoods@chromium.org675526e2013-05-30 00:04:49 +0000169 context->Unmap(mStagingBuffer, 0);
shannon.woods@transgaming.com70c856f2013-02-28 23:07:53 +0000170 }
171
shannonwoods@chromium.org675526e2013-05-30 00:04:49 +0000172 for (DirectBufferList::iterator it = mDirectBuffers.begin(); it != mDirectBuffers.end(); it++)
173 {
174 (*it)->markDirty();
175 }
shannon.woods@transgaming.com70c856f2013-02-28 23:07:53 +0000176
shannonwoods@chromium.org675526e2013-05-30 00:04:49 +0000177 mSize = std::max(mSize, requiredStagingBufferSize);
shannon.woods@transgaming.com70c856f2013-02-28 23:07:53 +0000178 mWriteUsageCount = 0;
179
180 mResolvedDataValid = false;
181}
182
shannon.woods%transgaming.com@gtempaccount.comab30bab2013-04-13 03:39:24 +0000183void BufferStorage11::copyData(BufferStorage* sourceStorage, unsigned int size,
184 unsigned int sourceOffset, unsigned int destOffset)
185{
186 BufferStorage11* source = makeBufferStorage11(sourceStorage);
187 if (source)
188 {
189 ID3D11DeviceContext *context = mRenderer->getDeviceContext();
190
191 D3D11_BOX srcBox;
192 srcBox.left = sourceOffset;
193 srcBox.right = sourceOffset + size;
194 srcBox.top = 0;
195 srcBox.bottom = 1;
196 srcBox.front = 0;
197 srcBox.back = 1;
198
shannonwoods@chromium.org675526e2013-05-30 00:04:49 +0000199 ASSERT(mStagingBuffer && source->mStagingBuffer);
200 context->CopySubresourceRegion(mStagingBuffer, 0, destOffset, 0, 0, source->mStagingBuffer, 0, &srcBox);
shannon.woods%transgaming.com@gtempaccount.comab30bab2013-04-13 03:39:24 +0000201 }
202}
203
shannon.woods@transgaming.com70c856f2013-02-28 23:07:53 +0000204void BufferStorage11::clear()
205{
206 mResolvedDataValid = false;
207 mSize = 0;
208}
209
210unsigned int BufferStorage11::getSize() const
211{
212 return mSize;
213}
214
215bool BufferStorage11::supportsDirectBinding() const
216{
217 return true;
218}
219
220void BufferStorage11::markBufferUsage()
221{
222 mReadUsageCount++;
223 mWriteUsageCount++;
224
225 static const unsigned int usageLimit = 5;
226
227 if (mReadUsageCount > usageLimit && mResolvedData)
228 {
229 free(mResolvedData);
230 mResolvedData = NULL;
231 mResolvedDataSize = 0;
232 mResolvedDataValid = false;
233 }
shannonwoods@chromium.org675526e2013-05-30 00:04:49 +0000234}
shannon.woods@transgaming.com70c856f2013-02-28 23:07:53 +0000235
shannonwoods@chromium.org675526e2013-05-30 00:04:49 +0000236ID3D11Buffer *BufferStorage11::getBuffer(GLenum usage)
237{
238 for (DirectBufferList::iterator it = mDirectBuffers.begin(); it != mDirectBuffers.end(); it++)
shannon.woods@transgaming.com70c856f2013-02-28 23:07:53 +0000239 {
shannonwoods@chromium.org675526e2013-05-30 00:04:49 +0000240 DirectBufferStorage11 *directBuffer = *it;
241
242 if (directBuffer->hasTarget(usage))
243 {
244 if (directBuffer->isDirty())
245 {
246 // if updateFromStagingBuffer returns true, the D3D buffer has been recreated
247 // and we should update our serial
248 if (directBuffer->updateFromStagingBuffer(mStagingBuffer, mSize, 0))
249 {
250 updateSerial();
251 }
252 }
253 return directBuffer->getD3DBuffer();
254 }
255 }
256
257 // buffer is not allocated, create it
258 DirectBufferStorage11 *directBuffer = new DirectBufferStorage11(mRenderer, usage);
259 directBuffer->updateFromStagingBuffer(mStagingBuffer, mSize, 0);
260
261 mDirectBuffers.push_back(directBuffer);
262 updateSerial();
263
264 return directBuffer->getD3DBuffer();
265}
266
267DirectBufferStorage11::DirectBufferStorage11(Renderer11 *renderer, const GLenum target)
268 : mRenderer(renderer)
269 , mTarget(target)
270 , mDirectBuffer(NULL)
271 , mBufferSize(0)
272 , mDirty(false)
273{
274}
275
276DirectBufferStorage11::~DirectBufferStorage11()
277{
278 SafeRelease(mDirectBuffer);
279}
280
281bool DirectBufferStorage11::hasTarget(const GLenum target) const
282{
283 switch (target)
284 {
285 case GL_ELEMENT_ARRAY_BUFFER:
286 case GL_ARRAY_BUFFER:
287 return mTarget == GL_ELEMENT_ARRAY_BUFFER || mTarget == GL_ARRAY_BUFFER;
288 default:
289 return target == mTarget;
shannon.woods@transgaming.com70c856f2013-02-28 23:07:53 +0000290 }
291}
292
shannonwoods@chromium.org675526e2013-05-30 00:04:49 +0000293// Returns true if it recreates the direct buffer
294bool DirectBufferStorage11::updateFromStagingBuffer(ID3D11Buffer *stagingBuffer, const size_t size, const size_t offset)
shannon.woods@transgaming.com70c856f2013-02-28 23:07:53 +0000295{
shannonwoods@chromium.org675526e2013-05-30 00:04:49 +0000296 ID3D11Device *device = mRenderer->getDevice();
297 ID3D11DeviceContext *context = mRenderer->getDeviceContext();
298
299 // unused for now
300 ASSERT(offset == 0);
301
302 unsigned int requiredBufferSize = size + offset;
303 bool createBuffer = !mDirectBuffer || mBufferSize < requiredBufferSize;
304
305 // (Re)initialize D3D buffer if needed
306 if (createBuffer)
307 {
308 D3D11_BUFFER_DESC bufferDesc;
309 fillBufferDesc(&bufferDesc, requiredBufferSize);
310
311 ID3D11Buffer *newBuffer;
312 HRESULT result = device->CreateBuffer(&bufferDesc, NULL, &newBuffer);
313
314 if (FAILED(result))
315 {
316 return gl::error(GL_OUT_OF_MEMORY, false);
317 }
318
319 // No longer need the old buffer
320 SafeRelease(mDirectBuffer);
321 mDirectBuffer = newBuffer;
322
323 mBufferSize = bufferDesc.ByteWidth;
324 }
325 else
326 {
327 mBufferSize = requiredBufferSize;
328 }
329
330 // Copy data via staging buffer
331 D3D11_BOX srcBox;
332 srcBox.left = 0;
333 srcBox.right = size;
334 srcBox.top = 0;
335 srcBox.bottom = 1;
336 srcBox.front = 0;
337 srcBox.back = 1;
338
339 context->CopySubresourceRegion(mDirectBuffer, 0, offset, 0, 0, stagingBuffer, 0, &srcBox);
340
341 mDirty = false;
342
343 return createBuffer;
344}
345
346void DirectBufferStorage11::fillBufferDesc(D3D11_BUFFER_DESC* bufferDesc, unsigned int bufferSize)
347{
348 bufferDesc->ByteWidth = bufferSize;
349 bufferDesc->MiscFlags = 0;
350 bufferDesc->StructureByteStride = 0;
351
352 switch (mTarget)
353 {
354 case GL_ELEMENT_ARRAY_BUFFER:
355 case GL_ARRAY_BUFFER:
356 bufferDesc->Usage = D3D11_USAGE_DEFAULT;
357 bufferDesc->BindFlags = D3D11_BIND_INDEX_BUFFER | D3D11_BIND_VERTEX_BUFFER;
358 bufferDesc->CPUAccessFlags = 0;
359 break;
360
361 default:
362 UNREACHABLE();
363 break;
364 }
shannon.woods@transgaming.com70c856f2013-02-28 23:07:53 +0000365}
366
367}