mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-11-13 22:47:26 +01:00
179 lines
6.4 KiB
C++
179 lines
6.4 KiB
C++
|
/*
|
||
|
* Copyright 2015 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 <algorithm>
|
||
|
#include <memory.h>
|
||
|
#include <stdint.h>
|
||
|
|
||
|
#include "oboe_fifo_FifoControllerBase_android.h"
|
||
|
#include "oboe_fifo_FifoController_android.h"
|
||
|
#include "oboe_fifo_FifoControllerIndirect_android.h"
|
||
|
#include "oboe_fifo_FifoBuffer_android.h"
|
||
|
|
||
|
namespace oboe {
|
||
|
|
||
|
FifoBuffer::FifoBuffer(uint32_t bytesPerFrame, uint32_t capacityInFrames)
|
||
|
: mBytesPerFrame(bytesPerFrame)
|
||
|
, mStorage(nullptr)
|
||
|
, mFramesReadCount(0)
|
||
|
, mFramesUnderrunCount(0)
|
||
|
{
|
||
|
mFifo = std::make_unique<FifoController>(capacityInFrames);
|
||
|
// allocate buffer
|
||
|
int32_t bytesPerBuffer = bytesPerFrame * capacityInFrames;
|
||
|
mStorage = new uint8_t[bytesPerBuffer];
|
||
|
mStorageOwned = true;
|
||
|
}
|
||
|
|
||
|
FifoBuffer::FifoBuffer( uint32_t bytesPerFrame,
|
||
|
uint32_t capacityInFrames,
|
||
|
std::atomic<uint64_t> *readCounterAddress,
|
||
|
std::atomic<uint64_t> *writeCounterAddress,
|
||
|
uint8_t *dataStorageAddress
|
||
|
)
|
||
|
: mBytesPerFrame(bytesPerFrame)
|
||
|
, mStorage(dataStorageAddress)
|
||
|
, mFramesReadCount(0)
|
||
|
, mFramesUnderrunCount(0)
|
||
|
{
|
||
|
mFifo = std::make_unique<FifoControllerIndirect>(capacityInFrames,
|
||
|
readCounterAddress,
|
||
|
writeCounterAddress);
|
||
|
mStorage = dataStorageAddress;
|
||
|
mStorageOwned = false;
|
||
|
}
|
||
|
|
||
|
FifoBuffer::~FifoBuffer() {
|
||
|
if (mStorageOwned) {
|
||
|
delete[] mStorage;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int32_t FifoBuffer::convertFramesToBytes(int32_t frames) {
|
||
|
return frames * mBytesPerFrame;
|
||
|
}
|
||
|
|
||
|
int32_t FifoBuffer::read(void *buffer, int32_t numFrames) {
|
||
|
if (numFrames <= 0) {
|
||
|
return 0;
|
||
|
}
|
||
|
// safe because numFrames is guaranteed positive
|
||
|
uint32_t framesToRead = static_cast<uint32_t>(numFrames);
|
||
|
uint32_t framesAvailable = mFifo->getFullFramesAvailable();
|
||
|
framesToRead = std::min(framesToRead, framesAvailable);
|
||
|
|
||
|
uint32_t readIndex = mFifo->getReadIndex(); // ranges 0 to capacity
|
||
|
uint8_t *destination = reinterpret_cast<uint8_t *>(buffer);
|
||
|
uint8_t *source = &mStorage[convertFramesToBytes(readIndex)];
|
||
|
if ((readIndex + framesToRead) > mFifo->getFrameCapacity()) {
|
||
|
// read in two parts, first part here is at the end of the mStorage buffer
|
||
|
int32_t frames1 = static_cast<int32_t>(mFifo->getFrameCapacity() - readIndex);
|
||
|
int32_t numBytes = convertFramesToBytes(frames1);
|
||
|
if (numBytes < 0) {
|
||
|
return static_cast<int32_t>(Result::ErrorOutOfRange);
|
||
|
}
|
||
|
memcpy(destination, source, static_cast<size_t>(numBytes));
|
||
|
destination += numBytes;
|
||
|
// read second part, which is at the beginning of mStorage
|
||
|
source = &mStorage[0];
|
||
|
int32_t frames2 = static_cast<uint32_t>(framesToRead - frames1);
|
||
|
numBytes = convertFramesToBytes(frames2);
|
||
|
if (numBytes < 0) {
|
||
|
return static_cast<int32_t>(Result::ErrorOutOfRange);
|
||
|
}
|
||
|
memcpy(destination, source, static_cast<size_t>(numBytes));
|
||
|
} else {
|
||
|
// just read in one shot
|
||
|
int32_t numBytes = convertFramesToBytes(framesToRead);
|
||
|
if (numBytes < 0) {
|
||
|
return static_cast<int32_t>(Result::ErrorOutOfRange);
|
||
|
}
|
||
|
memcpy(destination, source, static_cast<size_t>(numBytes));
|
||
|
}
|
||
|
mFifo->advanceReadIndex(framesToRead);
|
||
|
|
||
|
return framesToRead;
|
||
|
}
|
||
|
|
||
|
int32_t FifoBuffer::write(const void *buffer, int32_t numFrames) {
|
||
|
if (numFrames <= 0) {
|
||
|
return 0;
|
||
|
}
|
||
|
// Guaranteed positive.
|
||
|
uint32_t framesToWrite = static_cast<uint32_t>(numFrames);
|
||
|
uint32_t framesAvailable = mFifo->getEmptyFramesAvailable();
|
||
|
framesToWrite = std::min(framesToWrite, framesAvailable);
|
||
|
|
||
|
uint32_t writeIndex = mFifo->getWriteIndex();
|
||
|
int byteIndex = convertFramesToBytes(writeIndex);
|
||
|
const uint8_t *source = reinterpret_cast<const uint8_t *>(buffer);
|
||
|
uint8_t *destination = &mStorage[byteIndex];
|
||
|
if ((writeIndex + framesToWrite) > mFifo->getFrameCapacity()) {
|
||
|
// write in two parts, first part here
|
||
|
int32_t frames1 = static_cast<uint32_t>(mFifo->getFrameCapacity() - writeIndex);
|
||
|
int32_t numBytes = convertFramesToBytes(frames1);
|
||
|
if (numBytes < 0) {
|
||
|
return static_cast<int32_t>(Result::ErrorOutOfRange);
|
||
|
}
|
||
|
memcpy(destination, source, static_cast<size_t>(numBytes));
|
||
|
// read second part
|
||
|
source += convertFramesToBytes(frames1);
|
||
|
destination = &mStorage[0];
|
||
|
int frames2 = static_cast<uint32_t>(framesToWrite - frames1);
|
||
|
numBytes = convertFramesToBytes(frames2);
|
||
|
if (numBytes < 0) {
|
||
|
return static_cast<int32_t>(Result::ErrorOutOfRange);
|
||
|
}
|
||
|
memcpy(destination, source, static_cast<size_t>(numBytes));
|
||
|
} else {
|
||
|
// just write in one shot
|
||
|
int32_t numBytes = convertFramesToBytes(framesToWrite);
|
||
|
if (numBytes < 0) {
|
||
|
return static_cast<int32_t>(Result::ErrorOutOfRange);
|
||
|
}
|
||
|
memcpy(destination, source, static_cast<size_t>(numBytes));
|
||
|
}
|
||
|
mFifo->advanceWriteIndex(framesToWrite);
|
||
|
|
||
|
return framesToWrite;
|
||
|
}
|
||
|
|
||
|
int32_t FifoBuffer::readNow(void *buffer, int32_t numFrames) {
|
||
|
int32_t framesRead = read(buffer, numFrames);
|
||
|
if (framesRead < 0) {
|
||
|
return framesRead;
|
||
|
}
|
||
|
int32_t framesLeft = numFrames - framesRead;
|
||
|
mFramesReadCount += framesRead;
|
||
|
mFramesUnderrunCount += framesLeft;
|
||
|
// Zero out any samples we could not set.
|
||
|
if (framesLeft > 0) {
|
||
|
uint8_t *destination = reinterpret_cast<uint8_t *>(buffer);
|
||
|
destination += convertFramesToBytes(framesRead); // point to first byte not set
|
||
|
int32_t bytesToZero = convertFramesToBytes(framesLeft);
|
||
|
memset(destination, 0, static_cast<size_t>(bytesToZero));
|
||
|
}
|
||
|
|
||
|
return framesRead;
|
||
|
}
|
||
|
|
||
|
|
||
|
uint32_t FifoBuffer::getBufferCapacityInFrames() const {
|
||
|
return mFifo->getFrameCapacity();
|
||
|
}
|
||
|
|
||
|
} // namespace oboe
|