Result GraphicsInterfaceD3D11::writeBuffer(void *dst_buf_, const void *src, size_t write_size, BufferType type) { if (write_size == 0) { return Result::OK; } if (!dst_buf_ || !src) { return Result::InvalidParameter; } auto *dst_buf = (ID3D11Buffer*)dst_buf_; auto proc_write = [this](ID3D11Buffer *buf, const void *src, size_t size) -> HRESULT { D3D11_MAPPED_SUBRESOURCE mapped; HRESULT hr = m_context->Map(buf, 0, D3D11_MAP_WRITE, 0, &mapped); if (FAILED(hr)) { return hr; } memcpy(mapped.pData, src, size); m_context->Unmap(buf, 0); return S_OK; }; // try direct access auto hr = proc_write(dst_buf, src, write_size); if (SUCCEEDED(hr)) { return Result::OK; } // try copy-via-staging auto staging = createStagingBuffer(write_size, StagingFlag::Upload); hr = proc_write(staging.Get(), src, write_size); m_context->CopyResource(dst_buf, staging.Get()); return TranslateReturnCode(hr); }
Result GraphicsInterfaceD3D11::readBuffer(void *dst, void *src_buf_, size_t read_size, BufferType type) { if (read_size == 0) { return Result::OK; } if (!dst || !src_buf_) { return Result::InvalidParameter; } auto *src_buf = (ID3D11Buffer*)src_buf_; auto proc_read = [this](void *dst, ID3D11Buffer *buf, size_t size) -> HRESULT { D3D11_MAPPED_SUBRESOURCE mapped; HRESULT hr = m_context->Map(buf, 0, D3D11_MAP_READ, 0, &mapped); if (FAILED(hr)) { return hr; } memcpy(dst, mapped.pData, size); m_context->Unmap(buf, 0); return S_OK; }; // try direct access auto hr = proc_read(dst, src_buf, read_size); if (SUCCEEDED(hr)) { return Result::OK; } // try copy-via-staging auto staging = createStagingBuffer(read_size, StagingFlag::Readback); m_context->CopyResource(staging.Get(), src_buf); sync(); hr = proc_read(dst, staging.Get(), read_size); return TranslateReturnCode(hr); }
//----------------------------------------------------------------------------- void *D3D11HardwarePixelBuffer::_mapstagingbuffer(D3D11_MAP flags) { if(!mStagingBuffer) createStagingBuffer(); if(flags == D3D11_MAP_READ_WRITE || flags == D3D11_MAP_READ || flags == D3D11_MAP_WRITE) { if(mLockBox.getHeight() == mParentTexture->getHeight() && mLockBox.getWidth() == mParentTexture->getWidth()) mDevice.GetImmediateContext()->CopyResource(mStagingBuffer, mParentTexture->getTextureResource()); else { D3D11_BOX dstBoxDx11 = OgreImageBoxToDx11Box(mLockBox); dstBoxDx11.front = 0; dstBoxDx11.back = mLockBox.getDepth(); unsigned int subresource = D3D11CalcSubresource(mSubresourceIndex, mLockBox.front, mParentTexture->getNumMipmaps()+1); mDevice.GetImmediateContext()->CopySubresourceRegion(mStagingBuffer, subresource, mLockBox.left, mLockBox.top, mSubresourceIndex, mParentTexture->getTextureResource(), subresource, &dstBoxDx11); } } else if(flags == D3D11_MAP_WRITE_DISCARD) flags = D3D11_MAP_WRITE; // stagingbuffer doesn't support discarding PixelBox box; _map(mStagingBuffer, flags, box); return box.data; }
void* D3D11TextureCore::mapstagingbuffer(D3D11_MAP flags, UINT32 mipLevel, UINT32 face, UINT32& rowPitch, UINT32& slicePitch) { // Note: I am creating and destroying a staging resource every time a texture is read. // Consider offering a flag on init that will keep this active all the time (at the cost of double memory). // Reading is slow operation anyway so I don't believe doing it as we are now will influence it much. if(!mStagingBuffer) createStagingBuffer(); D3D11RenderAPI* rs = static_cast<D3D11RenderAPI*>(RenderAPICore::instancePtr()); D3D11Device& device = rs->getPrimaryDevice(); device.getImmediateContext()->CopyResource(mStagingBuffer, mTex); return map(mStagingBuffer, flags, face, mipLevel, rowPitch, slicePitch); }