void VertexDataManager::hintUnmapAllResources(const std::vector<gl::VertexAttribute> &vertexAttributes) { mStreamingBuffer->getVertexBuffer()->hintUnmapResource(); for (const TranslatedAttribute *translated : mActiveEnabledAttributes) { gl::Buffer *buffer = translated->attribute->buffer.get(); BufferD3D *storage = buffer ? GetImplAs<BufferD3D>(buffer) : nullptr; StaticVertexBufferInterface *staticBuffer = storage ? storage->getStaticVertexBuffer(*translated->attribute) : nullptr; if (staticBuffer) { staticBuffer->getVertexBuffer()->hintUnmapResource(); } } for (auto ¤tValue : mCurrentValueCache) { if (currentValue.buffer != nullptr) { currentValue.buffer->getVertexBuffer()->hintUnmapResource(); } } }
gl::Error VertexDataManager::reserveSpaceForAttrib(const TranslatedAttribute &translatedAttrib, GLsizei count, GLsizei instances) const { const gl::VertexAttribute &attrib = *translatedAttrib.attribute; gl::Buffer *buffer = attrib.buffer.get(); BufferD3D *bufferImpl = buffer ? GetImplAs<BufferD3D>(buffer) : NULL; StaticVertexBufferInterface *staticBuffer = bufferImpl ? bufferImpl->getStaticVertexBuffer(attrib) : NULL; VertexBufferInterface *vertexBuffer = staticBuffer ? staticBuffer : static_cast<VertexBufferInterface*>(mStreamingBuffer); if (!vertexBuffer->directStoragePossible(attrib, translatedAttrib.currentValueType)) { if (staticBuffer) { if (staticBuffer->getBufferSize() == 0) { int totalCount = ElementsInBuffer(attrib, static_cast<unsigned int>(bufferImpl->getSize())); gl::Error error = staticBuffer->reserveVertexSpace(attrib, totalCount, 0); if (error.isError()) { return error; } } } else { size_t totalCount = ComputeVertexAttributeElementCount(attrib, count, instances); ASSERT(!bufferImpl || ElementsInBuffer(attrib, static_cast<unsigned int>(bufferImpl->getSize())) >= static_cast<int>(totalCount)); gl::Error error = mStreamingBuffer->reserveVertexSpace( attrib, static_cast<GLsizei>(totalCount), instances); if (error.isError()) { return error; } } } return gl::Error(GL_NO_ERROR); }
void VertexDataManager::invalidateMatchingStaticData(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue) const { gl::Buffer *buffer = attrib.buffer.get(); if (buffer) { BufferD3D *bufferImpl = BufferD3D::makeBufferD3D(buffer->getImplementation()); StaticVertexBufferInterface *staticBuffer = bufferImpl->getStaticVertexBuffer(); if (staticBuffer && staticBuffer->getBufferSize() > 0 && !staticBuffer->lookupAttribute(attrib, NULL) && !staticBuffer->directStoragePossible(attrib, currentValue)) { bufferImpl->invalidateStaticData(); } } }
gl::Error VertexDataManager::reserveSpaceForAttrib(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, GLsizei count, GLsizei instances) const { gl::Buffer *buffer = attrib.buffer.get(); BufferD3D *bufferImpl = buffer ? BufferD3D::makeBufferD3D(buffer->getImplementation()) : NULL; StaticVertexBufferInterface *staticBuffer = bufferImpl ? bufferImpl->getStaticVertexBuffer() : NULL; VertexBufferInterface *vertexBuffer = staticBuffer ? staticBuffer : static_cast<VertexBufferInterface*>(mStreamingBuffer); if (!vertexBuffer->directStoragePossible(attrib, currentValue)) { if (staticBuffer) { if (staticBuffer->getBufferSize() == 0) { int totalCount = ElementsInBuffer(attrib, bufferImpl->getSize()); gl::Error error = staticBuffer->reserveVertexSpace(attrib, totalCount, 0); if (error.isError()) { return error; } } } else { int totalCount = StreamingBufferElementCount(attrib, count, instances); ASSERT(!bufferImpl || ElementsInBuffer(attrib, bufferImpl->getSize()) >= totalCount); gl::Error error = mStreamingBuffer->reserveVertexSpace(attrib, totalCount, instances); if (error.isError()) { return error; } } } return gl::Error(GL_NO_ERROR); }
gl::Error VertexDataManager::storeAttribute(TranslatedAttribute *translated, GLint start, GLsizei count, GLsizei instances) { const gl::VertexAttribute &attrib = *translated->attribute; gl::Buffer *buffer = attrib.buffer.get(); ASSERT(buffer || attrib.pointer); ASSERT(attrib.enabled); BufferD3D *storage = buffer ? GetImplAs<BufferD3D>(buffer) : NULL; StaticVertexBufferInterface *staticBuffer = storage ? storage->getStaticVertexBuffer(attrib) : NULL; VertexBufferInterface *vertexBuffer = staticBuffer ? staticBuffer : static_cast<VertexBufferInterface*>(mStreamingBuffer); bool directStorage = vertexBuffer->directStoragePossible(attrib, translated->currentValueType); // Instanced vertices do not apply the 'start' offset GLint firstVertexIndex = (instances > 0 && attrib.divisor > 0 ? 0 : start); translated->vertexBuffer = vertexBuffer->getVertexBuffer(); if (directStorage) { translated->storage = storage; translated->serial = storage->getSerial(); translated->stride = static_cast<unsigned int>(ComputeVertexAttributeStride(attrib)); translated->offset = static_cast<unsigned int>(attrib.offset + translated->stride * firstVertexIndex); return gl::Error(GL_NO_ERROR); } // Compute source data pointer const uint8_t *sourceData = nullptr; if (buffer) { gl::Error error = storage->getData(&sourceData); if (error.isError()) { return error; } sourceData += static_cast<int>(attrib.offset); } else { sourceData = static_cast<const uint8_t*>(attrib.pointer); } unsigned int streamOffset = 0; unsigned int outputElementSize = 0; if (staticBuffer) { gl::Error error = staticBuffer->getVertexBuffer()->getSpaceRequired(attrib, 1, 0, &outputElementSize); if (error.isError()) { return error; } if (!staticBuffer->lookupAttribute(attrib, &streamOffset)) { // Convert the entire buffer int totalCount = ElementsInBuffer(attrib, static_cast<unsigned int>(storage->getSize())); int startIndex = static_cast<int>(attrib.offset) / static_cast<int>(ComputeVertexAttributeStride(attrib)); error = staticBuffer->storeVertexAttributes(attrib, translated->currentValueType, -startIndex, totalCount, 0, &streamOffset, sourceData); if (error.isError()) { return error; } } unsigned int firstElementOffset = (static_cast<unsigned int>(attrib.offset) / static_cast<unsigned int>(ComputeVertexAttributeStride(attrib))) * outputElementSize; unsigned int startOffset = (instances == 0 || attrib.divisor == 0) ? firstVertexIndex * outputElementSize : 0; if (streamOffset + firstElementOffset + startOffset < streamOffset) { return gl::Error(GL_OUT_OF_MEMORY); } streamOffset += firstElementOffset + startOffset; } else { size_t totalCount = ComputeVertexAttributeElementCount(attrib, count, instances); gl::Error error = mStreamingBuffer->getVertexBuffer()->getSpaceRequired(attrib, 1, 0, &outputElementSize); if (error.isError()) { return error; } error = mStreamingBuffer->storeVertexAttributes( attrib, translated->currentValueType, firstVertexIndex, static_cast<GLsizei>(totalCount), instances, &streamOffset, sourceData); if (error.isError()) { return error; } } translated->storage = nullptr; translated->serial = vertexBuffer->getSerial(); translated->stride = outputElementSize; translated->offset = streamOffset; return gl::Error(GL_NO_ERROR); }
gl::Error VertexDataManager::prepareVertexData(const gl::State &state, GLint start, GLsizei count, std::vector<TranslatedAttribute> *translatedAttribs, GLsizei instances) { if (!mStreamingBuffer) { return gl::Error(GL_OUT_OF_MEMORY, "Internal streaming vertex buffer is unexpectedly NULL."); } // Compute active enabled and active disable attributes, for speed. // TODO(jmadill): don't recompute if there was no state change const gl::VertexArray *vertexArray = state.getVertexArray(); const gl::Program *program = state.getProgram(); const auto &vertexAttributes = vertexArray->getVertexAttributes(); mActiveEnabledAttributes.clear(); mActiveDisabledAttributes.clear(); translatedAttribs->clear(); for (size_t attribIndex = 0; attribIndex < vertexAttributes.size(); ++attribIndex) { if (program->isAttribLocationActive(attribIndex)) { // Resize automatically puts in empty attribs translatedAttribs->resize(attribIndex + 1); TranslatedAttribute *translated = &(*translatedAttribs)[attribIndex]; // Record the attribute now translated->active = true; translated->attribute = &vertexAttributes[attribIndex]; translated->currentValueType = state.getVertexAttribCurrentValue(static_cast<unsigned int>(attribIndex)).Type; translated->divisor = vertexAttributes[attribIndex].divisor; if (vertexAttributes[attribIndex].enabled) { mActiveEnabledAttributes.push_back(translated); } else { mActiveDisabledAttributes.push_back(attribIndex); } } } // Reserve the required space in the buffers for (const TranslatedAttribute *activeAttrib : mActiveEnabledAttributes) { gl::Error error = reserveSpaceForAttrib(*activeAttrib, count, instances); if (error.isError()) { return error; } } // Perform the vertex data translations for (TranslatedAttribute *activeAttrib : mActiveEnabledAttributes) { gl::Error error = storeAttribute(activeAttrib, start, count, instances); if (error.isError()) { hintUnmapAllResources(vertexAttributes); return error; } } for (size_t attribIndex : mActiveDisabledAttributes) { if (mCurrentValueCache[attribIndex].buffer == nullptr) { mCurrentValueCache[attribIndex].buffer = new StreamingVertexBufferInterface(mFactory, CONSTANT_VERTEX_BUFFER_SIZE); } gl::Error error = storeCurrentValue( state.getVertexAttribCurrentValue(static_cast<unsigned int>(attribIndex)), &(*translatedAttribs)[attribIndex], &mCurrentValueCache[attribIndex]); if (error.isError()) { hintUnmapAllResources(vertexAttributes); return error; } } // Commit all the static vertex buffers. This fixes them in size/contents, and forces ANGLE // to use a new static buffer (or recreate the static buffers) next time for (size_t attribIndex = 0; attribIndex < vertexAttributes.size(); ++attribIndex) { const gl::VertexAttribute &attrib = vertexAttributes[attribIndex]; gl::Buffer *buffer = attrib.buffer.get(); BufferD3D *storage = buffer ? GetImplAs<BufferD3D>(buffer) : nullptr; StaticVertexBufferInterface *staticBuffer = storage ? storage->getStaticVertexBuffer(attrib) : nullptr; if (staticBuffer) { staticBuffer->commit(); } } // Hint to unmap all the resources hintUnmapAllResources(vertexAttributes); for (const TranslatedAttribute *activeAttrib : mActiveEnabledAttributes) { gl::Buffer *buffer = activeAttrib->attribute->buffer.get(); if (buffer) { BufferD3D *bufferD3D = GetImplAs<BufferD3D>(buffer); size_t typeSize = ComputeVertexAttributeTypeSize(*activeAttrib->attribute); bufferD3D->promoteStaticUsage(count * static_cast<int>(typeSize)); } } return gl::Error(GL_NO_ERROR); }
gl::Error VertexDataManager::storeAttribute(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, TranslatedAttribute *translated, GLint start, GLsizei count, GLsizei instances) { gl::Buffer *buffer = attrib.buffer.get(); ASSERT(buffer || attrib.pointer); BufferD3D *storage = buffer ? BufferD3D::makeBufferD3D(buffer->getImplementation()) : NULL; StaticVertexBufferInterface *staticBuffer = storage ? storage->getStaticVertexBuffer() : NULL; VertexBufferInterface *vertexBuffer = staticBuffer ? staticBuffer : static_cast<VertexBufferInterface*>(mStreamingBuffer); bool directStorage = vertexBuffer->directStoragePossible(attrib, currentValue); unsigned int streamOffset = 0; unsigned int outputElementSize = 0; if (directStorage) { outputElementSize = ComputeVertexAttributeStride(attrib); streamOffset = attrib.offset + outputElementSize * start; } else if (staticBuffer) { gl::Error error = staticBuffer->getVertexBuffer()->getSpaceRequired(attrib, 1, 0, &outputElementSize); if (error.isError()) { return error; } if (!staticBuffer->lookupAttribute(attrib, &streamOffset)) { // Convert the entire buffer int totalCount = ElementsInBuffer(attrib, storage->getSize()); int startIndex = attrib.offset / ComputeVertexAttributeStride(attrib); gl::Error error = staticBuffer->storeVertexAttributes(attrib, currentValue, -startIndex, totalCount, 0, &streamOffset); if (error.isError()) { return error; } } unsigned int firstElementOffset = (attrib.offset / ComputeVertexAttributeStride(attrib)) * outputElementSize; unsigned int startOffset = (instances == 0 || attrib.divisor == 0) ? start * outputElementSize : 0; if (streamOffset + firstElementOffset + startOffset < streamOffset) { return gl::Error(GL_OUT_OF_MEMORY); } streamOffset += firstElementOffset + startOffset; } else { int totalCount = StreamingBufferElementCount(attrib, count, instances); gl::Error error = mStreamingBuffer->getVertexBuffer()->getSpaceRequired(attrib, 1, 0, &outputElementSize); if (error.isError()) { return error; } error = mStreamingBuffer->storeVertexAttributes(attrib, currentValue, start, totalCount, instances, &streamOffset); if (error.isError()) { return error; } } translated->storage = directStorage ? storage : NULL; translated->vertexBuffer = vertexBuffer->getVertexBuffer(); translated->serial = directStorage ? storage->getSerial() : vertexBuffer->getSerial(); translated->divisor = attrib.divisor; translated->attribute = &attrib; translated->currentValueType = currentValue.Type; translated->stride = outputElementSize; translated->offset = streamOffset; return gl::Error(GL_NO_ERROR); }