| // |
| // Copyright 2016 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. |
| // |
| // VertexArray11: |
| // Implementation of rx::VertexArray11. |
| // |
| |
| #include "libANGLE/renderer/d3d/d3d11/VertexArray11.h" |
| |
| #include "common/bitset_utils.h" |
| #include "libANGLE/Context.h" |
| #include "libANGLE/renderer/d3d/IndexBuffer.h" |
| #include "libANGLE/renderer/d3d/d3d11/Buffer11.h" |
| #include "libANGLE/renderer/d3d/d3d11/Context11.h" |
| |
| using namespace angle; |
| |
| namespace rx |
| { |
| VertexArray11::VertexArray11(const gl::VertexArrayState &data) |
| : VertexArrayImpl(data), |
| mAttributeStorageTypes(data.getMaxAttribs(), VertexStorageType::CURRENT_VALUE), |
| mTranslatedAttribs(data.getMaxAttribs()), |
| mAppliedNumViewsToDivisor(1), |
| mCurrentElementArrayStorage(IndexStorageType::Invalid), |
| mCachedDestinationIndexType(gl::DrawElementsType::InvalidEnum) |
| {} |
| |
| VertexArray11::~VertexArray11() {} |
| |
| void VertexArray11::destroy(const gl::Context *context) {} |
| |
| // As VertexAttribPointer can modify both attribute and binding, we should also set other attributes |
| // that are also using this binding dirty. |
| #define ANGLE_VERTEX_DIRTY_ATTRIB_FUNC(INDEX) \ |
| case gl::VertexArray::DIRTY_BIT_ATTRIB_0 + INDEX: \ |
| if ((*attribBits)[INDEX][gl::VertexArray::DirtyAttribBitType::DIRTY_ATTRIB_POINTER]) \ |
| { \ |
| attributesToUpdate |= mState.getBindingToAttributesMask(INDEX); \ |
| } \ |
| else \ |
| { \ |
| attributesToUpdate.set(INDEX); \ |
| } \ |
| invalidateVertexBuffer = true; \ |
| (*attribBits)[INDEX].reset(); \ |
| break; |
| |
| #define ANGLE_VERTEX_DIRTY_BINDING_FUNC(INDEX) \ |
| case gl::VertexArray::DIRTY_BIT_BINDING_0 + INDEX: \ |
| attributesToUpdate |= mState.getBindingToAttributesMask(INDEX); \ |
| invalidateVertexBuffer = true; \ |
| (*bindingBits)[INDEX].reset(); \ |
| break; |
| |
| #define ANGLE_VERTEX_DIRTY_BUFFER_DATA_FUNC(INDEX) \ |
| case gl::VertexArray::DIRTY_BIT_BUFFER_DATA_0 + INDEX: \ |
| if (mAttributeStorageTypes[INDEX] == VertexStorageType::STATIC) \ |
| { \ |
| invalidateVertexBuffer = true; \ |
| mAttribsToTranslate.set(INDEX); \ |
| } \ |
| break; |
| |
| angle::Result VertexArray11::syncState(const gl::Context *context, |
| const gl::VertexArray::DirtyBits &dirtyBits, |
| gl::VertexArray::DirtyAttribBitsArray *attribBits, |
| gl::VertexArray::DirtyBindingBitsArray *bindingBits) |
| { |
| ASSERT(dirtyBits.any()); |
| |
| Renderer11 *renderer = GetImplAs<Context11>(context)->getRenderer(); |
| StateManager11 *stateManager = renderer->getStateManager(); |
| |
| // Generate a state serial. This serial is used in the program class to validate the cached |
| // input layout, and skip recomputation in the fast path. |
| mCurrentStateSerial = renderer->generateSerial(); |
| |
| bool invalidateVertexBuffer = false; |
| |
| gl::AttributesMask attributesToUpdate; |
| |
| // Make sure we trigger re-translation for static index or vertex data. |
| for (size_t dirtyBit : dirtyBits) |
| { |
| switch (dirtyBit) |
| { |
| case gl::VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER: |
| case gl::VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER_DATA: |
| { |
| mLastDrawElementsType.reset(); |
| mLastDrawElementsIndices.reset(); |
| mLastPrimitiveRestartEnabled.reset(); |
| mCachedIndexInfo.reset(); |
| break; |
| } |
| |
| ANGLE_VERTEX_INDEX_CASES(ANGLE_VERTEX_DIRTY_ATTRIB_FUNC) |
| ANGLE_VERTEX_INDEX_CASES(ANGLE_VERTEX_DIRTY_BINDING_FUNC) |
| ANGLE_VERTEX_INDEX_CASES(ANGLE_VERTEX_DIRTY_BUFFER_DATA_FUNC) |
| |
| default: |
| UNREACHABLE(); |
| break; |
| } |
| } |
| |
| for (size_t attribIndex : attributesToUpdate) |
| { |
| updateVertexAttribStorage(context, stateManager, attribIndex); |
| } |
| |
| if (invalidateVertexBuffer) |
| { |
| // TODO(jmadill): Individual attribute invalidation. |
| stateManager->invalidateVertexBuffer(); |
| } |
| |
| return angle::Result::Continue; |
| } |
| |
| angle::Result VertexArray11::syncStateForDraw(const gl::Context *context, |
| GLint firstVertex, |
| GLsizei vertexOrIndexCount, |
| gl::DrawElementsType indexTypeOrInvalid, |
| const void *indices, |
| GLsizei instances, |
| GLint baseVertex) |
| { |
| Renderer11 *renderer = GetImplAs<Context11>(context)->getRenderer(); |
| StateManager11 *stateManager = renderer->getStateManager(); |
| |
| const gl::State &glState = context->getState(); |
| const gl::Program *program = glState.getProgram(); |
| ASSERT(program); |
| mAppliedNumViewsToDivisor = (program->usesMultiview() ? program->getNumViews() : 1); |
| |
| if (mAttribsToTranslate.any()) |
| { |
| const gl::AttributesMask &activeLocations = |
| glState.getProgram()->getActiveAttribLocationsMask(); |
| gl::AttributesMask activeDirtyAttribs = (mAttribsToTranslate & activeLocations); |
| if (activeDirtyAttribs.any()) |
| { |
| ANGLE_TRY(updateDirtyAttribs(context, activeDirtyAttribs)); |
| stateManager->invalidateInputLayout(); |
| } |
| } |
| |
| if (mDynamicAttribsMask.any()) |
| { |
| const gl::AttributesMask &activeLocations = |
| glState.getProgram()->getActiveAttribLocationsMask(); |
| gl::AttributesMask activeDynamicAttribs = (mDynamicAttribsMask & activeLocations); |
| |
| if (activeDynamicAttribs.any()) |
| { |
| ANGLE_TRY(updateDynamicAttribs(context, stateManager->getVertexDataManager(), |
| firstVertex, vertexOrIndexCount, indexTypeOrInvalid, |
| indices, instances, baseVertex, activeDynamicAttribs)); |
| stateManager->invalidateInputLayout(); |
| } |
| } |
| |
| if (indexTypeOrInvalid != gl::DrawElementsType::InvalidEnum) |
| { |
| bool restartEnabled = context->getState().isPrimitiveRestartEnabled(); |
| if (!mLastDrawElementsType.valid() || mLastDrawElementsType.value() != indexTypeOrInvalid || |
| mLastDrawElementsIndices.value() != indices || |
| mLastPrimitiveRestartEnabled.value() != restartEnabled) |
| { |
| mLastDrawElementsType = indexTypeOrInvalid; |
| mLastDrawElementsIndices = indices; |
| mLastPrimitiveRestartEnabled = restartEnabled; |
| |
| ANGLE_TRY(updateElementArrayStorage(context, vertexOrIndexCount, indexTypeOrInvalid, |
| indices, restartEnabled)); |
| stateManager->invalidateIndexBuffer(); |
| } |
| else if (mCurrentElementArrayStorage == IndexStorageType::Dynamic) |
| { |
| stateManager->invalidateIndexBuffer(); |
| } |
| } |
| |
| return angle::Result::Continue; |
| } |
| |
| angle::Result VertexArray11::updateElementArrayStorage(const gl::Context *context, |
| GLsizei indexCount, |
| gl::DrawElementsType indexType, |
| const void *indices, |
| bool restartEnabled) |
| { |
| bool usePrimitiveRestartWorkaround = UsePrimitiveRestartWorkaround(restartEnabled, indexType); |
| |
| ANGLE_TRY(GetIndexTranslationDestType(context, indexCount, indexType, indices, |
| usePrimitiveRestartWorkaround, |
| &mCachedDestinationIndexType)); |
| |
| unsigned int offset = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(indices)); |
| |
| mCurrentElementArrayStorage = |
| ClassifyIndexStorage(context->getState(), mState.getElementArrayBuffer(), indexType, |
| mCachedDestinationIndexType, offset); |
| |
| return angle::Result::Continue; |
| } |
| |
| void VertexArray11::updateVertexAttribStorage(const gl::Context *context, |
| StateManager11 *stateManager, |
| size_t attribIndex) |
| { |
| const gl::VertexAttribute &attrib = mState.getVertexAttribute(attribIndex); |
| const gl::VertexBinding &binding = mState.getBindingFromAttribIndex(attribIndex); |
| |
| VertexStorageType newStorageType = ClassifyAttributeStorage(context, attrib, binding); |
| |
| // Note: having an unchanged storage type doesn't mean the attribute is clean. |
| mAttribsToTranslate.set(attribIndex, newStorageType != VertexStorageType::DYNAMIC); |
| |
| if (mAttributeStorageTypes[attribIndex] == newStorageType) |
| return; |
| |
| mAttributeStorageTypes[attribIndex] = newStorageType; |
| mDynamicAttribsMask.set(attribIndex, newStorageType == VertexStorageType::DYNAMIC); |
| |
| if (newStorageType == VertexStorageType::CURRENT_VALUE) |
| { |
| stateManager->invalidateCurrentValueAttrib(attribIndex); |
| } |
| } |
| |
| bool VertexArray11::hasActiveDynamicAttrib(const gl::Context *context) |
| { |
| const auto &activeLocations = context->getState().getProgram()->getActiveAttribLocationsMask(); |
| gl::AttributesMask activeDynamicAttribs = (mDynamicAttribsMask & activeLocations); |
| return activeDynamicAttribs.any(); |
| } |
| |
| angle::Result VertexArray11::updateDirtyAttribs(const gl::Context *context, |
| const gl::AttributesMask &activeDirtyAttribs) |
| { |
| const auto &glState = context->getState(); |
| const auto &attribs = mState.getVertexAttributes(); |
| const auto &bindings = mState.getVertexBindings(); |
| |
| for (size_t dirtyAttribIndex : activeDirtyAttribs) |
| { |
| mAttribsToTranslate.reset(dirtyAttribIndex); |
| |
| auto *translatedAttrib = &mTranslatedAttribs[dirtyAttribIndex]; |
| const auto ¤tValue = glState.getVertexAttribCurrentValue(dirtyAttribIndex); |
| |
| // Record basic attrib info |
| translatedAttrib->attribute = &attribs[dirtyAttribIndex]; |
| translatedAttrib->binding = &bindings[translatedAttrib->attribute->bindingIndex]; |
| translatedAttrib->currentValueType = currentValue.Type; |
| translatedAttrib->divisor = |
| translatedAttrib->binding->getDivisor() * mAppliedNumViewsToDivisor; |
| |
| switch (mAttributeStorageTypes[dirtyAttribIndex]) |
| { |
| case VertexStorageType::DIRECT: |
| VertexDataManager::StoreDirectAttrib(context, translatedAttrib); |
| break; |
| case VertexStorageType::STATIC: |
| { |
| ANGLE_TRY(VertexDataManager::StoreStaticAttrib(context, translatedAttrib)); |
| break; |
| } |
| case VertexStorageType::CURRENT_VALUE: |
| // Current value attribs are managed by the StateManager11. |
| break; |
| default: |
| UNREACHABLE(); |
| break; |
| } |
| } |
| |
| return angle::Result::Continue; |
| } |
| |
| angle::Result VertexArray11::updateDynamicAttribs(const gl::Context *context, |
| VertexDataManager *vertexDataManager, |
| GLint firstVertex, |
| GLsizei vertexOrIndexCount, |
| gl::DrawElementsType indexTypeOrInvalid, |
| const void *indices, |
| GLsizei instances, |
| GLint baseVertex, |
| const gl::AttributesMask &activeDynamicAttribs) |
| { |
| const auto &glState = context->getState(); |
| const auto &attribs = mState.getVertexAttributes(); |
| const auto &bindings = mState.getVertexBindings(); |
| |
| GLint startVertex; |
| size_t vertexCount; |
| ANGLE_TRY(GetVertexRangeInfo(context, firstVertex, vertexOrIndexCount, indexTypeOrInvalid, |
| indices, baseVertex, &startVertex, &vertexCount)); |
| |
| for (size_t dynamicAttribIndex : activeDynamicAttribs) |
| { |
| auto *dynamicAttrib = &mTranslatedAttribs[dynamicAttribIndex]; |
| const auto ¤tValue = glState.getVertexAttribCurrentValue(dynamicAttribIndex); |
| |
| // Record basic attrib info |
| dynamicAttrib->attribute = &attribs[dynamicAttribIndex]; |
| dynamicAttrib->binding = &bindings[dynamicAttrib->attribute->bindingIndex]; |
| dynamicAttrib->currentValueType = currentValue.Type; |
| dynamicAttrib->divisor = dynamicAttrib->binding->getDivisor() * mAppliedNumViewsToDivisor; |
| } |
| |
| ANGLE_TRY(vertexDataManager->storeDynamicAttribs( |
| context, &mTranslatedAttribs, activeDynamicAttribs, startVertex, vertexCount, instances)); |
| |
| VertexDataManager::PromoteDynamicAttribs(context, mTranslatedAttribs, activeDynamicAttribs, |
| vertexCount); |
| |
| return angle::Result::Continue; |
| } |
| |
| const std::vector<TranslatedAttribute> &VertexArray11::getTranslatedAttribs() const |
| { |
| return mTranslatedAttribs; |
| } |
| |
| void VertexArray11::markAllAttributeDivisorsForAdjustment(int numViews) |
| { |
| if (mAppliedNumViewsToDivisor != numViews) |
| { |
| mAppliedNumViewsToDivisor = numViews; |
| mAttribsToTranslate.set(); |
| // mDynamicAttribsMask may have already been set (updateVertexAttribStorage |
| // We don't want to override DYNAMIC attribs as they will be handled separately. |
| mAttribsToTranslate = mAttribsToTranslate ^ mDynamicAttribsMask; |
| } |
| } |
| |
| const TranslatedIndexData &VertexArray11::getCachedIndexInfo() const |
| { |
| ASSERT(mCachedIndexInfo.valid()); |
| return mCachedIndexInfo.value(); |
| } |
| |
| void VertexArray11::updateCachedIndexInfo(const TranslatedIndexData &indexInfo) |
| { |
| mCachedIndexInfo = indexInfo; |
| } |
| |
| bool VertexArray11::isCachedIndexInfoValid() const |
| { |
| return mCachedIndexInfo.valid(); |
| } |
| |
| gl::DrawElementsType VertexArray11::getCachedDestinationIndexType() const |
| { |
| return mCachedDestinationIndexType; |
| } |
| |
| } // namespace rx |