std::size_t VertexDataManager::writeAttributeData(ArrayVertexBuffer *vertexBuffer, GLint start, GLsizei count, const VertexAttribute &attribute, GLsizei instances) { Buffer *buffer = attribute.mBoundBuffer.get(); int inputStride = attribute.stride(); int elementSize = attribute.typeSize(); const FormatConverter &converter = formatConverter(attribute); std::size_t streamOffset = 0; void *output = NULL; if (vertexBuffer) { output = vertexBuffer->map(attribute, spaceRequired(attribute, count, instances), &streamOffset); } if (output == NULL) { ERR("Failed to map vertex buffer."); return -1; } const char *input = NULL; if (buffer) { int offset = attribute.mOffset; input = static_cast<const char*>(buffer->data()) + offset; } else { input = static_cast<const char*>(attribute.mPointer); } if (instances == 0 || attribute.mDivisor == 0) { input += inputStride * start; } if (converter.identity && inputStride == elementSize) { memcpy(output, input, count * inputStride); } else { converter.convertArray(input, inputStride, count, output); } vertexBuffer->unmap(); return streamOffset; }
gl::Error VertexBuffer9::storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, GLint start, GLsizei count, GLsizei instances, unsigned int offset) { if (!mVertexBuffer) { return gl::Error(GL_OUT_OF_MEMORY, "Internal vertex buffer is not initialized."); } gl::Buffer *buffer = attrib.buffer.get(); int inputStride = gl::ComputeVertexAttributeStride(attrib); int elementSize = gl::ComputeVertexAttributeTypeSize(attrib); DWORD lockFlags = mDynamicUsage ? D3DLOCK_NOOVERWRITE : 0; uint8_t *mapPtr = NULL; unsigned int mapSize; gl::Error error = spaceRequired(attrib, count, instances, &mapSize); if (error.isError()) { return error; } HRESULT result = mVertexBuffer->Lock(offset, mapSize, reinterpret_cast<void**>(&mapPtr), lockFlags); if (FAILED(result)) { return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal vertex buffer, HRESULT: 0x%08x.", result); } const uint8_t *input = NULL; if (attrib.enabled) { if (buffer) { BufferD3D *storage = BufferD3D::makeFromBuffer(buffer); ASSERT(storage); gl::Error error = storage->getData(&input); if (error.isError()) { return error; } input += static_cast<int>(attrib.offset); } else { input = static_cast<const uint8_t*>(attrib.pointer); } } else { input = reinterpret_cast<const uint8_t*>(currentValue.FloatValues); } if (instances == 0 || attrib.divisor == 0) { input += inputStride * start; } gl::VertexFormat vertexFormat(attrib, currentValue.Type); const d3d9::VertexFormat &d3dVertexInfo = d3d9::GetVertexFormatInfo(mRenderer->getCapsDeclTypes(), vertexFormat); bool needsConversion = (d3dVertexInfo.conversionType & VERTEX_CONVERT_CPU) > 0; if (!needsConversion && inputStride == elementSize) { size_t copySize = static_cast<size_t>(count) * static_cast<size_t>(inputStride); memcpy(mapPtr, input, copySize); } else { d3dVertexInfo.copyFunction(input, inputStride, count, mapPtr); } mVertexBuffer->Unlock(); return gl::Error(GL_NO_ERROR); }
GLenum VertexDataManager::prepareVertexData(GLint start, GLsizei count, TranslatedAttribute *translated, GLsizei instances) { if (!mStreamingBuffer) { return GL_OUT_OF_MEMORY; } const VertexAttributeArray &attribs = mContext->getVertexAttributes(); Program *program = mContext->getCurrentProgram(); ProgramBinary *programBinary = program->getProgramBinary(); for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++) { translated[attributeIndex].active = (programBinary->getSemanticIndex(attributeIndex) != -1); } // Determine the required storage size per used buffer, and invalidate static buffers that don't contain matching attributes for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) { if (translated[i].active && attribs[i].mArrayEnabled) { Buffer *buffer = attribs[i].mBoundBuffer.get(); StaticVertexBuffer *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL; if (staticBuffer) { if (staticBuffer->size() == 0) { int totalCount = elementsInBuffer(attribs[i], buffer->size()); staticBuffer->addRequiredSpace(spaceRequired(attribs[i], totalCount, 0)); } else if (staticBuffer->lookupAttribute(attribs[i]) == -1) { // This static buffer doesn't have matching attributes, so fall back to using the streaming buffer // Add the space of all previous attributes belonging to the invalidated static buffer to the streaming buffer for (int previous = 0; previous < i; previous++) { if (translated[previous].active && attribs[previous].mArrayEnabled) { Buffer *previousBuffer = attribs[previous].mBoundBuffer.get(); StaticVertexBuffer *previousStaticBuffer = previousBuffer ? previousBuffer->getStaticVertexBuffer() : NULL; if (staticBuffer == previousStaticBuffer) { mStreamingBuffer->addRequiredSpace(spaceRequired(attribs[previous], count, instances)); } } } mStreamingBuffer->addRequiredSpace(spaceRequired(attribs[i], count, instances)); buffer->invalidateStaticData(); } } else { mStreamingBuffer->addRequiredSpace(spaceRequired(attribs[i], count, instances)); } } } // Reserve the required space per used buffer for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) { if (translated[i].active && attribs[i].mArrayEnabled) { Buffer *buffer = attribs[i].mBoundBuffer.get(); ArrayVertexBuffer *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL; ArrayVertexBuffer *vertexBuffer = staticBuffer ? staticBuffer : mStreamingBuffer; if (vertexBuffer) { vertexBuffer->reserveRequiredSpace(); } } } // Perform the vertex data translations for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) { if (translated[i].active) { if (attribs[i].mArrayEnabled) { Buffer *buffer = attribs[i].mBoundBuffer.get(); if (!buffer && attribs[i].mPointer == NULL) { // This is an application error that would normally result in a crash, but we catch it and return an error ERR("An enabled vertex array has no buffer and no pointer."); return GL_INVALID_OPERATION; } const FormatConverter &converter = formatConverter(attribs[i]); StaticVertexBuffer *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL; ArrayVertexBuffer *vertexBuffer = staticBuffer ? staticBuffer : static_cast<ArrayVertexBuffer*>(mStreamingBuffer); std::size_t streamOffset = -1; if (staticBuffer) { streamOffset = staticBuffer->lookupAttribute(attribs[i]); if (streamOffset == -1) { // Convert the entire buffer int totalCount = elementsInBuffer(attribs[i], buffer->size()); int startIndex = attribs[i].mOffset / attribs[i].stride(); streamOffset = writeAttributeData(staticBuffer, -startIndex, totalCount, attribs[i], 0); } if (streamOffset != -1) { streamOffset += (attribs[i].mOffset / attribs[i].stride()) * converter.outputElementSize; if (instances == 0 || attribs[i].mDivisor == 0) { streamOffset += start * converter.outputElementSize; } } } else { streamOffset = writeAttributeData(mStreamingBuffer, start, count, attribs[i], instances); } if (streamOffset == -1) { return GL_OUT_OF_MEMORY; } translated[i].vertexBuffer = vertexBuffer->getBuffer(); translated[i].serial = vertexBuffer->getSerial(); translated[i].divisor = attribs[i].mDivisor; translated[i].type = converter.d3dDeclType; translated[i].stride = converter.outputElementSize; translated[i].offset = streamOffset; } else { if (!mCurrentValueBuffer[i]) { mCurrentValueBuffer[i] = new StreamingVertexBuffer(mDevice, CONSTANT_VERTEX_BUFFER_SIZE); } StreamingVertexBuffer *buffer = mCurrentValueBuffer[i]; if (mDirtyCurrentValue[i]) { const int requiredSpace = 4 * sizeof(float); buffer->addRequiredSpace(requiredSpace); buffer->reserveRequiredSpace(); float *data = static_cast<float*>(buffer->map(VertexAttribute(), requiredSpace, &mCurrentValueOffsets[i])); if (data) { data[0] = attribs[i].mCurrentValue[0]; data[1] = attribs[i].mCurrentValue[1]; data[2] = attribs[i].mCurrentValue[2]; data[3] = attribs[i].mCurrentValue[3]; buffer->unmap(); mDirtyCurrentValue[i] = false; } } translated[i].vertexBuffer = mCurrentValueBuffer[i]->getBuffer(); translated[i].serial = mCurrentValueBuffer[i]->getSerial(); translated[i].divisor = 0; translated[i].type = D3DDECLTYPE_FLOAT4; translated[i].stride = 0; translated[i].offset = mCurrentValueOffsets[i]; } } } for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) { if (translated[i].active && attribs[i].mArrayEnabled) { Buffer *buffer = attribs[i].mBoundBuffer.get(); if (buffer) { buffer->promoteStaticUsage(count * attribs[i].typeSize()); } } } return GL_NO_ERROR; }
gl::Error VertexBuffer9::getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances, unsigned int *outSpaceRequired) const { return spaceRequired(attrib, count, instances, outSpaceRequired); }