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); }
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); }
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; }