| // Copyright (C) 2016 The Android Open Source Project |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| #include "ChannelStream.h" |
| |
| #include "render-utils/RenderChannel.h" |
| |
| #define EMUGL_DEBUG_LEVEL 0 |
| #include "host-common/debug.h" |
| #include "host-common/dma_device.h" |
| #include "host-common/GfxstreamFatalError.h" |
| |
| #include <assert.h> |
| #include <memory.h> |
| |
| namespace gfxstream { |
| |
| using IoResult = RenderChannel::IoResult; |
| using emugl::ABORT_REASON_OTHER; |
| using emugl::FatalError; |
| |
| ChannelStream::ChannelStream(RenderChannelImpl* channel, size_t bufSize) |
| : IOStream(bufSize), mChannel(channel) { |
| mWriteBuffer.resize_noinit(bufSize); |
| } |
| |
| void* ChannelStream::allocBuffer(size_t minSize) { |
| if (mWriteBuffer.size() < minSize) { |
| mWriteBuffer.resize_noinit(minSize); |
| } |
| return mWriteBuffer.data(); |
| } |
| |
| int ChannelStream::commitBuffer(size_t size) { |
| assert(size <= mWriteBuffer.size()); |
| if (mWriteBuffer.isAllocated()) { |
| mWriteBuffer.resize(size); |
| mChannel->writeToGuest(std::move(mWriteBuffer)); |
| } else { |
| mChannel->writeToGuest( |
| RenderChannel::Buffer(mWriteBuffer.data(), mWriteBuffer.data() + size)); |
| } |
| return size; |
| } |
| |
| const unsigned char* ChannelStream::readRaw(void* buf, size_t* inout_len) { |
| size_t wanted = *inout_len; |
| size_t count = 0U; |
| auto dst = static_cast<uint8_t*>(buf); |
| D("wanted %d bytes", (int)wanted); |
| while (count < wanted) { |
| if (mReadBufferLeft > 0) { |
| size_t avail = std::min<size_t>(wanted - count, mReadBufferLeft); |
| memcpy(dst + count, |
| mReadBuffer.data() + (mReadBuffer.size() - mReadBufferLeft), |
| avail); |
| count += avail; |
| mReadBufferLeft -= avail; |
| continue; |
| } |
| bool blocking = (count == 0); |
| auto result = mChannel->readFromGuest(&mReadBuffer, blocking); |
| D("readFromGuest() returned %d, size %d", (int)result, (int)mReadBuffer.size()); |
| if (result == IoResult::Ok) { |
| mReadBufferLeft = mReadBuffer.size(); |
| continue; |
| } |
| if (count > 0) { // There is some data to return. |
| break; |
| } |
| // Result can only be IoResult::Error if |count| == 0 |
| // since |blocking| was true, it cannot be IoResult::TryAgain. |
| assert(result == IoResult::Error); |
| D("error while trying to read"); |
| return nullptr; |
| } |
| *inout_len = count; |
| D("read %d bytes", (int)count); |
| return (const unsigned char*)buf; |
| } |
| |
| void* ChannelStream::getDmaForReading(uint64_t guest_paddr) { |
| return emugl::g_emugl_dma_get_host_addr(guest_paddr); |
| } |
| |
| void ChannelStream::unlockDma(uint64_t guest_paddr) { emugl::g_emugl_dma_unlock(guest_paddr); } |
| |
| void ChannelStream::forceStop() { |
| mChannel->stopFromHost(); |
| } |
| |
| int ChannelStream::writeFully(const void* buf, size_t len) { |
| void* dstBuf = alloc(len); |
| memcpy(dstBuf, buf, len); |
| flush(); |
| return 0; |
| } |
| |
| const unsigned char *ChannelStream::readFully( void *buf, size_t len) { |
| GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) |
| << "not intended for use with ChannelStream"; |
| } |
| |
| void ChannelStream::onSave(android::base::Stream* stream) { |
| // Write only the data that's left in read buffer, but in the same format |
| // as saveBuffer() does. |
| stream->putBe32(mReadBufferLeft); |
| stream->write(mReadBuffer.data() + mReadBuffer.size() - mReadBufferLeft, |
| mReadBufferLeft); |
| android::base::saveBuffer(stream, mWriteBuffer); |
| } |
| |
| unsigned char* ChannelStream::onLoad(android::base::Stream* stream) { |
| android::base::loadBuffer(stream, &mReadBuffer); |
| mReadBufferLeft = mReadBuffer.size(); |
| android::base::loadBuffer(stream, &mWriteBuffer); |
| return reinterpret_cast<unsigned char*>(mWriteBuffer.data()); |
| } |
| |
| } // namespace gfxstream |