1 //
2 // Copyright (c) 2002-2012 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 // VertexBuffer9.cpp: Defines the D3D9 VertexBuffer implementation.
8 
9 #include "libANGLE/renderer/d3d/d3d9/VertexBuffer9.h"
10 #include "libANGLE/renderer/d3d/d3d9/Renderer9.h"
11 #include "libANGLE/renderer/d3d/d3d9/formatutils9.h"
12 #include "libANGLE/renderer/d3d/d3d9/vertexconversion.h"
13 #include "libANGLE/renderer/d3d/BufferD3D.h"
14 #include "libANGLE/VertexAttribute.h"
15 #include "libANGLE/Buffer.h"
16 
17 namespace rx
18 {
19 
VertexBuffer9(Renderer9 * renderer)20 VertexBuffer9::VertexBuffer9(Renderer9 *renderer) : mRenderer(renderer)
21 {
22     mVertexBuffer = nullptr;
23     mBufferSize = 0;
24     mDynamicUsage = false;
25 }
26 
~VertexBuffer9()27 VertexBuffer9::~VertexBuffer9()
28 {
29     SafeRelease(mVertexBuffer);
30 }
31 
initialize(unsigned int size,bool dynamicUsage)32 gl::Error VertexBuffer9::initialize(unsigned int size, bool dynamicUsage)
33 {
34     SafeRelease(mVertexBuffer);
35 
36     updateSerial();
37 
38     if (size > 0)
39     {
40         DWORD flags = D3DUSAGE_WRITEONLY;
41         if (dynamicUsage)
42         {
43             flags |= D3DUSAGE_DYNAMIC;
44         }
45 
46         HRESULT result = mRenderer->createVertexBuffer(size, flags, &mVertexBuffer);
47 
48         if (FAILED(result))
49         {
50             return gl::OutOfMemory()
51                    << "Failed to allocate internal vertex buffer of size " << size;
52         }
53     }
54 
55     mBufferSize = size;
56     mDynamicUsage = dynamicUsage;
57     return gl::NoError();
58 }
59 
storeVertexAttributes(const gl::VertexAttribute & attrib,const gl::VertexBinding & binding,GLenum currentValueType,GLint start,GLsizei count,GLsizei instances,unsigned int offset,const uint8_t * sourceData)60 gl::Error VertexBuffer9::storeVertexAttributes(const gl::VertexAttribute &attrib,
61                                                const gl::VertexBinding &binding,
62                                                GLenum currentValueType,
63                                                GLint start,
64                                                GLsizei count,
65                                                GLsizei instances,
66                                                unsigned int offset,
67                                                const uint8_t *sourceData)
68 {
69     if (!mVertexBuffer)
70     {
71         return gl::OutOfMemory() << "Internal vertex buffer is not initialized.";
72     }
73 
74     int inputStride = static_cast<int>(gl::ComputeVertexAttributeStride(attrib, binding));
75     int elementSize = static_cast<int>(gl::ComputeVertexAttributeTypeSize(attrib));
76 
77     DWORD lockFlags = mDynamicUsage ? D3DLOCK_NOOVERWRITE : 0;
78 
79     uint8_t *mapPtr = nullptr;
80 
81     auto errorOrMapSize = mRenderer->getVertexSpaceRequired(attrib, binding, count, instances);
82     if (errorOrMapSize.isError())
83     {
84         return errorOrMapSize.getError();
85     }
86 
87     unsigned int mapSize = errorOrMapSize.getResult();
88 
89     HRESULT result = mVertexBuffer->Lock(offset, mapSize, reinterpret_cast<void**>(&mapPtr), lockFlags);
90     if (FAILED(result))
91     {
92         return gl::OutOfMemory() << "Failed to lock internal vertex buffer, " << gl::FmtHR(result);
93     }
94 
95     const uint8_t *input = sourceData;
96 
97     if (instances == 0 || binding.getDivisor() == 0)
98     {
99         input += inputStride * start;
100     }
101 
102     gl::VertexFormatType vertexFormatType = gl::GetVertexFormatType(attrib, currentValueType);
103     const d3d9::VertexFormat &d3dVertexInfo = d3d9::GetVertexFormatInfo(mRenderer->getCapsDeclTypes(), vertexFormatType);
104     bool needsConversion = (d3dVertexInfo.conversionType & VERTEX_CONVERT_CPU) > 0;
105 
106     if (!needsConversion && inputStride == elementSize)
107     {
108         size_t copySize = static_cast<size_t>(count) * static_cast<size_t>(inputStride);
109         memcpy(mapPtr, input, copySize);
110     }
111     else
112     {
113         d3dVertexInfo.copyFunction(input, inputStride, count, mapPtr);
114     }
115 
116     mVertexBuffer->Unlock();
117 
118     return gl::NoError();
119 }
120 
getBufferSize() const121 unsigned int VertexBuffer9::getBufferSize() const
122 {
123     return mBufferSize;
124 }
125 
setBufferSize(unsigned int size)126 gl::Error VertexBuffer9::setBufferSize(unsigned int size)
127 {
128     if (size > mBufferSize)
129     {
130         return initialize(size, mDynamicUsage);
131     }
132     else
133     {
134         return gl::NoError();
135     }
136 }
137 
discard()138 gl::Error VertexBuffer9::discard()
139 {
140     if (!mVertexBuffer)
141     {
142         return gl::OutOfMemory() << "Internal vertex buffer is not initialized.";
143     }
144 
145     void *dummy;
146     HRESULT result;
147 
148     result = mVertexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD);
149     if (FAILED(result))
150     {
151         return gl::OutOfMemory() << "Failed to lock internal buffer for discarding, "
152                                  << gl::FmtHR(result);
153     }
154 
155     result = mVertexBuffer->Unlock();
156     if (FAILED(result))
157     {
158         return gl::OutOfMemory() << "Failed to unlock internal buffer for discarding, "
159                                  << gl::FmtHR(result);
160     }
161 
162     return gl::NoError();
163 }
164 
getBuffer() const165 IDirect3DVertexBuffer9 * VertexBuffer9::getBuffer() const
166 {
167     return mVertexBuffer;
168 }
169 }  // namespace rx
170