void VertexArray11::updateVertexAttribStorage(size_t attribIndex) { const auto &attrib = mData.getVertexAttribute(attribIndex); const auto &binding = mData.getBindingFromAttribIndex(attribIndex); // Note: having an unchanged storage type doesn't mean the attribute is clean. auto oldStorageType = mAttributeStorageTypes[attribIndex]; auto newStorageType = ClassifyAttributeStorage(attrib, binding); mAttributeStorageTypes[attribIndex] = newStorageType; if (newStorageType == VertexStorageType::DYNAMIC) { if (oldStorageType != VertexStorageType::DYNAMIC) { // Sync dynamic attribs in a different set. mAttribsToTranslate.reset(attribIndex); mDynamicAttribsMask.set(attribIndex); } } else { mAttribsToTranslate.set(attribIndex); if (oldStorageType == VertexStorageType::DYNAMIC) { ASSERT(mDynamicAttribsMask[attribIndex]); mDynamicAttribsMask.reset(attribIndex); } } gl::Buffer *oldBufferGL = mCurrentBuffers[attribIndex].get(); gl::Buffer *newBufferGL = binding.buffer.get(); Buffer11 *oldBuffer11 = oldBufferGL ? GetImplAs<Buffer11>(oldBufferGL) : nullptr; Buffer11 *newBuffer11 = newBufferGL ? GetImplAs<Buffer11>(newBufferGL) : nullptr; if (oldBuffer11 != newBuffer11 || oldStorageType != newStorageType) { // Note that for static callbacks, promotion to a static buffer from a dynamic buffer means // we need to tag dynamic buffers with static callbacks. OnBufferDataDirtyChannel *newChannel = nullptr; if (newBuffer11 != nullptr) { switch (newStorageType) { case VertexStorageType::DIRECT: newChannel = newBuffer11->getDirectBroadcastChannel(); break; case VertexStorageType::STATIC: case VertexStorageType::DYNAMIC: newChannel = newBuffer11->getStaticBroadcastChannel(); break; default: break; } } mOnBufferDataDirty[attribIndex].bind(newChannel); mCurrentBuffers[attribIndex] = binding.buffer; } }
gl::Error VertexDataManager::prepareVertexData(const gl::State &state, GLint start, GLsizei count, std::vector<TranslatedAttribute> *translatedAttribs, GLsizei instances) { ASSERT(mStreamingBuffer); const gl::VertexArray *vertexArray = state.getVertexArray(); const auto &vertexAttributes = vertexArray->getVertexAttributes(); mDynamicAttribsMaskCache.reset(); const gl::Program *program = state.getProgram(); translatedAttribs->clear(); for (size_t attribIndex = 0; attribIndex < vertexAttributes.size(); ++attribIndex) { // Skip attrib locations the program doesn't use. if (!program->isAttribLocationActive(attribIndex)) continue; const auto &attrib = vertexAttributes[attribIndex]; // Resize automatically puts in empty attribs translatedAttribs->resize(attribIndex + 1); TranslatedAttribute *translated = &(*translatedAttribs)[attribIndex]; auto currentValueData = state.getVertexAttribCurrentValue(static_cast<unsigned int>(attribIndex)); // Record the attribute now translated->active = true; translated->attribute = &attrib; translated->currentValueType = currentValueData.Type; translated->divisor = attrib.divisor; switch (ClassifyAttributeStorage(attrib)) { case VertexStorageType::STATIC: { // Store static attribute. gl::Error error = StoreStaticAttrib(translated, start, count, instances); if (error.isError()) { return error; } break; } case VertexStorageType::DYNAMIC: // Dynamic attributes must be handled together. mDynamicAttribsMaskCache.set(attribIndex); break; case VertexStorageType::DIRECT: // Update translated data for direct attributes. StoreDirectAttrib(translated, start); break; case VertexStorageType::CURRENT_VALUE: { gl::Error error = storeCurrentValue(currentValueData, translated, attribIndex); if (error.isError()) { return error; } break; } default: UNREACHABLE(); break; } } if (mDynamicAttribsMaskCache.none()) { gl::Error(GL_NO_ERROR); } return storeDynamicAttribs(translatedAttribs, mDynamicAttribsMaskCache, start, count, instances); }
angle::Result VertexDataManager::prepareVertexData( const gl::Context *context, GLint start, GLsizei count, std::vector<TranslatedAttribute> *translatedAttribs, GLsizei instances) { const gl::State &state = context->getGLState(); const gl::VertexArray *vertexArray = state.getVertexArray(); const auto &vertexAttributes = vertexArray->getVertexAttributes(); const auto &vertexBindings = vertexArray->getVertexBindings(); mDynamicAttribsMaskCache.reset(); const gl::Program *program = state.getProgram(); translatedAttribs->clear(); for (size_t attribIndex = 0; attribIndex < vertexAttributes.size(); ++attribIndex) { // Skip attrib locations the program doesn't use. if (!program->isAttribLocationActive(attribIndex)) continue; const auto &attrib = vertexAttributes[attribIndex]; const auto &binding = vertexBindings[attrib.bindingIndex]; // Resize automatically puts in empty attribs translatedAttribs->resize(attribIndex + 1); TranslatedAttribute *translated = &(*translatedAttribs)[attribIndex]; auto currentValueData = state.getVertexAttribCurrentValue(attribIndex); // Record the attribute now translated->active = true; translated->attribute = &attrib; translated->binding = &binding; translated->currentValueType = currentValueData.Type; translated->divisor = binding.getDivisor(); switch (ClassifyAttributeStorage(context, attrib, binding)) { case VertexStorageType::STATIC: { // Store static attribute. ANGLE_TRY(StoreStaticAttrib(context, translated)); break; } case VertexStorageType::DYNAMIC: // Dynamic attributes must be handled together. mDynamicAttribsMaskCache.set(attribIndex); break; case VertexStorageType::DIRECT: // Update translated data for direct attributes. StoreDirectAttrib(context, translated); break; case VertexStorageType::CURRENT_VALUE: { ANGLE_TRY(storeCurrentValue(context, currentValueData, translated, attribIndex)); break; } default: UNREACHABLE(); break; } } if (mDynamicAttribsMaskCache.none()) { return angle::Result::Continue(); } ANGLE_TRY(storeDynamicAttribs(context, translatedAttribs, mDynamicAttribsMaskCache, start, count, instances)); PromoteDynamicAttribs(context, *translatedAttribs, mDynamicAttribsMaskCache, count); return angle::Result::Continue(); }