#include "precompiled.h" // // Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // VertexBuffer9.cpp: Defines the D3D9 VertexBuffer implementation. #include "libGLESv2/renderer/d3d/d3d9/VertexBuffer9.h" #include "libGLESv2/renderer/vertexconversion.h" #include "libGLESv2/renderer/BufferImpl.h" #include "libGLESv2/VertexAttribute.h" #include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" #include "libGLESv2/renderer/d3d/d3d9/formatutils9.h" #include "libGLESv2/Buffer.h" namespace rx { VertexBuffer9::VertexBuffer9(rx::Renderer9 *const renderer) : mRenderer(renderer) { mVertexBuffer = NULL; mBufferSize = 0; mDynamicUsage = false; } VertexBuffer9::~VertexBuffer9() { SafeRelease(mVertexBuffer); } bool VertexBuffer9::initialize(unsigned int size, bool dynamicUsage) { SafeRelease(mVertexBuffer); updateSerial(); if (size > 0) { DWORD flags = D3DUSAGE_WRITEONLY; if (dynamicUsage) { flags |= D3DUSAGE_DYNAMIC; } HRESULT result = mRenderer->createVertexBuffer(size, flags, &mVertexBuffer); if (FAILED(result)) { ERR("Out of memory allocating a vertex buffer of size %lu.", size); return false; } } mBufferSize = size; mDynamicUsage = dynamicUsage; return true; } VertexBuffer9 *VertexBuffer9::makeVertexBuffer9(VertexBuffer *vertexBuffer) { ASSERT(HAS_DYNAMIC_TYPE(VertexBuffer9*, vertexBuffer)); return static_cast(vertexBuffer); } bool VertexBuffer9::storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, GLint start, GLsizei count, GLsizei instances, unsigned int offset) { if (mVertexBuffer) { gl::Buffer *buffer = attrib.buffer.get(); int inputStride = gl::ComputeVertexAttributeStride(attrib); int elementSize = gl::ComputeVertexAttributeTypeSize(attrib); DWORD lockFlags = mDynamicUsage ? D3DLOCK_NOOVERWRITE : 0; void *mapPtr = NULL; unsigned int mapSize; if (!spaceRequired(attrib, count, instances, &mapSize)) { return false; } HRESULT result = mVertexBuffer->Lock(offset, mapSize, &mapPtr, lockFlags); if (FAILED(result)) { ERR("Lock failed with error 0x%08x", result); return false; } const char *input = NULL; if (attrib.enabled) { if (buffer) { BufferImpl *storage = buffer->getImplementation(); input = static_cast(storage->getData()) + static_cast(attrib.offset); } else { input = static_cast(attrib.pointer); } } else { input = reinterpret_cast(currentValue.FloatValues); } if (instances == 0 || attrib.divisor == 0) { input += inputStride * start; } gl::VertexFormat vertexFormat(attrib, currentValue.Type); bool needsConversion = (d3d9::GetVertexConversionType(vertexFormat) & VERTEX_CONVERT_CPU) > 0; if (!needsConversion && inputStride == elementSize) { size_t copySize = static_cast(count) * static_cast(inputStride); memcpy(mapPtr, input, copySize); } else { VertexCopyFunction copyFunction = d3d9::GetVertexCopyFunction(vertexFormat); copyFunction(input, inputStride, count, mapPtr); } mVertexBuffer->Unlock(); return true; } else { ERR("Vertex buffer not initialized."); return false; } } bool VertexBuffer9::getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances, unsigned int *outSpaceRequired) const { return spaceRequired(attrib, count, instances, outSpaceRequired); } unsigned int VertexBuffer9::getBufferSize() const { return mBufferSize; } bool VertexBuffer9::setBufferSize(unsigned int size) { if (size > mBufferSize) { return initialize(size, mDynamicUsage); } else { return true; } } bool VertexBuffer9::discard() { if (mVertexBuffer) { void *dummy; HRESULT result; result = mVertexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD); if (FAILED(result)) { ERR("Discard lock failed with error 0x%08x", result); return false; } result = mVertexBuffer->Unlock(); if (FAILED(result)) { ERR("Discard unlock failed with error 0x%08x", result); return false; } return true; } else { ERR("Vertex buffer not initialized."); return false; } } IDirect3DVertexBuffer9 * VertexBuffer9::getBuffer() const { return mVertexBuffer; } bool VertexBuffer9::spaceRequired(const gl::VertexAttribute &attrib, std::size_t count, GLsizei instances, unsigned int *outSpaceRequired) { gl::VertexFormat vertexFormat(attrib, GL_FLOAT); unsigned int elementSize = d3d9::GetVertexElementSize(vertexFormat); if (attrib.enabled) { unsigned int elementCount = 0; if (instances == 0 || attrib.divisor == 0) { elementCount = count; } else { if (static_cast(instances) < std::numeric_limits::max() - (attrib.divisor - 1)) { // Round up elementCount = (static_cast(instances) + (attrib.divisor - 1)) / attrib.divisor; } else { elementCount = static_cast(instances) / attrib.divisor; } } if (elementSize <= std::numeric_limits::max() / elementCount) { if (outSpaceRequired) { *outSpaceRequired = elementSize * elementCount; } return true; } else { return false; } } else { const unsigned int elementSize = 4; if (outSpaceRequired) { *outSpaceRequired = elementSize * 4; } return true; } } }