bool VertexBufferInterface::directStoragePossible(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue) const { gl::Buffer *buffer = attrib.mBoundBuffer.get(); BufferStorage *storage = buffer ? buffer->getStorage() : NULL; if (!storage || !storage->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; bool requiresConversion = false; if (attrib.mType != GL_FLOAT) { gl::VertexFormat vertexFormat(attrib, currentValue.Type); unsigned int outputElementSize; getVertexBuffer()->getSpaceRequired(attrib, 1, 0, &outputElementSize); alignment = std::min<size_t>(outputElementSize, 4); requiresConversion = (mRenderer->getVertexConversionType(vertexFormat) & VERTEX_CONVERT_CPU) != 0; } bool isAligned = (static_cast<size_t>(attrib.stride()) % alignment == 0) && (static_cast<size_t>(attrib.mOffset) % alignment == 0); return !requiresConversion && isAligned; }
static bool directStoragePossible(VertexBufferInterface* vb, const gl::VertexAttribute& attrib) { gl::Buffer *buffer = attrib.mBoundBuffer.get(); BufferStorage *storage = buffer ? buffer->getStorage() : NULL; const bool isAligned = (attrib.stride() % 4 == 0) && (attrib.mOffset % 4 == 0); return storage && storage->supportsDirectBinding() && !vb->getVertexBuffer()->requiresConversion(attrib) && isAligned; }
void Buffer11::markTransformFeedbackUsage() { BufferStorage *transformFeedbackStorage = getBufferStorage(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK); if (transformFeedbackStorage) { transformFeedbackStorage->setDataRevision(transformFeedbackStorage->getDataRevision() + 1); } invalidateStaticData(); }
gl::Error Buffer11::copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size) { Buffer11 *sourceBuffer = makeBuffer11(source); ASSERT(sourceBuffer != NULL); BufferStorage *copyDest = getLatestBufferStorage(); if (!copyDest) { copyDest = getStagingStorage(); } BufferStorage *copySource = sourceBuffer->getLatestBufferStorage(); if (!copySource || !copyDest) { return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal staging buffer."); } // If copying to/from a pixel pack buffer, we must have a staging or // pack buffer partner, because other native buffers can't be mapped if (copyDest->getUsage() == BUFFER_USAGE_PIXEL_PACK && !copySource->isMappable()) { copySource = sourceBuffer->getStagingStorage(); } else if (copySource->getUsage() == BUFFER_USAGE_PIXEL_PACK && !copyDest->isMappable()) { copyDest = getStagingStorage(); } // D3D11 does not allow overlapped copies until 11.1, and only if the // device supports D3D11_FEATURE_DATA_D3D11_OPTIONS::CopyWithOverlap // Get around this via a different source buffer if (copySource == copyDest) { if (copySource->getUsage() == BUFFER_USAGE_STAGING) { copySource = getBufferStorage(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK); } else { copySource = getStagingStorage(); } } copyDest->copyFromStorage(copySource, sourceOffset, size, destOffset); copyDest->setDataRevision(copyDest->getDataRevision() + 1); mSize = std::max<size_t>(mSize, destOffset + size); invalidateStaticData(); return gl::Error(GL_NO_ERROR); }
bool VertexBuffer11::storeVertexAttributes(const gl::VertexAttribute &attrib, GLint start, GLsizei count, GLsizei instances, unsigned int offset) { if (mBuffer) { gl::Buffer *buffer = attrib.mBoundBuffer.get(); int inputStride = attrib.stride(); const VertexConverter &converter = getVertexConversion(attrib); ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext(); D3D11_MAPPED_SUBRESOURCE mappedResource; HRESULT result = dxContext->Map(mBuffer, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &mappedResource); if (FAILED(result)) { ERR("Vertex buffer map failed with error 0x%08x", result); return false; } char* output = reinterpret_cast<char*>(mappedResource.pData) + offset; const char *input = NULL; if (buffer) { BufferStorage *storage = buffer->getStorage(); input = static_cast<const char*>(storage->getData()) + static_cast<int>(attrib.mOffset); } else { input = static_cast<const char*>(attrib.mPointer); } if (instances == 0 || attrib.mDivisor == 0) { input += inputStride * start; } converter.conversionFunc(input, inputStride, count, output); dxContext->Unmap(mBuffer, 0); return true; } else { ERR("Vertex buffer not initialized."); return false; } }
int MicroDisplayControler::FreeRunning(MicroDisplayInit& mdi, BufferStorage& s) { //采集mdi.MaxPics行图像到缓存 if (MicroDisplayControler::StartGrabbing(mdi) < 0) { MD_ErrorMessageWait(mdi.fg); return -1; } frameindex_t lastPicNr = 0; cv::Mat OriginalImage; do{ lastPicNr = Fg_getLastPicNumberBlockingEx(mdi.fg, lastPicNr + 1, mdi.nCamPort, 100, mdi.pMem0); if (lastPicNr < 0){ int status = 0; MD_ErrorMessageWait(mdi.fg); Fg_stopAcquireEx(mdi.fg, mdi.nCamPort, mdi.pMem0, 0); Fg_FreeMemEx(mdi.fg, mdi.pMem0); Fg_FreeGrabber(mdi.fg); CloseDisplay(mdi.nId); return -1; } unsigned char *bytePtr = (unsigned char*)Fg_getImagePtrEx(mdi.fg, lastPicNr, 0, mdi.pMem0); if (mdi.nId != -1) ::DrawBuffer(mdi.nId, Fg_getImagePtrEx(mdi.fg, lastPicNr, 0, mdi.pMem0), (int)lastPicNr, ""); if (mdi.colorType == mdi.GRAY) OriginalImage = cv::Mat(mdi.height, mdi.width, CV_8U, bytePtr); else OriginalImage = cv::Mat(mdi.height, mdi.width, CV_8UC3, bytePtr); } while (!s.AddFrame(OriginalImage)); MicroDisplayControler::EndGrabbing(mdi); //功能主循环END return 0; }
gl::Error Buffer11::packPixels(ID3D11Texture2D *srcTexture, UINT srcSubresource, const PackPixelsParams ¶ms) { PackStorage *packStorage = getPackStorage(); BufferStorage *latestStorage = getLatestBufferStorage(); if (packStorage) { gl::Error error = packStorage->packPixels(srcTexture, srcSubresource, params); if (error.isError()) { return error; } packStorage->setDataRevision(latestStorage ? latestStorage->getDataRevision() + 1 : 1); } return gl::Error(GL_NO_ERROR); }
int VirtualCamera::FreeRunning(MicroDisplayInit& mdi, BufferStorage& s) { EndFlag = false; BufferIndex = 0; cv::Mat OriginalImage; do{ Sleep(0.1); } while (!s.AddFrame(GetNext())); return 0; }
Buffer11::BufferStorage *Buffer11::getLatestBufferStorage() const { // Even though we iterate over all the direct buffers, it is expected that only // 1 or 2 will be present. BufferStorage *latestStorage = NULL; DataRevision latestRevision = 0; for (auto it = mBufferStorages.begin(); it != mBufferStorages.end(); it++) { BufferStorage *storage = it->second; if (!latestStorage || storage->getDataRevision() > latestRevision) { latestStorage = storage; latestRevision = storage->getDataRevision(); } } // resize buffer if (latestStorage && latestStorage->getSize() < mSize) { if (latestStorage->resize(mSize, true).isError()) { // Out of memory error return NULL; } } return latestStorage; }
gl::Error Buffer11::map(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr) { ASSERT(!mMappedStorage); BufferStorage *latestStorage = getLatestBufferStorage(); if (latestStorage && (latestStorage->getUsage() == BUFFER_USAGE_PIXEL_PACK || latestStorage->getUsage() == BUFFER_USAGE_STAGING)) { // Latest storage is mappable. mMappedStorage = latestStorage; } else { // Fall back to using the staging buffer if the latest storage does // not exist or is not CPU-accessible. mMappedStorage = getStagingStorage(); } if (!mMappedStorage) { return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate mappable internal buffer."); } if ((access & GL_MAP_WRITE_BIT) > 0) { // Update the data revision immediately, since the data might be changed at any time mMappedStorage->setDataRevision(mMappedStorage->getDataRevision() + 1); } uint8_t *mappedBuffer = mMappedStorage->map(offset, length, access); if (!mappedBuffer) { return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal buffer."); } *mapPtr = static_cast<GLvoid *>(mappedBuffer); return gl::Error(GL_NO_ERROR); }
gl::Error Buffer11::setSubData(const void *data, size_t size, size_t offset) { size_t requiredSize = size + offset; if (data && size > 0) { // Use system memory storage for dynamic buffers. BufferStorage *writeBuffer = nullptr; if (supportsDirectBinding()) { writeBuffer = getStagingStorage(); if (!writeBuffer) { return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal buffer."); } } else { SystemMemoryStorage *systemMemoryStorage = nullptr; gl::Error error = getSystemMemoryStorage(&systemMemoryStorage); if (error.isError()) { return error; } writeBuffer = systemMemoryStorage; } ASSERT(writeBuffer); // Explicitly resize the staging buffer, preserving data if the new data will not // completely fill the buffer if (writeBuffer->getSize() < requiredSize) { bool preserveData = (offset > 0); gl::Error error = writeBuffer->resize(requiredSize, preserveData); if (error.isError()) { return error; } } writeBuffer->setData(static_cast<const uint8_t *>(data), offset, size); writeBuffer->setDataRevision(writeBuffer->getDataRevision() + 1); } mSize = std::max(mSize, requiredSize); invalidateStaticData(); return gl::Error(GL_NO_ERROR); }
GLenum VertexDataManager::prepareVertexData(const gl::VertexAttribute attribs[], gl::ProgramBinary *programBinary, GLint start, GLsizei count, TranslatedAttribute *translated, GLsizei instances) { if (!mStreamingBuffer) { return GL_OUT_OF_MEMORY; } for (int attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++) { translated[attributeIndex].active = (programBinary->getSemanticIndex(attributeIndex) != -1); } // Invalidate static buffers that don't contain matching attributes for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) { if (translated[i].active && attribs[i].mArrayEnabled) { gl::Buffer *buffer = attribs[i].mBoundBuffer.get(); StaticVertexBufferInterface *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL; if (staticBuffer && staticBuffer->getBufferSize() > 0 && staticBuffer->lookupAttribute(attribs[i]) == -1 && !directStoragePossible(staticBuffer, attribs[i])) { buffer->invalidateStaticData(); } } } // Reserve the required space in the buffers for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) { if (translated[i].active && attribs[i].mArrayEnabled) { gl::Buffer *buffer = attribs[i].mBoundBuffer.get(); StaticVertexBufferInterface *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL; VertexBufferInterface *vertexBuffer = staticBuffer ? staticBuffer : static_cast<VertexBufferInterface*>(mStreamingBuffer); if (!directStoragePossible(vertexBuffer, attribs[i])) { if (staticBuffer) { if (staticBuffer->getBufferSize() == 0) { int totalCount = elementsInBuffer(attribs[i], buffer->size()); if (!staticBuffer->reserveVertexSpace(attribs[i], totalCount, 0)) { return GL_OUT_OF_MEMORY; } } } else { if (!mStreamingBuffer->reserveVertexSpace(attribs[i], count, instances)) { return GL_OUT_OF_MEMORY; } } } } } // Perform the vertex data translations for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) { if (translated[i].active) { if (attribs[i].mArrayEnabled) { gl::Buffer *buffer = attribs[i].mBoundBuffer.get(); if (!buffer && attribs[i].mPointer == NULL) { // This is an application error that would normally result in a crash, but we catch it and return an error ERR("An enabled vertex array has no buffer and no pointer."); return GL_INVALID_OPERATION; } StaticVertexBufferInterface *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL; VertexBufferInterface *vertexBuffer = staticBuffer ? staticBuffer : static_cast<VertexBufferInterface*>(mStreamingBuffer); BufferStorage *storage = buffer ? buffer->getStorage() : NULL; bool directStorage = directStoragePossible(vertexBuffer, attribs[i]); std::size_t streamOffset = -1; unsigned int outputElementSize = 0; if (directStorage) { outputElementSize = attribs[i].stride(); streamOffset = attribs[i].mOffset + outputElementSize * start; storage->markBufferUsage(); } else if (staticBuffer) { streamOffset = staticBuffer->lookupAttribute(attribs[i]); outputElementSize = staticBuffer->getVertexBuffer()->getSpaceRequired(attribs[i], 1, 0); if (streamOffset == -1) { // Convert the entire buffer int totalCount = elementsInBuffer(attribs[i], storage->getSize()); int startIndex = attribs[i].mOffset / attribs[i].stride(); streamOffset = staticBuffer->storeVertexAttributes(attribs[i], -startIndex, totalCount, 0); } if (streamOffset != -1) { streamOffset += (attribs[i].mOffset / attribs[i].stride()) * outputElementSize; if (instances == 0 || attribs[i].mDivisor == 0) { streamOffset += start * outputElementSize; } } } else { outputElementSize = mStreamingBuffer->getVertexBuffer()->getSpaceRequired(attribs[i], 1, 0); streamOffset = mStreamingBuffer->storeVertexAttributes(attribs[i], start, count, instances); } if (streamOffset == -1) { return GL_OUT_OF_MEMORY; } translated[i].storage = directStorage ? storage : NULL; translated[i].vertexBuffer = vertexBuffer->getVertexBuffer(); translated[i].serial = directStorage ? storage->getSerial() : vertexBuffer->getSerial(); translated[i].divisor = attribs[i].mDivisor; translated[i].attribute = &attribs[i]; translated[i].stride = outputElementSize; translated[i].offset = streamOffset; } else { if (!mCurrentValueBuffer[i]) { mCurrentValueBuffer[i] = new StreamingVertexBufferInterface(mRenderer, CONSTANT_VERTEX_BUFFER_SIZE); } StreamingVertexBufferInterface *buffer = mCurrentValueBuffer[i]; if (mCurrentValue[i][0] != attribs[i].mCurrentValue[0] || mCurrentValue[i][1] != attribs[i].mCurrentValue[1] || mCurrentValue[i][2] != attribs[i].mCurrentValue[2] || mCurrentValue[i][3] != attribs[i].mCurrentValue[3]) { unsigned int requiredSpace = sizeof(float) * 4; if (!buffer->reserveRawDataSpace(requiredSpace)) { return GL_OUT_OF_MEMORY; } int streamOffset = buffer->storeRawData(attribs[i].mCurrentValue, requiredSpace); if (streamOffset == -1) { return GL_OUT_OF_MEMORY; } mCurrentValueOffsets[i] = streamOffset; } translated[i].storage = NULL; translated[i].vertexBuffer = mCurrentValueBuffer[i]->getVertexBuffer(); translated[i].serial = mCurrentValueBuffer[i]->getSerial(); translated[i].divisor = 0; translated[i].attribute = &attribs[i]; translated[i].stride = 0; translated[i].offset = mCurrentValueOffsets[i]; } } } for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) { if (translated[i].active && attribs[i].mArrayEnabled) { gl::Buffer *buffer = attribs[i].mBoundBuffer.get(); if (buffer) { buffer->promoteStaticUsage(count * attribs[i].typeSize()); } } } return GL_NO_ERROR; }
Buffer11::BufferStorage *Buffer11::getBufferStorage(BufferUsage usage) { BufferStorage *newStorage = NULL; auto directBufferIt = mBufferStorages.find(usage); if (directBufferIt != mBufferStorages.end()) { newStorage = directBufferIt->second; } if (!newStorage) { if (usage == BUFFER_USAGE_PIXEL_PACK) { newStorage = new PackStorage(mRenderer); } else if (usage == BUFFER_USAGE_SYSTEM_MEMORY) { newStorage = new SystemMemoryStorage(mRenderer); mHasSystemMemoryStorage = true; } else { // buffer is not allocated, create it newStorage = new NativeStorage(mRenderer, usage); } mBufferStorages.insert(std::make_pair(usage, newStorage)); } // resize buffer if (newStorage->getSize() < mSize) { if (newStorage->resize(mSize, true).isError()) { // Out of memory error return NULL; } } BufferStorage *latestBuffer = getLatestBufferStorage(); if (latestBuffer && latestBuffer->getDataRevision() > newStorage->getDataRevision()) { // Copy through a staging buffer if we're copying from or to a non-staging, mappable // buffer storage. This is because we can't map a GPU buffer, and copy CPU // data directly. If we're already using a staging buffer we're fine. if (latestBuffer->getUsage() != BUFFER_USAGE_STAGING && newStorage->getUsage() != BUFFER_USAGE_STAGING && (!latestBuffer->isMappable() || !newStorage->isMappable())) { NativeStorage *stagingBuffer = getStagingStorage(); stagingBuffer->copyFromStorage(latestBuffer, 0, latestBuffer->getSize(), 0); stagingBuffer->setDataRevision(latestBuffer->getDataRevision()); latestBuffer = stagingBuffer; } // if copyFromStorage returns true, the D3D buffer has been recreated // and we should update our serial if (newStorage->copyFromStorage(latestBuffer, 0, latestBuffer->getSize(), 0)) { updateSerial(); } newStorage->setDataRevision(latestBuffer->getDataRevision()); } return newStorage; }
GLenum VertexDataManager::prepareVertexData(const gl::VertexAttribute attribs[], const gl::VertexAttribCurrentValueData currentValues[], gl::ProgramBinary *programBinary, GLint start, GLsizei count, TranslatedAttribute *translated, GLsizei instances) { if (!mStreamingBuffer) { return GL_OUT_OF_MEMORY; } for (int attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++) { translated[attributeIndex].active = (programBinary->getSemanticIndex(attributeIndex) != -1); } // Invalidate static buffers that don't contain matching attributes for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) { if (translated[i].active && attribs[i].mArrayEnabled) { gl::Buffer *buffer = attribs[i].mBoundBuffer.get(); StaticVertexBufferInterface *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL; if (staticBuffer && staticBuffer->getBufferSize() > 0 && !staticBuffer->lookupAttribute(attribs[i], NULL) && !staticBuffer->directStoragePossible(attribs[i], currentValues[i])) { buffer->invalidateStaticData(); } } } // Reserve the required space in the buffers for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) { if (translated[i].active && attribs[i].mArrayEnabled) { gl::Buffer *buffer = attribs[i].mBoundBuffer.get(); StaticVertexBufferInterface *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL; VertexBufferInterface *vertexBuffer = staticBuffer ? staticBuffer : static_cast<VertexBufferInterface*>(mStreamingBuffer); if (!vertexBuffer->directStoragePossible(attribs[i], currentValues[i])) { if (staticBuffer) { if (staticBuffer->getBufferSize() == 0) { int totalCount = ElementsInBuffer(attribs[i], buffer->size()); if (!staticBuffer->reserveVertexSpace(attribs[i], totalCount, 0)) { return GL_OUT_OF_MEMORY; } } } else { int totalCount = StreamingBufferElementCount(attribs[i], count, instances); // [OpenGL ES 3.0.2] section 2.9.4 page 40: // We can return INVALID_OPERATION if our vertex attribute does not have enough backing data. if (buffer && ElementsInBuffer(attribs[i], buffer->size()) < totalCount) { return GL_INVALID_OPERATION; } if (!mStreamingBuffer->reserveVertexSpace(attribs[i], totalCount, instances)) { return GL_OUT_OF_MEMORY; } } } } } // Perform the vertex data translations for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) { if (translated[i].active) { if (attribs[i].mArrayEnabled) { gl::Buffer *buffer = attribs[i].mBoundBuffer.get(); if (!buffer && attribs[i].mPointer == NULL) { // This is an application error that would normally result in a crash, but we catch it and return an error ERR("An enabled vertex array has no buffer and no pointer."); return GL_INVALID_OPERATION; } StaticVertexBufferInterface *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL; VertexBufferInterface *vertexBuffer = staticBuffer ? staticBuffer : static_cast<VertexBufferInterface*>(mStreamingBuffer); BufferStorage *storage = buffer ? buffer->getStorage() : NULL; bool directStorage = vertexBuffer->directStoragePossible(attribs[i], currentValues[i]); unsigned int streamOffset = 0; unsigned int outputElementSize = 0; if (directStorage) { outputElementSize = attribs[i].stride(); streamOffset = attribs[i].mOffset + outputElementSize * start; } else if (staticBuffer) { if (!staticBuffer->getVertexBuffer()->getSpaceRequired(attribs[i], 1, 0, &outputElementSize)) { return GL_OUT_OF_MEMORY; } if (!staticBuffer->lookupAttribute(attribs[i], &streamOffset)) { // Convert the entire buffer int totalCount = ElementsInBuffer(attribs[i], storage->getSize()); int startIndex = attribs[i].mOffset / attribs[i].stride(); if (!staticBuffer->storeVertexAttributes(attribs[i], currentValues[i], -startIndex, totalCount, 0, &streamOffset)) { return GL_OUT_OF_MEMORY; } } unsigned int firstElementOffset = (attribs[i].mOffset / attribs[i].stride()) * outputElementSize; unsigned int startOffset = (instances == 0 || attribs[i].mDivisor == 0) ? start * outputElementSize : 0; if (streamOffset + firstElementOffset + startOffset < streamOffset) { return GL_OUT_OF_MEMORY; } streamOffset += firstElementOffset + startOffset; } else { int totalCount = StreamingBufferElementCount(attribs[i], count, instances); if (!mStreamingBuffer->getVertexBuffer()->getSpaceRequired(attribs[i], 1, 0, &outputElementSize) || !mStreamingBuffer->storeVertexAttributes(attribs[i], currentValues[i], start, totalCount, instances, &streamOffset)) { return GL_OUT_OF_MEMORY; } } translated[i].storage = directStorage ? storage : NULL; translated[i].vertexBuffer = vertexBuffer->getVertexBuffer(); translated[i].serial = directStorage ? storage->getSerial() : vertexBuffer->getSerial(); translated[i].divisor = attribs[i].mDivisor; translated[i].attribute = &attribs[i]; translated[i].currentValueType = currentValues[i].Type; translated[i].stride = outputElementSize; translated[i].offset = streamOffset; } else { if (!mCurrentValueBuffer[i]) { mCurrentValueBuffer[i] = new StreamingVertexBufferInterface(mRenderer, CONSTANT_VERTEX_BUFFER_SIZE); } StreamingVertexBufferInterface *buffer = mCurrentValueBuffer[i]; if (mCurrentValue[i] != currentValues[i]) { if (!buffer->reserveVertexSpace(attribs[i], 1, 0)) { return GL_OUT_OF_MEMORY; } unsigned int streamOffset; if (!buffer->storeVertexAttributes(attribs[i], currentValues[i], 0, 1, 0, &streamOffset)) { return GL_OUT_OF_MEMORY; } mCurrentValue[i] = currentValues[i]; mCurrentValueOffsets[i] = streamOffset; } translated[i].storage = NULL; translated[i].vertexBuffer = mCurrentValueBuffer[i]->getVertexBuffer(); translated[i].serial = mCurrentValueBuffer[i]->getSerial(); translated[i].divisor = 0; translated[i].attribute = &attribs[i]; translated[i].currentValueType = currentValues[i].Type; translated[i].stride = 0; translated[i].offset = mCurrentValueOffsets[i]; } } } for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) { if (translated[i].active && attribs[i].mArrayEnabled) { gl::Buffer *buffer = attribs[i].mBoundBuffer.get(); if (buffer) { buffer->promoteStaticUsage(count * attribs[i].typeSize()); } } } return GL_NO_ERROR; }
GLenum IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buffer *buffer, const GLvoid *indices, TranslatedIndexData *translated) { if (!mStreamingBufferShort) { return GL_OUT_OF_MEMORY; } GLenum destinationIndexType = (type == GL_UNSIGNED_INT) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT; unsigned int offset = 0; bool alignedOffset = false; BufferStorage *storage = NULL; if (buffer != NULL) { if (reinterpret_cast<uintptr_t>(indices) > std::numeric_limits<unsigned int>::max()) { return GL_OUT_OF_MEMORY; } offset = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(indices)); storage = buffer->getStorage(); switch (type) { case GL_UNSIGNED_BYTE: alignedOffset = (offset % sizeof(GLubyte) == 0); break; case GL_UNSIGNED_SHORT: alignedOffset = (offset % sizeof(GLushort) == 0); break; case GL_UNSIGNED_INT: alignedOffset = (offset % sizeof(GLuint) == 0); break; default: UNREACHABLE(); alignedOffset = false; } unsigned int typeSize = gl::GetTypeBytes(type); // check for integer overflows if (static_cast<unsigned int>(count) > (std::numeric_limits<unsigned int>::max() / typeSize) || typeSize * static_cast<unsigned int>(count) + offset < offset) { return GL_OUT_OF_MEMORY; } if (typeSize * static_cast<unsigned int>(count) + offset > storage->getSize()) { return GL_INVALID_OPERATION; } indices = static_cast<const GLubyte*>(storage->getData()) + offset; } StreamingIndexBufferInterface *streamingBuffer = (type == GL_UNSIGNED_INT) ? mStreamingBufferInt : mStreamingBufferShort; StaticIndexBufferInterface *staticBuffer = buffer ? buffer->getStaticIndexBuffer() : NULL; IndexBufferInterface *indexBuffer = streamingBuffer; bool directStorage = alignedOffset && storage && storage->supportsDirectBinding() && destinationIndexType == type; unsigned int streamOffset = 0; if (directStorage) { indexBuffer = streamingBuffer; streamOffset = offset; if (!buffer->getIndexRangeCache()->findRange(type, offset, count, &translated->minIndex, &translated->maxIndex, NULL)) { computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex); buffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex, translated->maxIndex, offset); } } else if (staticBuffer && staticBuffer->getBufferSize() != 0 && staticBuffer->getIndexType() == type && alignedOffset) { indexBuffer = staticBuffer; if (!staticBuffer->getIndexRangeCache()->findRange(type, offset, count, &translated->minIndex, &translated->maxIndex, &streamOffset)) { streamOffset = (offset / gl::GetTypeBytes(type)) * gl::GetTypeBytes(destinationIndexType); computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex); staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex, translated->maxIndex, streamOffset); } } else { unsigned int convertCount = count; if (staticBuffer) { if (staticBuffer->getBufferSize() == 0 && alignedOffset) { indexBuffer = staticBuffer; convertCount = storage->getSize() / gl::GetTypeBytes(type); } else { buffer->invalidateStaticData(); staticBuffer = NULL; } } if (!indexBuffer) { ERR("No valid index buffer."); return GL_INVALID_OPERATION; } unsigned int indexTypeSize = gl::GetTypeBytes(destinationIndexType); if (convertCount > std::numeric_limits<unsigned int>::max() / indexTypeSize) { ERR("Reserving %u indicies of %u bytes each exceeds the maximum buffer size.", convertCount, indexTypeSize); return GL_OUT_OF_MEMORY; } unsigned int bufferSizeRequired = convertCount * indexTypeSize; if (!indexBuffer->reserveBufferSpace(bufferSizeRequired, type)) { ERR("Failed to reserve %u bytes in an index buffer.", bufferSizeRequired); return GL_OUT_OF_MEMORY; } void* output = NULL; if (!indexBuffer->mapBuffer(bufferSizeRequired, &output, &streamOffset)) { ERR("Failed to map index buffer."); return GL_OUT_OF_MEMORY; } convertIndices(type, staticBuffer ? storage->getData() : indices, convertCount, output); if (!indexBuffer->unmapBuffer()) { ERR("Failed to unmap index buffer."); return GL_OUT_OF_MEMORY; } computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex); if (staticBuffer) { streamOffset = (offset / gl::GetTypeBytes(type)) * gl::GetTypeBytes(destinationIndexType); staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex, translated->maxIndex, streamOffset); } } translated->storage = directStorage ? storage : NULL; translated->indexBuffer = indexBuffer->getIndexBuffer(); translated->serial = directStorage ? storage->getSerial() : indexBuffer->getSerial(); translated->startIndex = streamOffset / gl::GetTypeBytes(destinationIndexType); translated->startOffset = streamOffset; if (buffer) { buffer->promoteStaticUsage(count * gl::GetTypeBytes(type)); } return GL_NO_ERROR; }