VertexStorageType ClassifyAttributeStorage(const gl::VertexAttribute &attrib) { // 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 = attrib.buffer.get(); if (!buffer) { return VertexStorageType::DYNAMIC; } // Check if the buffer supports direct storage. if (DirectStoragePossible(attrib)) { 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; } }
angle::Result VertexDataManager::reserveSpaceForAttrib(const gl::Context *context, const TranslatedAttribute &translatedAttrib, GLint start, size_t count, GLsizei instances) { ASSERT(translatedAttrib.attribute && translatedAttrib.binding); const auto &attrib = *translatedAttrib.attribute; const auto &binding = *translatedAttrib.binding; ASSERT(!DirectStoragePossible(context, 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(), count, static_cast<size_t>(instances)); // TODO([email protected]): force the index buffer to clamp any out of range indices instead // of invalid operation here. if (bufferD3D) { // 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())); ANGLE_CHECK_HR(GetImplAs<ContextD3D>(context), maxVertexCount <= elementsInBuffer, "Vertex buffer is not big enough for the draw call.", E_FAIL); } return mStreamingBuffer.reserveVertexSpace(context, attrib, binding, totalCount, instances); }
// static angle::Result 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(context, 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(bufferD3D->getFactory()->getVertexSpaceRequired(context, attrib, binding, 1, 0, &translated->stride)); auto *staticBuffer = bufferD3D->getStaticVertexBuffer(attrib, binding); ASSERT(staticBuffer); if (staticBuffer->empty()) { // Convert the entire buffer int totalCount = ElementsInBuffer(attrib, binding, static_cast<unsigned int>(bufferD3D->getSize())); int startIndex = offset / static_cast<int>(ComputeVertexAttributeStride(attrib, binding)); ANGLE_TRY(staticBuffer->storeStaticAttribute(context, attrib, binding, -startIndex, totalCount, 0, sourceData)); } 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; ANGLE_CHECK_HR_MATH(GetImplAs<ContextD3D>(context), checkedOffset.IsValid()); 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); return angle::Result::Continue(); }
// static void VertexDataManager::StoreDirectAttrib(TranslatedAttribute *directAttrib, GLint start) { const auto &attrib = *directAttrib->attribute; gl::Buffer *buffer = attrib.buffer.get(); BufferD3D *bufferD3D = buffer ? GetImplAs<BufferD3D>(buffer) : nullptr; // Instanced vertices do not apply the 'start' offset GLint firstVertexIndex = (attrib.divisor > 0 ? 0 : start); ASSERT(DirectStoragePossible(attrib)); directAttrib->vertexBuffer.set(nullptr); directAttrib->storage = bufferD3D; directAttrib->serial = bufferD3D->getSerial(); directAttrib->stride = static_cast<unsigned int>(ComputeVertexAttributeStride(attrib)); directAttrib->offset = static_cast<unsigned int>(attrib.offset + directAttrib->stride * firstVertexIndex); }
gl::Error VertexDataManager::reserveSpaceForAttrib(const TranslatedAttribute &translatedAttrib, GLsizei count, GLsizei instances) const { const gl::VertexAttribute &attrib = *translatedAttrib.attribute; ASSERT(!DirectStoragePossible(attrib)); gl::Buffer *buffer = attrib.buffer.get(); BufferD3D *bufferD3D = buffer ? GetImplAs<BufferD3D>(buffer) : nullptr; ASSERT(!bufferD3D || bufferD3D->getStaticVertexBuffer(attrib) == nullptr); UNUSED_ASSERTION_VARIABLE(bufferD3D); size_t totalCount = ComputeVertexAttributeElementCount(attrib, count, instances); ASSERT(!bufferD3D || ElementsInBuffer(attrib, static_cast<unsigned int>(bufferD3D->getSize())) >= static_cast<int>(totalCount)); return mStreamingBuffer->reserveVertexSpace(attrib, static_cast<GLsizei>(totalCount), instances); }
// static void VertexDataManager::StoreDirectAttrib(const gl::Context *context, 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(context, 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(TranslatedAttribute *translated, GLint start, GLsizei count, GLsizei instances) { const gl::VertexAttribute &attrib = *translated->attribute; gl::Buffer *buffer = attrib.buffer.get(); ASSERT(buffer && attrib.enabled && !DirectStoragePossible(attrib)); BufferD3D *bufferD3D = GetImplAs<BufferD3D>(buffer); // Instanced vertices do not apply the 'start' offset GLint firstVertexIndex = (attrib.divisor > 0 ? 0 : start); // Compute source data pointer const uint8_t *sourceData = nullptr; gl::Error error = bufferD3D->getData(&sourceData); if (error.isError()) { return error; } sourceData += static_cast<int>(attrib.offset); unsigned int streamOffset = 0; auto errorOrOutputElementSize = bufferD3D->getFactory()->getVertexSpaceRequired(attrib, 1, 0); if (errorOrOutputElementSize.isError()) { return errorOrOutputElementSize.getError(); } translated->storage = nullptr; translated->stride = errorOrOutputElementSize.getResult(); auto *staticBuffer = bufferD3D->getStaticVertexBuffer(attrib); ASSERT(staticBuffer); if (staticBuffer->empty()) { // Convert the entire buffer int totalCount = ElementsInBuffer(attrib, static_cast<unsigned int>(bufferD3D->getSize())); int startIndex = static_cast<int>(attrib.offset) / static_cast<int>(ComputeVertexAttributeStride(attrib)); error = staticBuffer->storeStaticAttribute(attrib, -startIndex, totalCount, 0, sourceData); if (error.isError()) { return error; } } unsigned int firstElementOffset = (static_cast<unsigned int>(attrib.offset) / static_cast<unsigned int>(ComputeVertexAttributeStride(attrib))) * translated->stride; ASSERT(attrib.divisor == 0 || firstVertexIndex == 0); unsigned int startOffset = firstVertexIndex * translated->stride; if (streamOffset + firstElementOffset + startOffset < streamOffset) { return gl::Error(GL_OUT_OF_MEMORY); } VertexBuffer *vertexBuffer = staticBuffer->getVertexBuffer(); translated->vertexBuffer.set(vertexBuffer); translated->serial = vertexBuffer->getSerial(); translated->offset = streamOffset + firstElementOffset + startOffset; return gl::Error(GL_NO_ERROR); }