diff options
Diffstat (limited to 'src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.cpp')
-rw-r--r-- | src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.cpp | 750 |
1 files changed, 482 insertions, 268 deletions
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.cpp index b392d0f4da..54ad5e54f5 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.cpp @@ -9,25 +9,38 @@ #include "libANGLE/renderer/d3d/VertexDataManager.h" +#include "common/bitset_utils.h" #include "libANGLE/Buffer.h" +#include "libANGLE/Context.h" #include "libANGLE/Program.h" #include "libANGLE/State.h" -#include "libANGLE/VertexAttribute.h" #include "libANGLE/VertexArray.h" +#include "libANGLE/VertexAttribute.h" +#include "libANGLE/formatutils.h" #include "libANGLE/renderer/d3d/BufferD3D.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" #include "libANGLE/renderer/d3d/VertexBuffer.h" -namespace -{ - enum { INITIAL_STREAM_BUFFER_SIZE = 1024*1024 }; - // This has to be at least 4k or else it fails on ATI cards. - enum { CONSTANT_VERTEX_BUFFER_SIZE = 4096 }; -} +using namespace angle; namespace rx { +namespace +{ +enum +{ + INITIAL_STREAM_BUFFER_SIZE = 1024 * 1024 +}; +// This has to be at least 4k or else it fails on ATI cards. +enum +{ + CONSTANT_VERTEX_BUFFER_SIZE = 4096 +}; -static int ElementsInBuffer(const gl::VertexAttribute &attrib, unsigned int size) +// Warning: you should ensure binding really matches attrib.bindingIndex before using this function. +int ElementsInBuffer(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, + unsigned int size) { // Size cannot be larger than a GLsizei if (size > static_cast<unsigned int>(std::numeric_limits<int>::max())) @@ -35,15 +48,139 @@ static int ElementsInBuffer(const gl::VertexAttribute &attrib, unsigned int size size = static_cast<unsigned int>(std::numeric_limits<int>::max()); } - GLsizei stride = static_cast<GLsizei>(ComputeVertexAttributeStride(attrib)); - return (size - attrib.offset % stride + + GLsizei stride = static_cast<GLsizei>(ComputeVertexAttributeStride(attrib, binding)); + GLsizei offset = static_cast<GLsizei>(ComputeVertexAttributeOffset(attrib, binding)); + return (size - offset % stride + (stride - static_cast<GLsizei>(ComputeVertexAttributeTypeSize(attrib)))) / stride; } -VertexDataManager::CurrentValueState::CurrentValueState() - : buffer(nullptr), - offset(0) +// Warning: you should ensure binding really matches attrib.bindingIndex before using this function. +bool DirectStoragePossible(const gl::VertexAttribute &attrib, const gl::VertexBinding &binding) +{ + // Current value attribs may not use direct storage. + if (!attrib.enabled) + { + return false; + } + + gl::Buffer *buffer = binding.getBuffer().get(); + if (!buffer) + { + return false; + } + + BufferD3D *bufferD3D = GetImplAs<BufferD3D>(buffer); + ASSERT(bufferD3D); + if (!bufferD3D->supportsDirectBinding()) + { + return false; + } + + // Alignment restrictions: In D3D, vertex data must be aligned to the format stride, or to a + // 4-byte boundary, whichever is smaller. (Undocumented, and experimentally confirmed) + size_t alignment = 4; + + // TODO(jmadill): add VertexFormatCaps + BufferFactoryD3D *factory = bufferD3D->getFactory(); + + gl::VertexFormatType vertexFormatType = gl::GetVertexFormatType(attrib); + + // CPU-converted vertex data must be converted (naturally). + if ((factory->getVertexConversionType(vertexFormatType) & VERTEX_CONVERT_CPU) != 0) + { + return false; + } + + if (attrib.type != GL_FLOAT) + { + auto errorOrElementSize = factory->getVertexSpaceRequired(attrib, binding, 1, 0); + if (errorOrElementSize.isError()) + { + ERR() << "Unlogged error in DirectStoragePossible."; + return false; + } + + alignment = std::min<size_t>(errorOrElementSize.getResult(), 4); + } + + GLintptr offset = ComputeVertexAttributeOffset(attrib, binding); + // Final alignment check - unaligned data must be converted. + return (static_cast<size_t>(ComputeVertexAttributeStride(attrib, binding)) % alignment == 0) && + (static_cast<size_t>(offset) % alignment == 0); +} +} // anonymous namespace + +TranslatedAttribute::TranslatedAttribute() + : active(false), + attribute(nullptr), + binding(nullptr), + currentValueType(GL_NONE), + baseOffset(0), + usesFirstVertexOffset(false), + stride(0), + vertexBuffer(), + storage(nullptr), + serial(0), + divisor(0) +{ +} + +TranslatedAttribute::TranslatedAttribute(const TranslatedAttribute &other) = default; + +gl::ErrorOrResult<unsigned int> TranslatedAttribute::computeOffset(GLint startVertex) const +{ + if (!usesFirstVertexOffset) + { + return baseOffset; + } + + CheckedNumeric<unsigned int> offset; + + offset = baseOffset + stride * static_cast<unsigned int>(startVertex); + ANGLE_TRY_CHECKED_MATH(offset); + return offset.ValueOrDie(); +} + +// Warning: you should ensure binding really matches attrib.bindingIndex before using this function. +VertexStorageType ClassifyAttributeStorage(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding) +{ + // If attribute is disabled, we use the current value. + if (!attrib.enabled) + { + return VertexStorageType::CURRENT_VALUE; + } + + // If specified with immediate data, we must use dynamic storage. + auto *buffer = binding.getBuffer().get(); + if (!buffer) + { + return VertexStorageType::DYNAMIC; + } + + // Check if the buffer supports direct storage. + if (DirectStoragePossible(attrib, binding)) + { + return VertexStorageType::DIRECT; + } + + // Otherwise the storage is static or dynamic. + BufferD3D *bufferD3D = GetImplAs<BufferD3D>(buffer); + ASSERT(bufferD3D); + switch (bufferD3D->getUsage()) + { + case D3DBufferUsage::DYNAMIC: + return VertexStorageType::DYNAMIC; + case D3DBufferUsage::STATIC: + return VertexStorageType::STATIC; + default: + UNREACHABLE(); + return VertexStorageType::UNKNOWN; + } +} + +VertexDataManager::CurrentValueState::CurrentValueState() : buffer(), offset(0) { data.FloatValues[0] = std::numeric_limits<float>::quiet_NaN(); data.FloatValues[1] = std::numeric_limits<float>::quiet_NaN(); @@ -54,379 +191,456 @@ VertexDataManager::CurrentValueState::CurrentValueState() VertexDataManager::CurrentValueState::~CurrentValueState() { - SafeDelete(buffer); } VertexDataManager::VertexDataManager(BufferFactoryD3D *factory) - : mFactory(factory), - mStreamingBuffer(nullptr), - // TODO(jmadill): use context caps - mCurrentValueCache(gl::MAX_VERTEX_ATTRIBS) + : mFactory(factory), mStreamingBuffer(), mCurrentValueCache(gl::MAX_VERTEX_ATTRIBS) { - mStreamingBuffer = new StreamingVertexBufferInterface(factory, INITIAL_STREAM_BUFFER_SIZE); - - if (!mStreamingBuffer) - { - ERR("Failed to allocate the streaming vertex buffer."); - } - - // TODO(jmadill): use context caps - mActiveEnabledAttributes.reserve(gl::MAX_VERTEX_ATTRIBS); - mActiveDisabledAttributes.reserve(gl::MAX_VERTEX_ATTRIBS); } VertexDataManager::~VertexDataManager() { - SafeDelete(mStreamingBuffer); } -void VertexDataManager::hintUnmapAllResources(const std::vector<gl::VertexAttribute> &vertexAttributes) +gl::Error VertexDataManager::initialize() { - mStreamingBuffer->getVertexBuffer()->hintUnmapResource(); - - for (const TranslatedAttribute *translated : mActiveEnabledAttributes) + mStreamingBuffer.reset( + new StreamingVertexBufferInterface(mFactory, INITIAL_STREAM_BUFFER_SIZE)); + if (!mStreamingBuffer) { - gl::Buffer *buffer = translated->attribute->buffer.get(); - BufferD3D *storage = buffer ? GetImplAs<BufferD3D>(buffer) : nullptr; - StaticVertexBufferInterface *staticBuffer = - storage - ? storage->getStaticVertexBuffer(*translated->attribute, D3D_BUFFER_DO_NOT_CREATE) - : nullptr; - - if (staticBuffer) - { - // 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 - staticBuffer->commit(); - - staticBuffer->getVertexBuffer()->hintUnmapResource(); - } + return gl::OutOfMemory() << "Failed to allocate the streaming vertex buffer."; } - for (auto ¤tValue : mCurrentValueCache) - { - if (currentValue.buffer != nullptr) - { - currentValue.buffer->getVertexBuffer()->hintUnmapResource(); - } - } + return gl::NoError(); } -gl::Error VertexDataManager::prepareVertexData(const gl::State &state, +void VertexDataManager::deinitialize() +{ + mStreamingBuffer.reset(); + mCurrentValueCache.clear(); +} + +gl::Error VertexDataManager::prepareVertexData(const gl::Context *context, 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."); - } + ASSERT(mStreamingBuffer); - // Compute active enabled and active disable attributes, for speed. - // TODO(jmadill): don't recompute if there was no state change + const gl::State &state = context->getGLState(); const gl::VertexArray *vertexArray = state.getVertexArray(); - const gl::Program *program = state.getProgram(); const auto &vertexAttributes = vertexArray->getVertexAttributes(); + const auto &vertexBindings = vertexArray->getVertexBindings(); + + mDynamicAttribsMaskCache.reset(); + const gl::Program *program = state.getProgram(); - 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); + // Skip attrib locations the program doesn't use. + if (!program->isAttribLocationActive(attribIndex)) + continue; + + const auto &attrib = vertexAttributes[attribIndex]; + const auto &binding = vertexBindings[attrib.bindingIndex]; - TranslatedAttribute *translated = &(*translatedAttribs)[attribIndex]; + // Resize automatically puts in empty attribs + translatedAttribs->resize(attribIndex + 1); - // 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; + TranslatedAttribute *translated = &(*translatedAttribs)[attribIndex]; + auto currentValueData = state.getVertexAttribCurrentValue(attribIndex); - if (vertexAttributes[attribIndex].enabled) + // Record the attribute now + translated->active = true; + translated->attribute = &attrib; + translated->binding = &binding; + translated->currentValueType = currentValueData.Type; + translated->divisor = binding.getDivisor(); + + switch (ClassifyAttributeStorage(attrib, binding)) + { + case VertexStorageType::STATIC: { - mActiveEnabledAttributes.push_back(translated); - - gl::Buffer *buffer = vertexAttributes[attribIndex].buffer.get(); - if (buffer) - { - // Also reinitialize static buffers which didn't contain matching data - // last time they were used - BufferD3D *bufferImpl = GetImplAs<BufferD3D>(buffer); - bufferImpl->reinitOutOfDateStaticData(); - } + // Store static attribute. + ANGLE_TRY(StoreStaticAttrib(context, translated)); + break; } - else + case VertexStorageType::DYNAMIC: + // Dynamic attributes must be handled together. + mDynamicAttribsMaskCache.set(attribIndex); + break; + case VertexStorageType::DIRECT: + // Update translated data for direct attributes. + StoreDirectAttrib(translated); + break; + case VertexStorageType::CURRENT_VALUE: { - mActiveDisabledAttributes.push_back(attribIndex); + ANGLE_TRY(storeCurrentValue(currentValueData, translated, attribIndex)); + break; } + default: + UNREACHABLE(); + break; } } - // Reserve the required space in the buffers - for (const TranslatedAttribute *activeAttrib : mActiveEnabledAttributes) + if (mDynamicAttribsMaskCache.none()) { - gl::Error error = reserveSpaceForAttrib(*activeAttrib, count, instances); - if (error.isError()) - { - return error; - } + return gl::NoError(); } - // Perform the vertex data translations - for (TranslatedAttribute *activeAttrib : mActiveEnabledAttributes) + ANGLE_TRY(storeDynamicAttribs(context, translatedAttribs, mDynamicAttribsMaskCache, start, + count, instances)); + + PromoteDynamicAttribs(context, *translatedAttribs, mDynamicAttribsMaskCache, count); + + return gl::NoError(); +} + +// static +void VertexDataManager::StoreDirectAttrib(TranslatedAttribute *directAttrib) +{ + ASSERT(directAttrib->attribute && directAttrib->binding); + const auto &attrib = *directAttrib->attribute; + const auto &binding = *directAttrib->binding; + + gl::Buffer *buffer = binding.getBuffer().get(); + ASSERT(buffer); + BufferD3D *bufferD3D = GetImplAs<BufferD3D>(buffer); + + ASSERT(DirectStoragePossible(attrib, binding)); + directAttrib->vertexBuffer.set(nullptr); + directAttrib->storage = bufferD3D; + directAttrib->serial = bufferD3D->getSerial(); + directAttrib->stride = static_cast<unsigned int>(ComputeVertexAttributeStride(attrib, binding)); + directAttrib->baseOffset = + static_cast<unsigned int>(ComputeVertexAttributeOffset(attrib, binding)); + + // Instanced vertices do not apply the 'start' offset + directAttrib->usesFirstVertexOffset = (binding.getDivisor() == 0); +} + +// static +gl::Error VertexDataManager::StoreStaticAttrib(const gl::Context *context, + TranslatedAttribute *translated) +{ + ASSERT(translated->attribute && translated->binding); + const auto &attrib = *translated->attribute; + const auto &binding = *translated->binding; + + gl::Buffer *buffer = binding.getBuffer().get(); + ASSERT(buffer && attrib.enabled && !DirectStoragePossible(attrib, binding)); + BufferD3D *bufferD3D = GetImplAs<BufferD3D>(buffer); + + // Compute source data pointer + const uint8_t *sourceData = nullptr; + const int offset = static_cast<int>(ComputeVertexAttributeOffset(attrib, binding)); + + ANGLE_TRY(bufferD3D->getData(context, &sourceData)); + sourceData += offset; + + unsigned int streamOffset = 0; + + translated->storage = nullptr; + ANGLE_TRY_RESULT(bufferD3D->getFactory()->getVertexSpaceRequired(attrib, binding, 1, 0), + translated->stride); + + auto *staticBuffer = bufferD3D->getStaticVertexBuffer(attrib, binding); + ASSERT(staticBuffer); + + if (staticBuffer->empty()) { - gl::Error error = storeAttribute(activeAttrib, start, count, instances); + // Convert the entire buffer + int totalCount = + ElementsInBuffer(attrib, binding, static_cast<unsigned int>(bufferD3D->getSize())); + int startIndex = offset / static_cast<int>(ComputeVertexAttributeStride(attrib, binding)); - if (error.isError()) - { - hintUnmapAllResources(vertexAttributes); - return error; - } + ANGLE_TRY(staticBuffer->storeStaticAttribute(attrib, binding, -startIndex, totalCount, 0, + sourceData)); } - for (size_t attribIndex : mActiveDisabledAttributes) + unsigned int firstElementOffset = + (static_cast<unsigned int>(offset) / + static_cast<unsigned int>(ComputeVertexAttributeStride(attrib, binding))) * + translated->stride; + + VertexBuffer *vertexBuffer = staticBuffer->getVertexBuffer(); + + CheckedNumeric<unsigned int> checkedOffset(streamOffset); + checkedOffset += firstElementOffset; + + if (!checkedOffset.IsValid()) { - if (mCurrentValueCache[attribIndex].buffer == nullptr) - { - mCurrentValueCache[attribIndex].buffer = new StreamingVertexBufferInterface(mFactory, CONSTANT_VERTEX_BUFFER_SIZE); - } + return gl::InternalError() << "Integer overflow in VertexDataManager::StoreStaticAttrib"; + } + + translated->vertexBuffer.set(vertexBuffer); + translated->serial = vertexBuffer->getSerial(); + translated->baseOffset = streamOffset + firstElementOffset; + + // Instanced vertices do not apply the 'start' offset + translated->usesFirstVertexOffset = (binding.getDivisor() == 0); - gl::Error error = storeCurrentValue( - state.getVertexAttribCurrentValue(static_cast<unsigned int>(attribIndex)), - &(*translatedAttribs)[attribIndex], &mCurrentValueCache[attribIndex]); - if (error.isError()) + return gl::NoError(); +} + +gl::Error VertexDataManager::storeDynamicAttribs( + const gl::Context *context, + std::vector<TranslatedAttribute> *translatedAttribs, + const gl::AttributesMask &dynamicAttribsMask, + GLint start, + GLsizei count, + GLsizei instances) +{ + // Instantiating this class will ensure the streaming buffer is never left mapped. + class StreamingBufferUnmapper final : NonCopyable + { + public: + StreamingBufferUnmapper(StreamingVertexBufferInterface *streamingBuffer) + : mStreamingBuffer(streamingBuffer) { - hintUnmapAllResources(vertexAttributes); - return error; + ASSERT(mStreamingBuffer); } + ~StreamingBufferUnmapper() { mStreamingBuffer->getVertexBuffer()->hintUnmapResource(); } + + private: + StreamingVertexBufferInterface *mStreamingBuffer; + }; + + // Will trigger unmapping on return. + StreamingBufferUnmapper localUnmapper(mStreamingBuffer.get()); + + // Reserve the required space for the dynamic buffers. + for (auto attribIndex : dynamicAttribsMask) + { + const auto &dynamicAttrib = (*translatedAttribs)[attribIndex]; + ANGLE_TRY(reserveSpaceForAttrib(dynamicAttrib, start, count, instances)); + } + + // Store dynamic attributes + for (auto attribIndex : dynamicAttribsMask) + { + auto *dynamicAttrib = &(*translatedAttribs)[attribIndex]; + ANGLE_TRY(storeDynamicAttrib(context, dynamicAttrib, start, count, instances)); } - // Hint to unmap all the resources - hintUnmapAllResources(vertexAttributes); + return gl::NoError(); +} - for (const TranslatedAttribute *activeAttrib : mActiveEnabledAttributes) +void VertexDataManager::PromoteDynamicAttribs( + const gl::Context *context, + const std::vector<TranslatedAttribute> &translatedAttribs, + const gl::AttributesMask &dynamicAttribsMask, + GLsizei count) +{ + for (auto attribIndex : dynamicAttribsMask) { - gl::Buffer *buffer = activeAttrib->attribute->buffer.get(); + const auto &dynamicAttrib = translatedAttribs[attribIndex]; + ASSERT(dynamicAttrib.attribute && dynamicAttrib.binding); + const auto &binding = *dynamicAttrib.binding; + gl::Buffer *buffer = binding.getBuffer().get(); if (buffer) { BufferD3D *bufferD3D = GetImplAs<BufferD3D>(buffer); - size_t typeSize = ComputeVertexAttributeTypeSize(*activeAttrib->attribute); - bufferD3D->promoteStaticUsage(count * static_cast<int>(typeSize)); + size_t typeSize = ComputeVertexAttributeTypeSize(*dynamicAttrib.attribute); + bufferD3D->promoteStaticUsage(context, count * static_cast<int>(typeSize)); } } - - return gl::Error(GL_NO_ERROR); } gl::Error VertexDataManager::reserveSpaceForAttrib(const TranslatedAttribute &translatedAttrib, + GLint start, 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, D3D_BUFFER_CREATE_IF_NECESSARY) - : NULL; - VertexBufferInterface *vertexBuffer = staticBuffer ? staticBuffer : static_cast<VertexBufferInterface*>(mStreamingBuffer); - - if (!vertexBuffer->directStoragePossible(attrib, translatedAttrib.currentValueType)) + ASSERT(translatedAttrib.attribute && translatedAttrib.binding); + const auto &attrib = *translatedAttrib.attribute; + const auto &binding = *translatedAttrib.binding; + + ASSERT(!DirectStoragePossible(attrib, binding)); + + gl::Buffer *buffer = binding.getBuffer().get(); + BufferD3D *bufferD3D = buffer ? GetImplAs<BufferD3D>(buffer) : nullptr; + ASSERT(!bufferD3D || bufferD3D->getStaticVertexBuffer(attrib, binding) == nullptr); + + size_t totalCount = gl::ComputeVertexBindingElementCount( + binding.getDivisor(), static_cast<size_t>(count), static_cast<size_t>(instances)); + // TODO(jiajia.qin@intel.com): force the index buffer to clamp any out of range indices instead + // of invalid operation here. + if (bufferD3D) { - if (staticBuffer) + // Vertices do not apply the 'start' offset when the divisor is non-zero even when doing + // a non-instanced draw call + GLint firstVertexIndex = binding.getDivisor() > 0 ? 0 : start; + int64_t maxVertexCount = + static_cast<int64_t>(firstVertexIndex) + static_cast<int64_t>(totalCount); + int elementsInBuffer = + ElementsInBuffer(attrib, binding, static_cast<unsigned int>(bufferD3D->getSize())); + + if (maxVertexCount > elementsInBuffer) { - 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::InvalidOperation() << "Vertex buffer is not big enough for the draw call."; } } - - return gl::Error(GL_NO_ERROR); + return mStreamingBuffer->reserveVertexSpace(attrib, binding, static_cast<GLsizei>(totalCount), + instances); } -gl::Error VertexDataManager::storeAttribute(TranslatedAttribute *translated, - GLint start, - GLsizei count, - GLsizei instances) +gl::Error VertexDataManager::storeDynamicAttrib(const gl::Context *context, + TranslatedAttribute *translated, + GLint start, + GLsizei count, + GLsizei instances) { - const gl::VertexAttribute &attrib = *translated->attribute; + ASSERT(translated->attribute && translated->binding); + const auto &attrib = *translated->attribute; + const auto &binding = *translated->binding; - gl::Buffer *buffer = attrib.buffer.get(); + gl::Buffer *buffer = binding.getBuffer().get(); ASSERT(buffer || attrib.pointer); ASSERT(attrib.enabled); - BufferD3D *storage = buffer ? GetImplAs<BufferD3D>(buffer) : NULL; - StaticVertexBufferInterface *staticBuffer = - storage ? storage->getStaticVertexBuffer(attrib, D3D_BUFFER_DO_NOT_CREATE) : NULL; - VertexBufferInterface *vertexBuffer = staticBuffer ? staticBuffer : static_cast<VertexBufferInterface*>(mStreamingBuffer); - bool directStorage = vertexBuffer->directStoragePossible(attrib, translated->currentValueType); + BufferD3D *storage = buffer ? GetImplAs<BufferD3D>(buffer) : nullptr; // Instanced vertices do not apply the 'start' offset - GLint firstVertexIndex = (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); - } + GLint firstVertexIndex = (binding.getDivisor() > 0 ? 0 : start); // 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); + ANGLE_TRY(storage->getData(context, &sourceData)); + sourceData += static_cast<int>(ComputeVertexAttributeOffset(attrib, binding)); } else { + // Attributes using client memory ignore the VERTEX_ATTRIB_BINDING state. + // https://www.opengl.org/registry/specs/ARB/vertex_attrib_binding.txt 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; - } - } + translated->storage = nullptr; + ANGLE_TRY_RESULT(mFactory->getVertexSpaceRequired(attrib, binding, 1, 0), translated->stride); - unsigned int firstElementOffset = - (static_cast<unsigned int>(attrib.offset) / - static_cast<unsigned int>(ComputeVertexAttributeStride(attrib))) * - outputElementSize; - ASSERT(attrib.divisor == 0 || firstVertexIndex == 0); - unsigned int startOffset = firstVertexIndex * outputElementSize; - if (streamOffset + firstElementOffset + startOffset < streamOffset) - { - return gl::Error(GL_OUT_OF_MEMORY); - } + size_t totalCount = gl::ComputeVertexBindingElementCount( + binding.getDivisor(), static_cast<size_t>(count), static_cast<size_t>(instances)); - 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; - } + ANGLE_TRY(mStreamingBuffer->storeDynamicAttribute( + attrib, binding, translated->currentValueType, firstVertexIndex, + static_cast<GLsizei>(totalCount), instances, &streamOffset, sourceData)); - error = mStreamingBuffer->storeVertexAttributes( - attrib, translated->currentValueType, firstVertexIndex, - static_cast<GLsizei>(totalCount), instances, &streamOffset, sourceData); - if (error.isError()) - { - return error; - } - } + VertexBuffer *vertexBuffer = mStreamingBuffer->getVertexBuffer(); - translated->storage = nullptr; + translated->vertexBuffer.set(vertexBuffer); translated->serial = vertexBuffer->getSerial(); - translated->stride = outputElementSize; - translated->offset = streamOffset; + translated->baseOffset = streamOffset; + translated->usesFirstVertexOffset = false; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error VertexDataManager::storeCurrentValue(const gl::VertexAttribCurrentValueData ¤tValue, TranslatedAttribute *translated, - CurrentValueState *cachedState) + size_t attribIndex) { + CurrentValueState *cachedState = &mCurrentValueCache[attribIndex]; + auto &buffer = cachedState->buffer; + + if (!buffer) + { + buffer.reset(new StreamingVertexBufferInterface(mFactory, CONSTANT_VERTEX_BUFFER_SIZE)); + } + if (cachedState->data != currentValue) { - const gl::VertexAttribute &attrib = *translated->attribute; + ASSERT(translated->attribute && translated->binding); + const auto &attrib = *translated->attribute; + const auto &binding = *translated->binding; - gl::Error error = cachedState->buffer->reserveVertexSpace(attrib, 1, 0); - if (error.isError()) - { - return error; - } + ANGLE_TRY(buffer->reserveVertexSpace(attrib, binding, 1, 0)); const uint8_t *sourceData = reinterpret_cast<const uint8_t*>(currentValue.FloatValues); unsigned int streamOffset; - error = cachedState->buffer->storeVertexAttributes(attrib, currentValue.Type, 0, 1, 0, &streamOffset, sourceData); - if (error.isError()) - { - return error; - } + ANGLE_TRY(buffer->storeDynamicAttribute(attrib, binding, currentValue.Type, 0, 1, 0, + &streamOffset, sourceData)); + + buffer->getVertexBuffer()->hintUnmapResource(); cachedState->data = currentValue; cachedState->offset = streamOffset; } - translated->storage = NULL; - translated->vertexBuffer = cachedState->buffer->getVertexBuffer(); - translated->serial = cachedState->buffer->getSerial(); + translated->vertexBuffer.set(buffer->getVertexBuffer()); + + translated->storage = nullptr; + translated->serial = buffer->getSerial(); translated->divisor = 0; + translated->stride = 0; + translated->baseOffset = static_cast<unsigned int>(cachedState->offset); + translated->usesFirstVertexOffset = false; - translated->stride = 0; - translated->offset = static_cast<unsigned int>(cachedState->offset); + return gl::NoError(); +} - return gl::Error(GL_NO_ERROR); +// VertexBufferBinding implementation +VertexBufferBinding::VertexBufferBinding() : mBoundVertexBuffer(nullptr) +{ } +VertexBufferBinding::VertexBufferBinding(const VertexBufferBinding &other) + : mBoundVertexBuffer(other.mBoundVertexBuffer) +{ + if (mBoundVertexBuffer) + { + mBoundVertexBuffer->addRef(); + } +} + +VertexBufferBinding::~VertexBufferBinding() +{ + if (mBoundVertexBuffer) + { + mBoundVertexBuffer->release(); + } } + +VertexBufferBinding &VertexBufferBinding::operator=(const VertexBufferBinding &other) +{ + mBoundVertexBuffer = other.mBoundVertexBuffer; + if (mBoundVertexBuffer) + { + mBoundVertexBuffer->addRef(); + } + return *this; +} + +void VertexBufferBinding::set(VertexBuffer *vertexBuffer) +{ + if (mBoundVertexBuffer == vertexBuffer) + return; + + if (mBoundVertexBuffer) + { + mBoundVertexBuffer->release(); + } + if (vertexBuffer) + { + vertexBuffer->addRef(); + } + + mBoundVertexBuffer = vertexBuffer; +} + +VertexBuffer *VertexBufferBinding::get() const +{ + return mBoundVertexBuffer; +} + +} // namespace rx |