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 "libGLESv2/renderer/d3d/d3d9/VertexBuffer9.h" 10 #include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" 11 #include "libGLESv2/renderer/d3d/d3d9/formatutils9.h" 12 #include "libGLESv2/renderer/vertexconversion.h" 13 #include "libGLESv2/renderer/BufferImpl.h" 14 #include "libGLESv2/VertexAttribute.h" 15 #include "libGLESv2/Buffer.h" 16 17 namespace rx 18 { 19 20 VertexBuffer9::VertexBuffer9(rx::Renderer9 *renderer) : mRenderer(renderer) 21 { 22 mVertexBuffer = NULL; 23 mBufferSize = 0; 24 mDynamicUsage = false; 25 } 26 27 VertexBuffer9::~VertexBuffer9() 28 { 29 SafeRelease(mVertexBuffer); 30 } 31 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::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal vertex buffer of size, %lu.", size); 51 } 52 } 53 54 mBufferSize = size; 55 mDynamicUsage = dynamicUsage; 56 return gl::Error(GL_NO_ERROR); 57 } 58 59 VertexBuffer9 *VertexBuffer9::makeVertexBuffer9(VertexBuffer *vertexBuffer) 60 { 61 ASSERT(HAS_DYNAMIC_TYPE(VertexBuffer9*, vertexBuffer)); 62 return static_cast<VertexBuffer9*>(vertexBuffer); 63 } 64 65 gl::Error VertexBuffer9::storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, 66 GLint start, GLsizei count, GLsizei instances, unsigned int offset) 67 { 68 if (!mVertexBuffer) 69 { 70 return gl::Error(GL_OUT_OF_MEMORY, "Internal vertex buffer is not initialized."); 71 } 72 73 gl::Buffer *buffer = attrib.buffer.get(); 74 75 int inputStride = gl::ComputeVertexAttributeStride(attrib); 76 int elementSize = gl::ComputeVertexAttributeTypeSize(attrib); 77 78 DWORD lockFlags = mDynamicUsage ? D3DLOCK_NOOVERWRITE : 0; 79 80 uint8_t *mapPtr = NULL; 81 82 unsigned int mapSize; 83 gl::Error error = spaceRequired(attrib, count, instances, &mapSize); 84 if (error.isError()) 85 { 86 return error; 87 } 88 89 HRESULT result = mVertexBuffer->Lock(offset, mapSize, reinterpret_cast<void**>(&mapPtr), lockFlags); 90 if (FAILED(result)) 91 { 92 return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal vertex buffer, HRESULT: 0x%08x.", result); 93 } 94 95 const uint8_t *input = NULL; 96 if (attrib.enabled) 97 { 98 if (buffer) 99 { 100 BufferImpl *storage = buffer->getImplementation(); 101 input = static_cast<const uint8_t*>(storage->getData()) + static_cast<int>(attrib.offset); 102 } 103 else 104 { 105 input = static_cast<const uint8_t*>(attrib.pointer); 106 } 107 } 108 else 109 { 110 input = reinterpret_cast<const uint8_t*>(currentValue.FloatValues); 111 } 112 113 if (instances == 0 || attrib.divisor == 0) 114 { 115 input += inputStride * start; 116 } 117 118 gl::VertexFormat vertexFormat(attrib, currentValue.Type); 119 const d3d9::VertexFormat &d3dVertexInfo = d3d9::GetVertexFormatInfo(mRenderer->getCapsDeclTypes(), vertexFormat); 120 bool needsConversion = (d3dVertexInfo.conversionType & VERTEX_CONVERT_CPU) > 0; 121 122 if (!needsConversion && inputStride == elementSize) 123 { 124 size_t copySize = static_cast<size_t>(count) * static_cast<size_t>(inputStride); 125 memcpy(mapPtr, input, copySize); 126 } 127 else 128 { 129 d3dVertexInfo.copyFunction(input, inputStride, count, mapPtr); 130 } 131 132 mVertexBuffer->Unlock(); 133 134 return gl::Error(GL_NO_ERROR); 135 } 136 137 gl::Error VertexBuffer9::getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances, 138 unsigned int *outSpaceRequired) const 139 { 140 return spaceRequired(attrib, count, instances, outSpaceRequired); 141 } 142 143 unsigned int VertexBuffer9::getBufferSize() const 144 { 145 return mBufferSize; 146 } 147 148 gl::Error VertexBuffer9::setBufferSize(unsigned int size) 149 { 150 if (size > mBufferSize) 151 { 152 return initialize(size, mDynamicUsage); 153 } 154 else 155 { 156 return gl::Error(GL_NO_ERROR); 157 } 158 } 159 160 gl::Error VertexBuffer9::discard() 161 { 162 if (!mVertexBuffer) 163 { 164 return gl::Error(GL_OUT_OF_MEMORY, "Internal vertex buffer is not initialized."); 165 } 166 167 void *dummy; 168 HRESULT result; 169 170 result = mVertexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD); 171 if (FAILED(result)) 172 { 173 return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal buffer for discarding, HRESULT: 0x%08x", result); 174 } 175 176 result = mVertexBuffer->Unlock(); 177 if (FAILED(result)) 178 { 179 return gl::Error(GL_OUT_OF_MEMORY, "Failed to unlock internal buffer for discarding, HRESULT: 0x%08x", result); 180 } 181 182 return gl::Error(GL_NO_ERROR); 183 } 184 185 IDirect3DVertexBuffer9 * VertexBuffer9::getBuffer() const 186 { 187 return mVertexBuffer; 188 } 189 190 gl::Error VertexBuffer9::spaceRequired(const gl::VertexAttribute &attrib, std::size_t count, GLsizei instances, 191 unsigned int *outSpaceRequired) const 192 { 193 gl::VertexFormat vertexFormat(attrib, GL_FLOAT); 194 const d3d9::VertexFormat &d3d9VertexInfo = d3d9::GetVertexFormatInfo(mRenderer->getCapsDeclTypes(), vertexFormat); 195 196 if (attrib.enabled) 197 { 198 unsigned int elementCount = 0; 199 if (instances == 0 || attrib.divisor == 0) 200 { 201 elementCount = count; 202 } 203 else 204 { 205 // Round up to divisor, if possible 206 elementCount = rx::UnsignedCeilDivide(static_cast<unsigned int>(instances), attrib.divisor); 207 } 208 209 if (d3d9VertexInfo.outputElementSize <= std::numeric_limits<unsigned int>::max() / elementCount) 210 { 211 if (outSpaceRequired) 212 { 213 *outSpaceRequired = d3d9VertexInfo.outputElementSize * elementCount; 214 } 215 return gl::Error(GL_NO_ERROR); 216 } 217 else 218 { 219 return gl::Error(GL_OUT_OF_MEMORY, "New vertex buffer size would result in an overflow."); 220 } 221 } 222 else 223 { 224 const unsigned int elementSize = 4; 225 if (outSpaceRequired) 226 { 227 *outSpaceRequired = elementSize * 4; 228 } 229 return gl::Error(GL_NO_ERROR); 230 } 231 } 232 233 } 234