1//
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// VertexBuffer11.cpp: Defines the D3D11 VertexBuffer implementation.
8
9#include "libGLESv2/renderer/d3d/d3d11/VertexBuffer11.h"
10#include "libGLESv2/renderer/d3d/d3d11/Buffer11.h"
11#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h"
12#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h"
13#include "libGLESv2/Buffer.h"
14#include "libGLESv2/VertexAttribute.h"
15
16namespace rx
17{
18
19VertexBuffer11::VertexBuffer11(rx::Renderer11 *const renderer) : mRenderer(renderer)
20{
21    mBuffer = NULL;
22    mBufferSize = 0;
23    mDynamicUsage = false;
24}
25
26VertexBuffer11::~VertexBuffer11()
27{
28    SafeRelease(mBuffer);
29}
30
31gl::Error VertexBuffer11::initialize(unsigned int size, bool dynamicUsage)
32{
33    SafeRelease(mBuffer);
34
35    updateSerial();
36
37    if (size > 0)
38    {
39        ID3D11Device* dxDevice = mRenderer->getDevice();
40
41        D3D11_BUFFER_DESC bufferDesc;
42        bufferDesc.ByteWidth = size;
43        bufferDesc.Usage = D3D11_USAGE_DYNAMIC;
44        bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
45        bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
46        bufferDesc.MiscFlags = 0;
47        bufferDesc.StructureByteStride = 0;
48
49        HRESULT result = dxDevice->CreateBuffer(&bufferDesc, NULL, &mBuffer);
50        if (FAILED(result))
51        {
52            return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal vertex buffer of size, %lu.", size);
53        }
54    }
55
56    mBufferSize = size;
57    mDynamicUsage = dynamicUsage;
58
59    return gl::Error(GL_NO_ERROR);
60}
61
62VertexBuffer11 *VertexBuffer11::makeVertexBuffer11(VertexBuffer *vetexBuffer)
63{
64    ASSERT(HAS_DYNAMIC_TYPE(VertexBuffer11*, vetexBuffer));
65    return static_cast<VertexBuffer11*>(vetexBuffer);
66}
67
68gl::Error VertexBuffer11::storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData &currentValue,
69                                                GLint start, GLsizei count, GLsizei instances, unsigned int offset)
70{
71    if (!mBuffer)
72    {
73        return gl::Error(GL_OUT_OF_MEMORY, "Internal vertex buffer is not initialized.");
74    }
75
76    gl::Buffer *buffer = attrib.buffer.get();
77    int inputStride = ComputeVertexAttributeStride(attrib);
78    ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext();
79
80    D3D11_MAPPED_SUBRESOURCE mappedResource;
81    HRESULT result = dxContext->Map(mBuffer, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &mappedResource);
82    if (FAILED(result))
83    {
84        return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal vertex buffer, HRESULT: 0x%08x.", result);
85    }
86
87    uint8_t *output = reinterpret_cast<uint8_t*>(mappedResource.pData) + offset;
88
89    const uint8_t *input = NULL;
90    if (attrib.enabled)
91    {
92        if (buffer)
93        {
94            Buffer11 *storage = Buffer11::makeBuffer11(buffer->getImplementation());
95            input = static_cast<const uint8_t*>(storage->getData()) + static_cast<int>(attrib.offset);
96        }
97        else
98        {
99            input = static_cast<const uint8_t*>(attrib.pointer);
100        }
101    }
102    else
103    {
104        input = reinterpret_cast<const uint8_t*>(currentValue.FloatValues);
105    }
106
107    if (instances == 0 || attrib.divisor == 0)
108    {
109        input += inputStride * start;
110    }
111
112    gl::VertexFormat vertexFormat(attrib, currentValue.Type);
113    const d3d11::VertexFormat &vertexFormatInfo = d3d11::GetVertexFormatInfo(vertexFormat);
114    ASSERT(vertexFormatInfo.copyFunction != NULL);
115    vertexFormatInfo.copyFunction(input, inputStride, count, output);
116
117    dxContext->Unmap(mBuffer, 0);
118
119    return gl::Error(GL_NO_ERROR);
120}
121
122gl::Error VertexBuffer11::getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count,
123                                           GLsizei instances, unsigned int *outSpaceRequired) const
124{
125    unsigned int elementCount = 0;
126    if (attrib.enabled)
127    {
128        if (instances == 0 || attrib.divisor == 0)
129        {
130            elementCount = count;
131        }
132        else
133        {
134            // Round up to divisor, if possible
135            elementCount = rx::UnsignedCeilDivide(static_cast<unsigned int>(instances), attrib.divisor);
136        }
137
138        gl::VertexFormat vertexFormat(attrib);
139        const d3d11::VertexFormat &vertexFormatInfo = d3d11::GetVertexFormatInfo(vertexFormat);
140        const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(vertexFormatInfo.nativeFormat);
141        unsigned int elementSize = dxgiFormatInfo.pixelBytes;
142        if (elementSize <= std::numeric_limits<unsigned int>::max() / elementCount)
143        {
144            if (outSpaceRequired)
145            {
146                *outSpaceRequired = elementSize * elementCount;
147            }
148            return gl::Error(GL_NO_ERROR);
149        }
150        else
151        {
152            return gl::Error(GL_OUT_OF_MEMORY, "New vertex buffer size would result in an overflow.");
153        }
154    }
155    else
156    {
157        const unsigned int elementSize = 4;
158        if (outSpaceRequired)
159        {
160            *outSpaceRequired = elementSize * 4;
161        }
162        return gl::Error(GL_NO_ERROR);
163    }
164}
165
166unsigned int VertexBuffer11::getBufferSize() const
167{
168    return mBufferSize;
169}
170
171gl::Error VertexBuffer11::setBufferSize(unsigned int size)
172{
173    if (size > mBufferSize)
174    {
175        return initialize(size, mDynamicUsage);
176    }
177    else
178    {
179        return gl::Error(GL_NO_ERROR);
180    }
181}
182
183gl::Error VertexBuffer11::discard()
184{
185    if (!mBuffer)
186    {
187        return gl::Error(GL_OUT_OF_MEMORY, "Internal vertex buffer is not initialized.");
188    }
189
190    ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext();
191
192    D3D11_MAPPED_SUBRESOURCE mappedResource;
193    HRESULT result = dxContext->Map(mBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
194    if (FAILED(result))
195    {
196        return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal buffer for discarding, HRESULT: 0x%08x", result);
197    }
198
199    dxContext->Unmap(mBuffer, 0);
200
201    return gl::Error(GL_NO_ERROR);
202}
203
204ID3D11Buffer *VertexBuffer11::getBuffer() const
205{
206    return mBuffer;
207}
208
209}
210