aboutsummaryrefslogtreecommitdiff
path: root/externals/oboe/samples/RhythmGame/src/main/cpp/utils
diff options
context:
space:
mode:
Diffstat (limited to 'externals/oboe/samples/RhythmGame/src/main/cpp/utils')
-rw-r--r--externals/oboe/samples/RhythmGame/src/main/cpp/utils/LockFreeQueue.h154
-rw-r--r--externals/oboe/samples/RhythmGame/src/main/cpp/utils/UtilityFunctions.cpp40
-rw-r--r--externals/oboe/samples/RhythmGame/src/main/cpp/utils/UtilityFunctions.h42
-rw-r--r--externals/oboe/samples/RhythmGame/src/main/cpp/utils/logging.h32
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