blob: 7a629dda9da0a815090131d3eb3acb148408568f [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 {
Geoff Langea228632013-07-30 15:17:12 -040046 SafeDelete(*it);
shannonwoods@chromium.org675526e2013-05-30 00:04:49 +000047 }
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
Shannon Woods193dc482013-06-26 15:30:09 -0400157 if (data && (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
shannonwoods@chromium.org29233b22013-05-30 00:04:57 +0000225 const unsigned int usageLimit = 5;
shannon.woods@transgaming.com70c856f2013-02-28 23:07:53 +0000226
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{
shannonwoods@chromium.org29233b22013-05-30 00:04:57 +0000238 markBufferUsage();
239
shannonwoods@chromium.org675526e2013-05-30 00:04:49 +0000240 for (DirectBufferList::iterator it = mDirectBuffers.begin(); it != mDirectBuffers.end(); it++)
shannon.woods@transgaming.com70c856f2013-02-28 23:07:53 +0000241 {
shannonwoods@chromium.org675526e2013-05-30 00:04:49 +0000242 DirectBufferStorage11 *directBuffer = *it;
243
244 if (directBuffer->hasTarget(usage))
245 {
246 if (directBuffer->isDirty())
247 {
248 // if updateFromStagingBuffer returns true, the D3D buffer has been recreated
249 // and we should update our serial
250 if (directBuffer->updateFromStagingBuffer(mStagingBuffer, mSize, 0))
251 {
252 updateSerial();
253 }
254 }
255 return directBuffer->getD3DBuffer();
256 }
257 }
258
259 // buffer is not allocated, create it
260 DirectBufferStorage11 *directBuffer = new DirectBufferStorage11(mRenderer, usage);
261 directBuffer->updateFromStagingBuffer(mStagingBuffer, mSize, 0);
262
263 mDirectBuffers.push_back(directBuffer);
264 updateSerial();
265
266 return directBuffer->getD3DBuffer();
267}
268
269DirectBufferStorage11::DirectBufferStorage11(Renderer11 *renderer, const GLenum target)
270 : mRenderer(renderer)
271 , mTarget(target)
272 , mDirectBuffer(NULL)
273 , mBufferSize(0)
274 , mDirty(false)
275{
276}
277
278DirectBufferStorage11::~DirectBufferStorage11()
279{
280 SafeRelease(mDirectBuffer);
281}
282
283bool DirectBufferStorage11::hasTarget(const GLenum target) const
284{
285 switch (target)
286 {
287 case GL_ELEMENT_ARRAY_BUFFER:
288 case GL_ARRAY_BUFFER:
289 return mTarget == GL_ELEMENT_ARRAY_BUFFER || mTarget == GL_ARRAY_BUFFER;
290 default:
291 return target == mTarget;
shannon.woods@transgaming.com70c856f2013-02-28 23:07:53 +0000292 }
293}
294
shannonwoods@chromium.org675526e2013-05-30 00:04:49 +0000295// Returns true if it recreates the direct buffer
296bool DirectBufferStorage11::updateFromStagingBuffer(ID3D11Buffer *stagingBuffer, const size_t size, const size_t offset)
shannon.woods@transgaming.com70c856f2013-02-28 23:07:53 +0000297{
shannonwoods@chromium.org675526e2013-05-30 00:04:49 +0000298 ID3D11Device *device = mRenderer->getDevice();
299 ID3D11DeviceContext *context = mRenderer->getDeviceContext();
300
301 // unused for now
302 ASSERT(offset == 0);
303
304 unsigned int requiredBufferSize = size + offset;
305 bool createBuffer = !mDirectBuffer || mBufferSize < requiredBufferSize;
306
307 // (Re)initialize D3D buffer if needed
308 if (createBuffer)
309 {
310 D3D11_BUFFER_DESC bufferDesc;
311 fillBufferDesc(&bufferDesc, requiredBufferSize);
312
313 ID3D11Buffer *newBuffer;
314 HRESULT result = device->CreateBuffer(&bufferDesc, NULL, &newBuffer);
315
316 if (FAILED(result))
317 {
318 return gl::error(GL_OUT_OF_MEMORY, false);
319 }
320
321 // No longer need the old buffer
322 SafeRelease(mDirectBuffer);
323 mDirectBuffer = newBuffer;
324
325 mBufferSize = bufferDesc.ByteWidth;
326 }
327 else
328 {
329 mBufferSize = requiredBufferSize;
330 }
331
332 // Copy data via staging buffer
333 D3D11_BOX srcBox;
334 srcBox.left = 0;
335 srcBox.right = size;
336 srcBox.top = 0;
337 srcBox.bottom = 1;
338 srcBox.front = 0;
339 srcBox.back = 1;
340
341 context->CopySubresourceRegion(mDirectBuffer, 0, offset, 0, 0, stagingBuffer, 0, &srcBox);
342
343 mDirty = false;
344
345 return createBuffer;
346}
347
348void DirectBufferStorage11::fillBufferDesc(D3D11_BUFFER_DESC* bufferDesc, unsigned int bufferSize)
349{
350 bufferDesc->ByteWidth = bufferSize;
351 bufferDesc->MiscFlags = 0;
352 bufferDesc->StructureByteStride = 0;
353
354 switch (mTarget)
355 {
356 case GL_ELEMENT_ARRAY_BUFFER:
357 case GL_ARRAY_BUFFER:
358 bufferDesc->Usage = D3D11_USAGE_DEFAULT;
359 bufferDesc->BindFlags = D3D11_BIND_INDEX_BUFFER | D3D11_BIND_VERTEX_BUFFER;
360 bufferDesc->CPUAccessFlags = 0;
361 break;
362
shannonwoods@chromium.orgce672482013-05-30 00:05:14 +0000363 case GL_UNIFORM_BUFFER:
364 bufferDesc->Usage = D3D11_USAGE_DYNAMIC;
365 bufferDesc->BindFlags = D3D11_BIND_CONSTANT_BUFFER;
366 bufferDesc->CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
367
368 // Constant buffers must be of a limited size, and aligned to 16 byte boundaries
369 // For our purposes we ignore any buffer data past the maximum constant buffer size
370 bufferDesc->ByteWidth = roundUp(bufferDesc->ByteWidth, 16u);
371 bufferDesc->ByteWidth = std::min(bufferDesc->ByteWidth, mRenderer->getMaxUniformBufferSize());
372 break;
373
shannonwoods@chromium.org675526e2013-05-30 00:04:49 +0000374 default:
375 UNREACHABLE();
376 break;
377 }
shannon.woods@transgaming.com70c856f2013-02-28 23:07:53 +0000378}
379
380}