Commit 0946393d by Jamie Madill Committed by Commit Bot

Move Buffer Subject/Observer to front end.

This makes BufferImpl into an Observer Subject. It also refactors the Vertex Array updates for the D3D11 backend use more of a dirty bit coding style. This change makes it so Buffer contents changes trigger front-end dirty bits from the back-end, which may be undesirable. Bug: angleproject:2389 Change-Id: Iac8ce1171284a86851c18cd1373ddf24fcefe40b Reviewed-on: https://chromium-review.googlesource.com/979812 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 59c5b897
......@@ -64,8 +64,7 @@ class BitSetT final
};
BitSetT();
BitSetT(BitsT value);
~BitSetT();
constexpr explicit BitSetT(BitsT value);
BitSetT(const BitSetT &other);
BitSetT &operator=(const BitSetT &other);
......@@ -90,6 +89,10 @@ class BitSetT final
BitSetT &operator^=(const BitSetT &other);
BitSetT operator~() const;
BitSetT &operator&=(BitsT value);
BitSetT &operator|=(BitsT value);
BitSetT &operator^=(BitsT value);
BitSetT operator<<(std::size_t pos) const;
BitSetT &operator<<=(std::size_t pos);
BitSetT operator>>(std::size_t pos) const;
......@@ -115,6 +118,7 @@ class BitSetT final
{
return (static_cast<BitsT>(1) << static_cast<size_t>(x));
}
// Produces a mask of ones up to the "x"th bit.
constexpr static BitsT Mask(std::size_t x)
{
return ((Bit(static_cast<ParamT>(x - 1)) - 1) << 1) + 1;
......@@ -216,12 +220,7 @@ BitSetT<N, BitsT, ParamT>::BitSetT() : mBits(0)
}
template <size_t N, typename BitsT, typename ParamT>
BitSetT<N, BitsT, ParamT>::BitSetT(BitsT value) : mBits(value & Mask(N))
{
}
template <size_t N, typename BitsT, typename ParamT>
BitSetT<N, BitsT, ParamT>::~BitSetT()
constexpr BitSetT<N, BitsT, ParamT>::BitSetT(BitsT value) : mBits(value & Mask(N))
{
}
......@@ -316,6 +315,27 @@ BitSetT<N, BitsT, ParamT> BitSetT<N, BitsT, ParamT>::operator~() const
}
template <size_t N, typename BitsT, typename ParamT>
BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::operator&=(BitsT value)
{
mBits &= value;
return *this;
}
template <size_t N, typename BitsT, typename ParamT>
BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::operator|=(BitsT value)
{
mBits |= value;
return *this;
}
template <size_t N, typename BitsT, typename ParamT>
BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::operator^=(BitsT value)
{
mBits ^= value;
return *this;
}
template <size_t N, typename BitsT, typename ParamT>
BitSetT<N, BitsT, ParamT> BitSetT<N, BitsT, ParamT>::operator<<(std::size_t pos) const
{
return BitSetT<N, BitsT, ParamT>((mBits << pos) & Mask(N));
......
......@@ -88,6 +88,9 @@ Error Buffer::bufferData(const Context *context,
mState.mUsage = usage;
mState.mSize = size;
// Notify when data changes.
mImpl->onStateChange(context, angle::SubjectMessage::CONTENTS_CHANGED);
return NoError();
}
......@@ -101,6 +104,9 @@ Error Buffer::bufferSubData(const Context *context,
mIndexRangeCache.invalidateRange(static_cast<unsigned int>(offset), static_cast<unsigned int>(size));
// Notify when data changes.
mImpl->onStateChange(context, angle::SubjectMessage::CONTENTS_CHANGED);
return NoError();
}
......@@ -115,6 +121,9 @@ Error Buffer::copyBufferSubData(const Context *context,
mIndexRangeCache.invalidateRange(static_cast<unsigned int>(destOffset), static_cast<unsigned int>(size));
// Notify when data changes.
mImpl->onStateChange(context, angle::SubjectMessage::CONTENTS_CHANGED);
return NoError();
}
......@@ -181,17 +190,26 @@ Error Buffer::unmap(const Context *context, GLboolean *result)
mState.mAccess = GL_WRITE_ONLY_OES;
mState.mAccessFlags = 0;
// Notify when data changes.
mImpl->onStateChange(context, angle::SubjectMessage::CONTENTS_CHANGED);
return NoError();
}
void Buffer::onTransformFeedback()
void Buffer::onTransformFeedback(const Context *context)
{
mIndexRangeCache.clear();
// Notify when data changes.
mImpl->onStateChange(context, angle::SubjectMessage::CONTENTS_CHANGED);
}
void Buffer::onPixelUnpack()
void Buffer::onPixelPack(const Context *context)
{
mIndexRangeCache.clear();
// Notify when data changes.
mImpl->onStateChange(context, angle::SubjectMessage::CONTENTS_CHANGED);
}
Error Buffer::getIndexRange(const gl::Context *context,
......
......@@ -92,8 +92,9 @@ class Buffer final : public RefCountObject, public LabeledObject
Error mapRange(const Context *context, GLintptr offset, GLsizeiptr length, GLbitfield access);
Error unmap(const Context *context, GLboolean *result);
void onTransformFeedback();
void onPixelUnpack();
// These are called when another operation changes Buffer data.
void onTransformFeedback(const Context *context);
void onPixelPack(const Context *context);
Error getIndexRange(const gl::Context *context,
GLenum type,
......
......@@ -129,13 +129,14 @@ gl::Error GetQueryObjectParameter(gl::Query *query, GLenum pname, T *params)
}
}
void MarkTransformFeedbackBufferUsage(gl::TransformFeedback *transformFeedback,
void MarkTransformFeedbackBufferUsage(const gl::Context *context,
gl::TransformFeedback *transformFeedback,
GLsizei count,
GLsizei instanceCount)
{
if (transformFeedback && transformFeedback->isActive() && !transformFeedback->isPaused())
{
transformFeedback->onVerticesDrawn(count, instanceCount);
transformFeedback->onVerticesDrawn(context, count, instanceCount);
}
}
......@@ -1804,7 +1805,7 @@ void Context::drawArrays(GLenum mode, GLint first, GLsizei count)
ANGLE_CONTEXT_TRY(prepareForDraw());
ANGLE_CONTEXT_TRY(mImplementation->drawArrays(this, mode, first, count));
MarkTransformFeedbackBufferUsage(mGLState.getCurrentTransformFeedback(), count, 1);
MarkTransformFeedbackBufferUsage(this, mGLState.getCurrentTransformFeedback(), count, 1);
}
void Context::drawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount)
......@@ -1818,7 +1819,8 @@ void Context::drawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsiz
ANGLE_CONTEXT_TRY(prepareForDraw());
ANGLE_CONTEXT_TRY(
mImplementation->drawArraysInstanced(this, mode, first, count, instanceCount));
MarkTransformFeedbackBufferUsage(mGLState.getCurrentTransformFeedback(), count, instanceCount);
MarkTransformFeedbackBufferUsage(this, mGLState.getCurrentTransformFeedback(), count,
instanceCount);
}
void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const void *indices)
......
......@@ -1388,7 +1388,7 @@ Error Framebuffer::readPixels(const Context *context,
Buffer *unpackBuffer = context->getGLState().getTargetBuffer(BufferBinding::PixelUnpack);
if (unpackBuffer)
{
unpackBuffer->onPixelUnpack();
unpackBuffer->onPixelPack(context);
}
return NoError();
......
......@@ -244,11 +244,11 @@ LinkResult MemoryProgramCache::Deserialize(const Context *context,
static_assert(MAX_VERTEX_ATTRIBS * 2 <= sizeof(uint32_t) * 8,
"All bits of mAttributesTypeMask types and mask fit into 32 bits each");
state->mAttributesTypeMask.from_ulong(stream.readInt<uint32_t>());
state->mAttributesMask = stream.readInt<uint32_t>();
state->mAttributesMask = stream.readInt<gl::AttributesMask>();
static_assert(MAX_VERTEX_ATTRIBS <= sizeof(unsigned long) * 8,
"Too many vertex attribs for mask");
state->mActiveAttribLocationsMask = stream.readInt<unsigned long>();
state->mActiveAttribLocationsMask = stream.readInt<gl::AttributesMask>();
unsigned int attribCount = stream.readInt<unsigned int>();
ASSERT(state->mAttributes.empty());
......@@ -390,7 +390,7 @@ LinkResult MemoryProgramCache::Deserialize(const Context *context,
"All bits of mDrawBufferTypeMask and mActiveOutputVariables types and mask fit "
"into 32 bits each");
state->mDrawBufferTypeMask.from_ulong(stream.readInt<uint32_t>());
state->mActiveOutputVariables = stream.readInt<uint32_t>();
state->mActiveOutputVariables = stream.readInt<gl::DrawBufferMask>();
unsigned int samplerRangeLow = stream.readInt<unsigned int>();
unsigned int samplerRangeHigh = stream.readInt<unsigned int>();
......@@ -426,7 +426,7 @@ LinkResult MemoryProgramCache::Deserialize(const Context *context,
static_assert(static_cast<unsigned long>(ShaderType::EnumCount) <= sizeof(unsigned long) * 8,
"Too many shader types");
state->mLinkedShaderStages = stream.readInt<unsigned long>();
state->mLinkedShaderStages = stream.readInt<gl::ShaderStagesMask>();
state->updateTransformFeedbackStrides();
......
......@@ -2679,6 +2679,14 @@ void State::setFramebufferDirty(const Framebuffer *framebuffer) const
}
}
void State::setVertexArrayDirty(const VertexArray *vertexArray) const
{
if (vertexArray == mVertexArray)
{
mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY);
}
}
void State::onProgramExecutableChange(Program *program)
{
// OpenGL Spec:
......
......@@ -446,6 +446,7 @@ class State : public angle::ObserverInterface, angle::NonCopyable
Error syncDirtyObject(const Context *context, GLenum target);
void setObjectDirty(GLenum target);
void setFramebufferDirty(const Framebuffer *framebuffer) const;
void setVertexArrayDirty(const VertexArray *vertexArray) const;
// This actually clears the current value dirty bits.
// TODO(jmadill): Pass mutable dirty bits into Impl.
......
......@@ -191,7 +191,7 @@ bool TransformFeedback::checkBufferSpaceForDraw(GLsizei count, GLsizei primcount
return vertices.IsValid() && vertices.ValueOrDie() <= mState.mVertexCapacity;
}
void TransformFeedback::onVerticesDrawn(GLsizei count, GLsizei primcount)
void TransformFeedback::onVerticesDrawn(const Context *context, GLsizei count, GLsizei primcount)
{
ASSERT(mState.mActive && !mState.mPaused);
// All draws should be validated with checkBufferSpaceForDraw so ValueOrDie should never fail.
......@@ -203,7 +203,7 @@ void TransformFeedback::onVerticesDrawn(GLsizei count, GLsizei primcount)
{
if (buffer.get() != nullptr)
{
buffer->onTransformFeedback();
buffer->onTransformFeedback(context);
}
}
}
......
......@@ -77,7 +77,7 @@ class TransformFeedback final : public RefCountObject, public LabeledObject
// how many vertices have been written to the buffers. This information is needed by
// checkBufferSpaceForDraw because each draw call appends vertices to the buffers starting just
// after the last vertex of the previous draw call.
void onVerticesDrawn(GLsizei count, GLsizei primcount);
void onVerticesDrawn(const Context *context, GLsizei count, GLsizei primcount);
bool hasBoundProgram(GLuint program) const;
......
......@@ -9,6 +9,7 @@
#include "libANGLE/VertexArray.h"
#include "libANGLE/Buffer.h"
#include "libANGLE/Context.h"
#include "libANGLE/renderer/BufferImpl.h"
#include "libANGLE/renderer/GLImplFactory.h"
#include "libANGLE/renderer/VertexArrayImpl.h"
......@@ -36,8 +37,13 @@ VertexArray::VertexArray(rx::GLImplFactory *factory,
size_t maxAttribBindings)
: mId(id),
mState(maxAttribs, maxAttribBindings),
mVertexArray(factory->createVertexArray(mState))
mVertexArray(factory->createVertexArray(mState)),
mElementArrayBufferObserverBinding(this, maxAttribBindings)
{
for (size_t attribIndex = 0; attribIndex < maxAttribBindings; ++attribIndex)
{
mArrayBufferObserverBindings.emplace_back(this, attribIndex);
}
}
void VertexArray::onDestroy(const Context *context)
......@@ -140,6 +146,8 @@ void VertexArray::bindVertexBufferImpl(const Context *context,
binding->setBuffer(context, boundBuffer, isBound);
binding->setOffset(offset);
binding->setStride(stride);
updateObserverBinding(bindingIndex);
}
void VertexArray::bindVertexBuffer(const Context *context,
......@@ -267,6 +275,7 @@ void VertexArray::setElementArrayBuffer(const Context *context, Buffer *buffer)
mState.mElementArrayBuffer.set(context, buffer);
if (isBound && mState.mElementArrayBuffer.get())
mState.mElementArrayBuffer->onBindingChanged(true, BufferBinding::ElementArray);
mElementArrayBufferObserverBinding.bind(buffer ? buffer->getImplementation() : nullptr);
mDirtyBits.set(DIRTY_BIT_ELEMENT_ARRAY_BUFFER);
}
......@@ -274,9 +283,11 @@ gl::Error VertexArray::syncState(const Context *context)
{
if (mDirtyBits.any())
{
mDirtyBitsGuard = mDirtyBits;
ANGLE_TRY(
mVertexArray->syncState(context, mDirtyBits, mDirtyAttribBits, mDirtyBindingBits));
mDirtyBits.reset();
mDirtyBitsGuard.reset();
// This is a bit of an implementation hack - but since we know the implementation
// details of the dirty bit class it should always have the same effect as iterating
......@@ -298,4 +309,39 @@ void VertexArray::onBindingChanged(bool bound)
}
}
VertexArray::DirtyBitType VertexArray::getDirtyBitFromIndex(bool contentsChanged,
angle::SubjectIndex index) const
{
if (index == mArrayBufferObserverBindings.size())
{
return contentsChanged ? DIRTY_BIT_ELEMENT_ARRAY_BUFFER_DATA
: DIRTY_BIT_ELEMENT_ARRAY_BUFFER;
}
else
{
// Note: this currently just gets the top-level dirty bit.
ASSERT(index < mArrayBufferObserverBindings.size());
return static_cast<DirtyBitType>(
(contentsChanged ? DIRTY_BIT_BUFFER_DATA_0 : DIRTY_BIT_BINDING_0) + index);
}
}
void VertexArray::onSubjectStateChange(const gl::Context *context,
angle::SubjectIndex index,
angle::SubjectMessage message)
{
bool contentsChanged = (message == angle::SubjectMessage::CONTENTS_CHANGED);
DirtyBitType dirtyBit = getDirtyBitFromIndex(contentsChanged, index);
ASSERT(!mDirtyBitsGuard.valid() || mDirtyBitsGuard.value().test(dirtyBit));
mDirtyBits.set(dirtyBit);
context->getGLState().setVertexArrayDirty(this);
}
void VertexArray::updateObserverBinding(size_t bindingIndex)
{
Buffer *boundBuffer = mState.mVertexBindings[bindingIndex].getBuffer().get();
mArrayBufferObserverBindings[bindingIndex].bind(boundBuffer ? boundBuffer->getImplementation()
: nullptr);
}
} // namespace gl
......@@ -15,6 +15,7 @@
#include "libANGLE/Constants.h"
#include "libANGLE/Debug.h"
#include "libANGLE/Observer.h"
#include "libANGLE/RefCountObject.h"
#include "libANGLE/State.h"
#include "libANGLE/VertexAttribute.h"
......@@ -72,7 +73,7 @@ class VertexArrayState final : angle::NonCopyable
ComponentTypeMask mVertexAttributesTypeMask;
};
class VertexArray final : public LabeledObject
class VertexArray final : public angle::ObserverInterface, public LabeledObject
{
public:
VertexArray(rx::GLImplFactory *factory, GLuint id, size_t maxAttribs, size_t maxAttribBindings);
......@@ -153,6 +154,11 @@ class VertexArray final : public LabeledObject
return mState.getEnabledAttributesMask();
}
// Observer implementation
void onSubjectStateChange(const gl::Context *context,
angle::SubjectIndex index,
angle::SubjectMessage message) override;
// Dirty bits for VertexArrays use a heirarchical design. At the top level, each attribute
// has a single dirty bit. Then an array of MAX_ATTRIBS dirty bits each has a dirty bit for
// enabled/pointer/format/binding. Bindings are handled similarly. Note that because the
......@@ -162,6 +168,7 @@ class VertexArray final : public LabeledObject
enum DirtyBitType
{
DIRTY_BIT_ELEMENT_ARRAY_BUFFER,
DIRTY_BIT_ELEMENT_ARRAY_BUFFER_DATA,
// Dirty bits for attributes.
DIRTY_BIT_ATTRIB_0,
......@@ -171,7 +178,11 @@ class VertexArray final : public LabeledObject
DIRTY_BIT_BINDING_0 = DIRTY_BIT_ATTRIB_MAX,
DIRTY_BIT_BINDING_MAX = DIRTY_BIT_BINDING_0 + gl::MAX_VERTEX_ATTRIB_BINDINGS,
DIRTY_BIT_UNKNOWN = DIRTY_BIT_BINDING_MAX,
// We keep separate dirty bits for bound buffers whose data changed since last update.
DIRTY_BIT_BUFFER_DATA_0 = DIRTY_BIT_BINDING_MAX,
DIRTY_BIT_BUFFER_DATA_MAX = DIRTY_BIT_BUFFER_DATA_0 + gl::MAX_VERTEX_ATTRIB_BINDINGS,
DIRTY_BIT_UNKNOWN = DIRTY_BIT_BUFFER_DATA_MAX,
DIRTY_BIT_MAX = DIRTY_BIT_UNKNOWN,
};
......@@ -218,14 +229,21 @@ class VertexArray final : public LabeledObject
void setDirtyAttribBit(size_t attribIndex, DirtyAttribBitType dirtyAttribBit);
void setDirtyBindingBit(size_t bindingIndex, DirtyBindingBitType dirtyBindingBit);
void updateObserverBinding(size_t bindingIndex);
DirtyBitType getDirtyBitFromIndex(bool contentsChanged, angle::SubjectIndex index) const;
GLuint mId;
VertexArrayState mState;
DirtyBits mDirtyBits;
DirtyAttribBitsArray mDirtyAttribBits;
DirtyBindingBitsArray mDirtyBindingBits;
Optional<DirtyBits> mDirtyBitsGuard;
rx::VertexArrayImpl *mVertexArray;
std::vector<angle::ObserverBinding> mArrayBufferObserverBindings;
angle::ObserverBinding mElementArrayBufferObserverBinding;
};
} // namespace gl
......
......@@ -19,7 +19,7 @@ using namespace gl;
TEST(VertexArrayTest, VerifyGetIndexFromDirtyBit)
{
VertexArray::DirtyBits dirtyBits;
constexpr size_t bits[] = {1, 4, 9, 16, 25};
constexpr size_t bits[] = {1, 4, 9, 16, 25, 35};
constexpr GLint count = sizeof(bits) / sizeof(size_t);
for (GLint i = 0; i < count; i++)
{
......@@ -29,7 +29,11 @@ TEST(VertexArrayTest, VerifyGetIndexFromDirtyBit)
for (size_t dirtyBit : dirtyBits)
{
const size_t index = VertexArray::GetVertexIndexFromDirtyBit(dirtyBit);
if (dirtyBit < VertexArray::DIRTY_BIT_ATTRIB_MAX)
if (dirtyBit < VertexArray::DIRTY_BIT_ATTRIB_0)
{
continue;
}
else if (dirtyBit < VertexArray::DIRTY_BIT_ATTRIB_MAX)
{
EXPECT_EQ(dirtyBit - VertexArray::DIRTY_BIT_ATTRIB_0, index);
}
......@@ -37,6 +41,10 @@ TEST(VertexArrayTest, VerifyGetIndexFromDirtyBit)
{
EXPECT_EQ(dirtyBit - VertexArray::DIRTY_BIT_BINDING_0, index);
}
else if (dirtyBit < VertexArray::DIRTY_BIT_BUFFER_DATA_MAX)
{
EXPECT_EQ(dirtyBit - VertexArray::DIRTY_BIT_BUFFER_DATA_0, index);
}
else
ASSERT_TRUE(false);
}
......
......@@ -311,7 +311,7 @@ unsigned long ComponentTypeMask::to_ulong() const
void ComponentTypeMask::from_ulong(unsigned long mask)
{
mTypeMask = mask;
mTypeMask = angle::BitSet<MAX_COMPONENT_TYPE_MASK_INDEX * 2>(mask);
}
bool ComponentTypeMask::Validate(unsigned long outputTypes,
......
......@@ -12,6 +12,7 @@
#include "common/angleutils.h"
#include "common/mathutil.h"
#include "libANGLE/Error.h"
#include "libANGLE/Observer.h"
#include "libANGLE/PackedGLEnums.h"
#include <stdint.h>
......@@ -24,7 +25,10 @@ class Context;
namespace rx
{
class BufferImpl : angle::NonCopyable
// We use two set of Subject messages. The CONTENTS_CHANGED message is signaled whenever data
// changes, to trigger re-translation or other events. Some buffers only need to be updated when the
// underlying driver object changes - this is notified via the STORAGE_CHANGED message.
class BufferImpl : public angle::Subject
{
public:
BufferImpl(const gl::BufferState &state) : mState(state) {}
......
......@@ -153,7 +153,7 @@ VertexStorageType ClassifyAttributeStorage(const gl::VertexAttribute &attrib,
}
// If specified with immediate data, we must use dynamic storage.
auto *buffer = binding.getBuffer().get();
gl::Buffer *buffer = binding.getBuffer().get();
if (!buffer)
{
return VertexStorageType::DYNAMIC;
......
......@@ -398,9 +398,6 @@ gl::Error Buffer11::setSubData(const gl::Context *context,
ANGLE_TRY(writeBuffer->setData(static_cast<const uint8_t *>(data), offset, size));
onStorageUpdate(writeBuffer);
// Notify when data changes.
onStateChange(context, angle::SubjectMessage::CONTENTS_CHANGED);
}
mSize = std::max(mSize, requiredSize);
......@@ -470,9 +467,6 @@ gl::Error Buffer11::copySubData(const gl::Context *context,
mSize = std::max<size_t>(mSize, destOffset + size);
invalidateStaticData(context);
// Also notify that the contents are dirty.
onStateChange(context, angle::SubjectMessage::CONTENTS_CHANGED);
return gl::NoError();
}
......
......@@ -47,10 +47,7 @@ enum BufferUsage
typedef size_t DataRevision;
// We use two set of Subject messages. The CONTENTS_CHANGED message is signaled whenever data
// changes, to trigger re-translation or other events. Some buffers only need to be updated when the
// underlying ID3D11Buffer object changes - this is notified via the STORAGE_CHANGED message.
class Buffer11 : public BufferD3D, public angle::Subject
class Buffer11 : public BufferD3D
{
public:
Buffer11(const gl::BufferState &state, Renderer11 *renderer);
......
......@@ -69,10 +69,22 @@ bool DrawCallHasStreamingElementArray(const gl::Context *context, GLenum srcType
: GL_UNSIGNED_SHORT;
// Not clear where the offset comes from here.
bool needsTranslation = false;
ClassifyIndexStorage(glState, elementArrayBuffer, srcType, dstType, 0, &needsTranslation);
return needsTranslation;
switch (ClassifyIndexStorage(glState, elementArrayBuffer, srcType, dstType, 0))
{
case IndexStorageType::Dynamic:
return true;
case IndexStorageType::Direct:
return false;
case IndexStorageType::Static:
{
BufferD3D *bufferD3D = GetImplAs<BufferD3D>(elementArrayBuffer);
StaticIndexBufferInterface *staticBuffer = bufferD3D->getStaticIndexBuffer();
return (staticBuffer->getBufferSize() == 0 || staticBuffer->getIndexType() != dstType);
}
default:
UNREACHABLE();
return true;
}
}
template <typename IndirectBufferT>
......
......@@ -18,7 +18,6 @@
#include "libANGLE/renderer/d3d/IndexDataManager.h"
#include "libANGLE/renderer/d3d/ProgramD3D.h"
#include "libANGLE/renderer/d3d/VertexDataManager.h"
#include "libANGLE/renderer/d3d/d3d11/Buffer11.h"
#include "libANGLE/renderer/d3d/d3d11/Context11.h"
#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
#include "libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h"
......
......@@ -1411,8 +1411,6 @@ gl::Error Renderer11::drawArrays(const gl::Context *context, const gl::DrawCallP
ANGLE_TRY(markTransformFeedbackUsage(context));
}
ANGLE_TRY(mStateManager.applyVertexBuffer(context, params));
gl::Program *program = glState.getProgram();
ASSERT(program != nullptr);
GLsizei adjustedInstanceCount = GetAdjustedInstanceCount(program, params.instances());
......@@ -1535,12 +1533,6 @@ gl::Error Renderer11::drawElements(const gl::Context *context, const gl::DrawCal
const auto &glState = context->getGLState();
ASSERT(!glState.isTransformFeedbackActiveUnpaused());
bool usePrimitiveRestartWorkaround =
UsePrimitiveRestartWorkaround(glState.isPrimitiveRestartEnabled(), params.type());
ANGLE_TRY(mStateManager.applyIndexBuffer(context, params, usePrimitiveRestartWorkaround));
ANGLE_TRY(mStateManager.applyVertexBuffer(context, params));
// If this draw call is coming from an indirect call, offset by the indirect call's base vertex.
// No base vertex parameter exists for a normal drawElements, so params.baseVertex will be zero.
int startVertex = static_cast<int>(params.firstVertex() - params.baseVertex());
......@@ -1623,8 +1615,6 @@ gl::Error Renderer11::drawArraysIndirect(const gl::Context *context,
const gl::State &glState = context->getGLState();
ASSERT(!glState.isTransformFeedbackActiveUnpaused());
ANGLE_TRY(mStateManager.applyVertexBuffer(context, params));
gl::Buffer *drawIndirectBuffer = glState.getTargetBuffer(gl::BufferBinding::DrawIndirect);
ASSERT(drawIndirectBuffer);
Buffer11 *storage = GetImplAs<Buffer11>(drawIndirectBuffer);
......@@ -1653,11 +1643,6 @@ gl::Error Renderer11::drawElementsIndirect(const gl::Context *context,
Buffer11 *storage = GetImplAs<Buffer11>(drawIndirectBuffer);
uintptr_t offset = reinterpret_cast<uintptr_t>(params.indirect());
bool usePrimitiveRestartWorkaround =
UsePrimitiveRestartWorkaround(glState.isPrimitiveRestartEnabled(), params.type());
ANGLE_TRY(mStateManager.applyIndexBuffer(context, params, usePrimitiveRestartWorkaround));
ANGLE_TRY(mStateManager.applyVertexBuffer(context, params));
ID3D11Buffer *buffer = nullptr;
ANGLE_TRY_RESULT(storage->getBuffer(context, BUFFER_USAGE_INDIRECT), buffer);
mDeviceContext->DrawIndexedInstancedIndirect(buffer, static_cast<unsigned int>(offset));
......
......@@ -183,15 +183,18 @@ class StateManager11 final : angle::NonCopyable
// Called by the Framebuffer11 and VertexArray11.
void invalidateShaders();
// Called by VertexArray11 to trigger attribute translation.
void invalidateVertexAttributeTranslation();
// Called by the Program on Uniform Buffer change. Also called internally.
void invalidateProgramUniformBuffers();
// Called by TransformFeedback11.
void invalidateTransformFeedback();
// Called by VertexArray11.
void invalidateInputLayout();
// Called by VertexArray11 element array buffer sync.
void invalidateIndexBuffer();
void setRenderTarget(ID3D11RenderTargetView *rtv, ID3D11DepthStencilView *dsv);
void setRenderTargets(ID3D11RenderTargetView **rtvs, UINT numRtvs, ID3D11DepthStencilView *dsv);
......@@ -232,14 +235,6 @@ class StateManager11 final : angle::NonCopyable
void setSimpleScissorRect(const gl::Rectangle &glRect);
void setScissorRectD3D(const D3D11_RECT &d3dRect);
// Not handled by an internal dirty bit because of the extra draw parameters.
gl::Error applyVertexBuffer(const gl::Context *context,
const gl::DrawCallParams &drawCallParams);
gl::Error applyIndexBuffer(const gl::Context *context,
const gl::DrawCallParams &drawCallParams,
bool usePrimitiveRestartWorkaround);
void setIndexBuffer(ID3D11Buffer *buffer, DXGI_FORMAT indexFormat, unsigned int offset);
gl::Error updateVertexOffsetsForPointSpritesEmulation(GLint startVertex,
......@@ -252,6 +247,7 @@ class StateManager11 final : angle::NonCopyable
InputLayoutCache *getInputLayoutCache() { return &mInputLayoutCache; }
GLsizei getCurrentMinimumDrawCount() const { return mCurrentMinimumDrawCount; }
VertexDataManager *getVertexDataManager() { return &mVertexDataManager; }
private:
template <typename SRVType>
......@@ -336,6 +332,8 @@ class StateManager11 final : angle::NonCopyable
void processFramebufferInvalidation(const gl::Context *context);
bool syncIndexBuffer(ID3D11Buffer *buffer, DXGI_FORMAT indexFormat, unsigned int offset);
gl::Error syncVertexBuffersAndInputLayout(const gl::Context *context,
const gl::DrawCallParams &vertexParams);
bool setInputLayoutInternal(const d3d11::InputLayout *inputLayout);
......@@ -352,6 +350,10 @@ class StateManager11 final : angle::NonCopyable
ProgramD3D *programD3D,
GLenum currentDrawMode);
// Not handled by an internal dirty bit because it isn't synced on drawArrays calls.
gl::Error applyIndexBuffer(const gl::Context *context,
const gl::DrawCallParams &drawCallParams);
enum DirtyBitType
{
DIRTY_BIT_RENDER_TARGET,
......@@ -367,6 +369,7 @@ class StateManager11 final : angle::NonCopyable
DIRTY_BIT_SHADERS,
DIRTY_BIT_CURRENT_VALUE_ATTRIBS,
DIRTY_BIT_TRANSFORM_FEEDBACK,
DIRTY_BIT_VERTEX_BUFFERS_AND_INPUT_LAYOUT,
DIRTY_BIT_PRIMITIVE_TOPOLOGY,
DIRTY_BIT_INVALID,
DIRTY_BIT_MAX = DIRTY_BIT_INVALID,
......@@ -475,8 +478,6 @@ class StateManager11 final : angle::NonCopyable
// Current applied input layout.
ResourceSerial mCurrentInputLayout;
bool mInputLayoutIsDirty;
bool mVertexAttribsNeedTranslation;
// Current applied vertex states.
// TODO(jmadill): Figure out how to use ResourceSerial here.
......
......@@ -10,7 +10,6 @@
#define LIBANGLE_RENDERER_D3D_D3D11_VERTEXARRAY11_H_
#include "libANGLE/Framebuffer.h"
#include "libANGLE/Observer.h"
#include "libANGLE/renderer/VertexArrayImpl.h"
#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
......@@ -19,52 +18,54 @@ namespace rx
{
class Renderer11;
class VertexArray11 : public angle::ObserverInterface, public VertexArrayImpl
class VertexArray11 : public VertexArrayImpl
{
public:
VertexArray11(const gl::VertexArrayState &data);
~VertexArray11() override;
void destroy(const gl::Context *context) override;
// Does not apply any state updates - these are done in syncStateForDraw which as access to
// the DrawCallParams before a draw.
gl::Error syncState(const gl::Context *context,
const gl::VertexArray::DirtyBits &dirtyBits,
const gl::VertexArray::DirtyAttribBitsArray &attribBits,
const gl::VertexArray::DirtyBindingBitsArray &bindingBits) override;
// This will flush any pending attrib updates and then check the dynamic attribs mask.
// Applied buffer pointers are updated here.
gl::Error syncStateForDraw(const gl::Context *context,
const gl::DrawCallParams &drawCallParams);
// This will check the dynamic attribs mask.
bool hasActiveDynamicAttrib(const gl::Context *context);
gl::Error updateDirtyAndDynamicAttribs(const gl::Context *context,
VertexDataManager *vertexDataManager,
const gl::DrawCallParams &drawCallParams);
void clearDirtyAndPromoteDynamicAttribs(const gl::Context *context,
const gl::DrawCallParams &drawCallParams);
const std::vector<TranslatedAttribute> &getTranslatedAttribs() const;
// Observer implementation
void onSubjectStateChange(const gl::Context *context,
angle::SubjectIndex index,
angle::SubjectMessage message) override;
Serial getCurrentStateSerial() const { return mCurrentStateSerial; }
// In case of a multi-view program change, we have to update all attributes so that the divisor
// is adjusted.
void markAllAttributeDivisorsForAdjustment(int numViews);
bool flushAttribUpdates(const gl::Context *context);
// Returns true if the element array buffer needs to be translated.
bool updateElementArrayStorage(const gl::Context *context,
GLenum elementType,
GLenum destElementType,
const void *indices);
gl::Error updateElementArrayStorage(const gl::Context *context,
const gl::DrawCallParams &drawCallParams,
bool restartEnabled);
TranslatedIndexData *getCachedIndexInfo();
void setCachedIndexInfoValid();
const TranslatedIndexData &getCachedIndexInfo() const;
void updateCachedIndexInfo(const TranslatedIndexData &indexInfo);
bool isCachedIndexInfoValid() const;
GLenum getCachedDestinationIndexType() const;
private:
void updateVertexAttribStorage(const gl::Context *context, size_t attribIndex);
void updateVertexAttribStorage(StateManager11 *stateManager,
size_t dirtyBit,
size_t attribIndex);
gl::Error updateDirtyAttribs(const gl::Context *context);
gl::Error updateDynamicAttribs(const gl::Context *context,
VertexDataManager *vertexDataManager,
const gl::DrawCallParams &drawCallParams);
std::vector<VertexStorageType> mAttributeStorageTypes;
std::vector<TranslatedAttribute> mTranslatedAttribs;
......@@ -72,30 +73,24 @@ class VertexArray11 : public angle::ObserverInterface, public VertexArrayImpl
// The mask of attributes marked as dynamic.
gl::AttributesMask mDynamicAttribsMask;
// A mask of attributes that need to be re-evaluated.
gl::AttributesMask mAttribsToUpdate;
// Mask applied to dirty bits on syncState. If a bit is on, it is relevant.
gl::VertexArray::DirtyBits mRelevantDirtyBitsMask;
// A set of attributes we know are dirty, and need to be re-translated.
gl::AttributesMask mAttribsToTranslate;
// We need to keep a safe pointer to the Buffer so we can attach the correct dirty callbacks.
std::vector<gl::BindingPointer<gl::Buffer>> mCurrentArrayBuffers;
gl::BindingPointer<gl::Buffer> mCurrentElementArrayBuffer;
std::vector<angle::ObserverBinding> mOnArrayBufferDataDirty;
angle::ObserverBinding mOnElementArrayBufferDataDirty;
Serial mCurrentStateSerial;
// The numViews value used to adjust the divisor.
int mAppliedNumViewsToDivisor;
// If the index buffer needs re-streaming.
GLenum mLastElementType;
unsigned int mLastDrawElementsOffset;
Optional<GLenum> mLastDrawElementsType;
Optional<const void *> mLastDrawElementsIndices;
Optional<bool> mLastPrimitiveRestartEnabled;
IndexStorageType mCurrentElementArrayStorage;
TranslatedIndexData mCachedIndexInfo;
bool mCachedIndexInfoValid;
Optional<TranslatedIndexData> mCachedIndexInfo;
GLenum mCachedDestinationIndexType;
};
} // namespace rx
......
......@@ -21,7 +21,6 @@
#include "libANGLE/formatutils.h"
#include "libANGLE/renderer/d3d/BufferD3D.h"
#include "libANGLE/renderer/d3d/FramebufferD3D.h"
#include "libANGLE/renderer/d3d/IndexBuffer.h"
#include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h"
#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
#include "libANGLE/renderer/d3d/d3d11/dxgi_support_table.h"
......@@ -2362,13 +2361,11 @@ IndexStorageType ClassifyIndexStorage(const gl::State &glState,
const gl::Buffer *elementArrayBuffer,
GLenum elementType,
GLenum destElementType,
unsigned int offset,
bool *needsTranslation)
unsigned int offset)
{
// No buffer bound means we are streaming from a client pointer.
if (!elementArrayBuffer || !IsOffsetAligned(elementType, offset))
{
*needsTranslation = true;
return IndexStorageType::Dynamic;
}
......@@ -2376,7 +2373,6 @@ IndexStorageType ClassifyIndexStorage(const gl::State &glState,
BufferD3D *bufferD3D = GetImplAs<BufferD3D>(elementArrayBuffer);
if (bufferD3D->supportsDirectBinding() && destElementType == elementType)
{
*needsTranslation = false;
return IndexStorageType::Direct;
}
......@@ -2384,15 +2380,10 @@ IndexStorageType ClassifyIndexStorage(const gl::State &glState,
StaticIndexBufferInterface *staticBuffer = bufferD3D->getStaticIndexBuffer();
if (staticBuffer != nullptr)
{
// Need to re-translate the static data if has never been used, or changed type.
*needsTranslation =
(staticBuffer->getBufferSize() == 0 || staticBuffer->getIndexType() != destElementType);
return IndexStorageType::Static;
}
// Static buffer not available, fall back to streaming.
*needsTranslation = true;
return IndexStorageType::Dynamic;
}
} // namespace rx
......@@ -419,8 +419,7 @@ IndexStorageType ClassifyIndexStorage(const gl::State &glState,
const gl::Buffer *elementArrayBuffer,
GLenum elementType,
GLenum destElementType,
unsigned int offset,
bool *needsTranslation);
unsigned int offset);
} // namespace rx
......
......@@ -716,6 +716,9 @@ gl::Error VertexArrayGL::syncState(const gl::Context *context,
updateElementArrayBufferBinding(context);
break;
case VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER_DATA:
break;
default:
{
ASSERT(dirtyBit >= VertexArray::DIRTY_BIT_ATTRIB_0);
......@@ -724,12 +727,16 @@ gl::Error VertexArrayGL::syncState(const gl::Context *context,
{
syncDirtyAttrib(context, index, attribBits[index]);
}
else
else if (dirtyBit < VertexArray::DIRTY_BIT_BINDING_MAX)
{
ASSERT(dirtyBit >= VertexArray::DIRTY_BIT_BINDING_0 &&
dirtyBit < VertexArray::DIRTY_BIT_BINDING_MAX);
ASSERT(dirtyBit >= VertexArray::DIRTY_BIT_BINDING_0);
syncDirtyBinding(context, index, bindingBits[index]);
}
else
{
ASSERT(dirtyBit >= VertexArray::DIRTY_BIT_BUFFER_DATA_0 &&
dirtyBit < VertexArray::DIRTY_BIT_BUFFER_DATA_MAX);
}
break;
}
}
......@@ -751,4 +758,4 @@ void VertexArrayGL::applyNumViewsToDivisor(int numViews)
}
}
} // rx
} // namespace rx
......@@ -18,7 +18,7 @@ namespace rx
{
class RendererVk;
class BufferVk : public BufferImpl, public ResourceVk, public angle::Subject
class BufferVk : public BufferImpl, public ResourceVk
{
public:
BufferVk(const gl::BufferState &state);
......
......@@ -109,54 +109,65 @@ gl::Error VertexArrayVk::syncState(const gl::Context *context,
const auto &attribs = mState.getVertexAttributes();
const auto &bindings = mState.getVertexBindings();
for (auto dirtyBit : dirtyBits)
for (size_t dirtyBit : dirtyBits)
{
if (dirtyBit == gl::VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER)
switch (dirtyBit)
{
gl::Buffer *bufferGL = mState.getElementArrayBuffer().get();
if (bufferGL)
case gl::VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER:
{
mCurrentElementArrayBufferResource = vk::GetImpl(bufferGL);
gl::Buffer *bufferGL = mState.getElementArrayBuffer().get();
if (bufferGL)
{
mCurrentElementArrayBufferResource = vk::GetImpl(bufferGL);
}
else
{
mCurrentElementArrayBufferResource = nullptr;
}
break;
}
else
{
mCurrentElementArrayBufferResource = nullptr;
}
continue;
}
size_t attribIndex = gl::VertexArray::GetVertexIndexFromDirtyBit(dirtyBit);
// Invalidate the input description for pipelines.
mDirtyPackedInputs.set(attribIndex);
const auto &attrib = attribs[attribIndex];
const auto &binding = bindings[attrib.bindingIndex];
if (attrib.enabled)
{
gl::Buffer *bufferGL = binding.getBuffer().get();
case gl::VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER_DATA:
break;
if (bufferGL)
{
BufferVk *bufferVk = vk::GetImpl(bufferGL);
mCurrentArrayBufferResources[attribIndex] = bufferVk;
mCurrentArrayBufferHandles[attribIndex] = bufferVk->getVkBuffer().getHandle();
mClientMemoryAttribs.reset(attribIndex);
}
else
default:
{
mCurrentArrayBufferResources[attribIndex] = nullptr;
mCurrentArrayBufferHandles[attribIndex] = VK_NULL_HANDLE;
mClientMemoryAttribs.set(attribIndex);
size_t attribIndex = gl::VertexArray::GetVertexIndexFromDirtyBit(dirtyBit);
// Invalidate the input description for pipelines.
mDirtyPackedInputs.set(attribIndex);
const auto &attrib = attribs[attribIndex];
const auto &binding = bindings[attrib.bindingIndex];
if (attrib.enabled)
{
gl::Buffer *bufferGL = binding.getBuffer().get();
if (bufferGL)
{
BufferVk *bufferVk = vk::GetImpl(bufferGL);
mCurrentArrayBufferResources[attribIndex] = bufferVk;
mCurrentArrayBufferHandles[attribIndex] =
bufferVk->getVkBuffer().getHandle();
mClientMemoryAttribs.reset(attribIndex);
}
else
{
mCurrentArrayBufferResources[attribIndex] = nullptr;
mCurrentArrayBufferHandles[attribIndex] = VK_NULL_HANDLE;
mClientMemoryAttribs.set(attribIndex);
}
// TODO(jmadill): Offset handling. Assume zero for now.
mCurrentArrayBufferOffsets[attribIndex] = 0;
}
else
{
mClientMemoryAttribs.reset(attribIndex);
UNIMPLEMENTED();
}
break;
}
// TODO(jmadill): Offset handling. Assume zero for now.
mCurrentArrayBufferOffsets[attribIndex] = 0;
}
else
{
mClientMemoryAttribs.reset(attribIndex);
UNIMPLEMENTED();
}
}
......
......@@ -1414,7 +1414,7 @@ void LineLoopHandler::onSubjectStateChange(const gl::Context *context,
angle::SubjectMessage message)
{
// Indicate we want to recopy on next draw since something changed in the buffer.
if (message == angle::SubjectMessage::STORAGE_CHANGED)
if (message == angle::SubjectMessage::CONTENTS_CHANGED)
{
mLineLoopIndexBuffer = VK_NULL_HANDLE;
}
......
......@@ -339,7 +339,7 @@ TEST_P(IndexedBufferCopyTest, IndexRangeBug)
glDrawElements(GL_POINTS, 1, GL_UNSIGNED_INT, nullptr);
EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_EQ(0, 0, 0, 255, 0, 255);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
}
class BufferDataTestES3 : public BufferDataTest
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment