diff options
Diffstat (limited to 'externals/oboe/samples/RhythmGame/src/main/cpp/utils')
4 files changed, 268 insertions, 0 deletions
diff --git a/externals/oboe/samples/RhythmGame/src/main/cpp/utils/LockFreeQueue.h b/externals/oboe/samples/RhythmGame/src/main/cpp/utils/LockFreeQueue.h new file mode 100644 index 0000000000..fa9f7168bb --- /dev/null +++ b/externals/oboe/samples/RhythmGame/src/main/cpp/utils/LockFreeQueue.h @@ -0,0 +1,154 @@ +/* + * Copyright 2018 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. + */ + + +#ifndef RHYTHMGAME_LOCKFREEQUEUE_H +#define RHYTHMGAME_LOCKFREEQUEUE_H + +#include <cstdint> +#include <atomic> + +/** + * A lock-free queue for single consumer, single producer. Not thread-safe when using multiple + * consumers or producers. + * + * Example code: + * + * LockFreeQueue<int, 1024> myQueue; + * int value = 123; + * myQueue.push(value); + * myQueue.pop(value); + * + * @tparam T - The item type + * @tparam CAPACITY - Maximum number of items which can be held in the queue. Must be a power of 2. + * Must be less than the maximum value permissible in INDEX_TYPE + * @tparam INDEX_TYPE - The internal index type, defaults to uint32_t. Changing this will affect + * the maximum capacity. Included for ease of unit testing because testing queue lengths of + * UINT32_MAX can be time consuming and is not always possible. + */ + +template <typename T, uint32_t CAPACITY, typename INDEX_TYPE = uint32_t> +class LockFreeQueue { +public: + + /** + * Implementation details: + * + * We have 2 counters: readCounter and writeCounter. Each will increment until it reaches + * INDEX_TYPE_MAX, then wrap to zero. Unsigned integer overflow is defined behaviour in C++. + * + * Each time we need to access our data array we call mask() which gives us the index into the + * array. This approach avoids having a "dead item" in the buffer to distinguish between full + * and empty states. It also allows us to have a size() method which is easily calculated. + * + * IMPORTANT: This implementation is only thread-safe with a single reader thread and a single + * writer thread. Have more than one of either will result in Bad Thingsā¢. + */ + + static constexpr bool isPowerOfTwo(uint32_t n) { return (n & (n - 1)) == 0; } + static_assert(isPowerOfTwo(CAPACITY), "Capacity must be a power of 2"); + static_assert(std::is_unsigned<INDEX_TYPE>::value, "Index type must be unsigned"); + + /** + * Pop a value off the head of the queue + * + * @param val - element will be stored in this variable + * @return true if value was popped successfully, false if the queue is empty + */ + bool pop(T &val) { + if (isEmpty()){ + return false; + } else { + val = buffer[mask(readCounter)]; + ++readCounter; + return true; + } + } + + /** + * Add an item to the back of the queue + * + * @param item - The item to add + * @return true if item was added, false if the queue was full + */ + bool push(const T& item) { + if (isFull()){ + return false; + } else { + buffer[mask(writeCounter)] = item; + ++writeCounter; + return true; + } + } + + /** + * Get the item at the front of the queue but do not remove it + * + * @param item - item will be stored in this variable + * @return true if item was stored, false if the queue was empty + */ + bool peek(T &item) const { + if (isEmpty()){ + return false; + } else { + item = buffer[mask(readCounter)]; + return true; + } + } + + /** + * Get the number of items in the queue + * + * @return number of items in the queue + */ + INDEX_TYPE size() const { + + /** + * This is worth some explanation: + * + * Whilst writeCounter is greater than readCounter the result of (write - read) will always + * be positive. Simple. + * + * But when writeCounter is equal to INDEX_TYPE_MAX (e.g. UINT32_MAX) the next push will + * wrap it around to zero, the start of the buffer, making writeCounter less than + * readCounter so the result of (write - read) will be negative. + * + * But because we're returning an unsigned type return value will be as follows: + * + * returnValue = INDEX_TYPE_MAX - (write - read) + * + * e.g. if write is 0, read is 150 and the INDEX_TYPE is uint8_t where the max value is + * 255 the return value will be (255 - (0 - 150)) = 105. + * + */ + return writeCounter - readCounter; + }; + +private: + + bool isEmpty() const { return readCounter == writeCounter; } + + bool isFull() const { return size() == CAPACITY; } + + INDEX_TYPE mask(INDEX_TYPE n) const { return static_cast<INDEX_TYPE>(n & (CAPACITY - 1)); } + + T buffer[CAPACITY]; + std::atomic<INDEX_TYPE> writeCounter { 0 }; + std::atomic<INDEX_TYPE> readCounter { 0 }; + +}; + +#endif //RHYTHMGAME_LOCKFREEQUEUE_H diff --git a/externals/oboe/samples/RhythmGame/src/main/cpp/utils/UtilityFunctions.cpp b/externals/oboe/samples/RhythmGame/src/main/cpp/utils/UtilityFunctions.cpp new file mode 100644 index 0000000000..431f607374 --- /dev/null +++ b/externals/oboe/samples/RhythmGame/src/main/cpp/utils/UtilityFunctions.cpp @@ -0,0 +1,40 @@ +/* + * Copyright 2018 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 <chrono> +#include <ui/OpenGLFunctions.h> +#include <GameConstants.h> +#include "UtilityFunctions.h" +#include "logging.h" + +int64_t nowUptimeMillis() { + using namespace std::chrono; + return duration_cast<milliseconds>(steady_clock::now().time_since_epoch()).count(); +} + +void renderEvent(TapResult r){ + switch (r) { + case TapResult::Success: + SetGLScreenColor(kTapSuccessColor); + break; + case TapResult::Early: + SetGLScreenColor(kTapEarlyColor); + break; + case TapResult::Late: + SetGLScreenColor(kTapLateColor); + break; + } +} diff --git a/externals/oboe/samples/RhythmGame/src/main/cpp/utils/UtilityFunctions.h b/externals/oboe/samples/RhythmGame/src/main/cpp/utils/UtilityFunctions.h new file mode 100644 index 0000000000..659cd109b9 --- /dev/null +++ b/externals/oboe/samples/RhythmGame/src/main/cpp/utils/UtilityFunctions.h @@ -0,0 +1,42 @@ +/* + * Copyright 2018 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. + */ + +#ifndef RHYTHMGAME_UTILITYFUNCTIONS_H +#define RHYTHMGAME_UTILITYFUNCTIONS_H + +#include <stdint.h> + +constexpr int64_t kMillisecondsInSecond = 1000; +constexpr int64_t kNanosecondsInMillisecond = 1000000; + +enum class TapResult { + Early, + Late, + Success +}; + +int64_t nowUptimeMillis(); + +constexpr int64_t convertFramesToMillis(const int64_t frames, const int sampleRate){ + return static_cast<int64_t>((static_cast<double>(frames)/ sampleRate) * kMillisecondsInSecond); +} + +TapResult getTapResult(int64_t tapTimeInMillis, int64_t tapWindowInMillis); + +void renderEvent(TapResult r); + + +#endif //RHYTHMGAME_UTILITYFUNCTIONS_H diff --git a/externals/oboe/samples/RhythmGame/src/main/cpp/utils/logging.h b/externals/oboe/samples/RhythmGame/src/main/cpp/utils/logging.h new file mode 100644 index 0000000000..cc04619805 --- /dev/null +++ b/externals/oboe/samples/RhythmGame/src/main/cpp/utils/logging.h @@ -0,0 +1,32 @@ +/* + * Copyright 2018 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. + */ + +#ifndef ANDROID_LOGGING_H +#define ANDROID_LOGGING_H + +#include <stdio.h> +#include <android/log.h> +#include <vector> + +#define APP_NAME "RhythmGame" +#define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, APP_NAME, __VA_ARGS__)) +#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, APP_NAME, __VA_ARGS__)) +#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, APP_NAME, __VA_ARGS__)) +#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, APP_NAME, __VA_ARGS__)) + + + +#endif //ANDROID_LOGGING_H |
