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