blob: fed21f8f737d88d2f49bb08bcecb01e9c495be3f [file] [log] [blame]
//
// 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/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()),
mCurrentBuffers(data.getMaxAttribs()),
mAppliedNumViewsToDivisor(1)
{
for (size_t attribIndex = 0; attribIndex < mCurrentBuffers.size(); ++attribIndex)
{
mOnBufferDataDirty.emplace_back(this, attribIndex);
}
}
void VertexArray11::destroy(const gl::Context *context)
{
for (auto &buffer : mCurrentBuffers)
{
if (buffer.get())
{
buffer.set(context, nullptr);
}
}
}
void VertexArray11::syncState(const gl::Context *context,
const gl::VertexArray::DirtyBits &dirtyBits)
{
ASSERT(dirtyBits.any());
// 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.
auto renderer = GetImplAs<Context11>(context)->getRenderer();
mCurrentStateSerial = renderer->generateSerial();
// TODO(jmadill): Individual attribute invalidation.
renderer->getStateManager()->invalidateVertexBuffer();
for (auto dirtyBit : dirtyBits)
{
if (dirtyBit == gl::VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER)
continue;
size_t index = gl::VertexArray::GetVertexIndexFromDirtyBit(dirtyBit);
// TODO(jiawei.shao@intel.com): Vertex Attrib Bindings
ASSERT(index == mData.getBindingIndexFromAttribIndex(index));
mAttribsToUpdate.set(index);
}
}
void VertexArray11::flushAttribUpdates(const gl::Context *context)
{
const gl::Program *program = context->getGLState().getProgram();
const auto &activeLocations = program->getActiveAttribLocationsMask();
if (mAttribsToUpdate.any())
{
// Skip attrib locations the program doesn't use.
gl::AttributesMask activeToUpdate = mAttribsToUpdate & activeLocations;
for (auto toUpdateIndex : activeToUpdate)
{
mAttribsToUpdate.reset(toUpdateIndex);
updateVertexAttribStorage(context, toUpdateIndex);
}
}
}
void VertexArray11::updateVertexAttribStorage(const gl::Context *context, 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.getBuffer().get();
Buffer11 *oldBuffer11 = oldBufferGL ? GetImplAs<Buffer11>(oldBufferGL) : nullptr;
Buffer11 *newBuffer11 = newBufferGL ? GetImplAs<Buffer11>(newBufferGL) : nullptr;
StateManager11 *stateManager = GetImplAs<Context11>(context)->getRenderer()->getStateManager();
if (oldBuffer11 != newBuffer11 || oldStorageType != newStorageType)
{
OnBufferDataDirtyChannel *newChannel = nullptr;
if (newStorageType == VertexStorageType::CURRENT_VALUE)
{
stateManager->invalidateCurrentValueAttrib(attribIndex);
}
else if (newBuffer11 != nullptr)
{
// Note that for static callbacks, promotion to a static buffer from a dynamic buffer
// means we need to tag dynamic buffers with static callbacks.
switch (newStorageType)
{
case VertexStorageType::DIRECT:
newChannel = newBuffer11->getDirectBroadcastChannel();
break;
case VertexStorageType::STATIC:
case VertexStorageType::DYNAMIC:
newChannel = newBuffer11->getStaticBroadcastChannel();
break;
default:
UNREACHABLE();
break;
}
}
mOnBufferDataDirty[attribIndex].bind(newChannel);
mCurrentBuffers[attribIndex].set(context, binding.getBuffer().get());
}
}
bool VertexArray11::hasDynamicAttrib(const gl::Context *context)
{
flushAttribUpdates(context);
return mDynamicAttribsMask.any();
}
bool VertexArray11::hasDirtyOrDynamicAttrib(const gl::Context *context)
{
flushAttribUpdates(context);
return mAttribsToTranslate.any() || mDynamicAttribsMask.any();
}
gl::Error VertexArray11::updateDirtyAndDynamicAttribs(const gl::Context *context,
VertexDataManager *vertexDataManager,
GLint start,
GLsizei count,
GLsizei instances)
{
flushAttribUpdates(context);
const auto &glState = context->getGLState();
const gl::Program *program = glState.getProgram();
const auto &activeLocations = program->getActiveAttribLocationsMask();
const auto &attribs = mData.getVertexAttributes();
const auto &bindings = mData.getVertexBindings();
mAppliedNumViewsToDivisor =
(program != nullptr && program->usesMultiview()) ? program->getNumViews() : 1;
if (mAttribsToTranslate.any())
{
// Skip attrib locations the program doesn't use, saving for the next frame.
gl::AttributesMask dirtyActiveAttribs = (mAttribsToTranslate & activeLocations);
for (auto dirtyAttribIndex : dirtyActiveAttribs)
{
mAttribsToTranslate.reset(dirtyAttribIndex);
auto *translatedAttrib = &mTranslatedAttribs[dirtyAttribIndex];
const auto &currentValue = 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(translatedAttrib);
break;
case VertexStorageType::STATIC:
{
ANGLE_TRY(VertexDataManager::StoreStaticAttrib(translatedAttrib));
break;
}
case VertexStorageType::CURRENT_VALUE:
// Current value attribs are managed by the StateManager11.
break;
default:
UNREACHABLE();
break;
}
}
}
if (mDynamicAttribsMask.any())
{
auto activeDynamicAttribs = (mDynamicAttribsMask & activeLocations);
for (auto dynamicAttribIndex : activeDynamicAttribs)
{
auto *dynamicAttrib = &mTranslatedAttribs[dynamicAttribIndex];
const auto &currentValue = 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(&mTranslatedAttribs, activeDynamicAttribs,
start, count, instances));
}
return gl::NoError();
}
const std::vector<TranslatedAttribute> &VertexArray11::getTranslatedAttribs() const
{
return mTranslatedAttribs;
}
void VertexArray11::signal(size_t channelID)
{
ASSERT(mAttributeStorageTypes[channelID] != VertexStorageType::CURRENT_VALUE);
// This can change a buffer's storage, we'll need to re-check.
mAttribsToUpdate.set(channelID);
}
void VertexArray11::clearDirtyAndPromoteDynamicAttribs(const gl::State &state, GLsizei count)
{
const gl::Program *program = state.getProgram();
const auto &activeLocations = program->getActiveAttribLocationsMask();
mAttribsToUpdate &= ~activeLocations;
// Promote to static after we clear the dirty attributes, otherwise we can lose dirtyness.
auto activeDynamicAttribs = (mDynamicAttribsMask & activeLocations);
VertexDataManager::PromoteDynamicAttribs(mTranslatedAttribs, activeDynamicAttribs, count);
}
void VertexArray11::markAllAttributeDivisorsForAdjustment(int numViews)
{
if (mAppliedNumViewsToDivisor != numViews)
{
mAppliedNumViewsToDivisor = numViews;
mAttribsToUpdate.set();
}
}
} // namespace rx