| /* |
| * Copyright (C) 2020 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 _STATE_TRACKING_SUPPORT_H_ |
| #define _STATE_TRACKING_SUPPORT_H_ |
| |
| #include "aemu/base/containers/HybridComponentManager.h" |
| #include "aemu/base/synchronization/AndroidLock.h" |
| |
| #include <GLES2/gl2.h> |
| #include <memory> |
| |
| template <class IndexType, bool initialIsTrue> |
| class PredicateMap { |
| public: |
| static const uint64_t kBitsPerEntry = 64; |
| void add(IndexType objId) { |
| static const uint64_t kNone = 0ULL; |
| static const uint64_t kAll = ~kNone; |
| IndexType index = objId / kBitsPerEntry; |
| if (!mStorage.get_const(index)) { |
| mStorage.add(index, initialIsTrue ? kAll : kNone); |
| } |
| } |
| |
| void remove(IndexType objId) { |
| if (initialIsTrue) { |
| set(objId, true); |
| } else { |
| set(objId, false); |
| } |
| } |
| |
| void set(IndexType objId, bool predicate) { |
| IndexType index = objId / kBitsPerEntry; |
| |
| if (!mStorage.get_const(index)) return; |
| |
| uint64_t* current = mStorage.get(index); |
| |
| uint64_t flag = 1ULL << (objId % kBitsPerEntry); |
| |
| if (predicate) { |
| *current = *current | flag; |
| } else { |
| *current = *current & (~flag); |
| } |
| } |
| |
| bool get(IndexType objId) const { |
| IndexType index = objId / kBitsPerEntry; |
| |
| const uint64_t* current = mStorage.get_const(index); |
| |
| if (!current) return initialIsTrue; |
| |
| uint64_t flag = 1ULL << (objId % kBitsPerEntry); |
| return (flag & (*current)) != 0; |
| } |
| |
| private: |
| using Storage = android::base::HybridComponentManager<10000, IndexType, uint64_t>; |
| Storage mStorage; |
| }; |
| |
| // Structures for fast validation of uniforms/attribs. |
| |
| struct UniformLocationInfo { |
| bool valid = false; |
| uint32_t columns; |
| uint32_t rows; |
| bool isSampler; |
| bool isInt; |
| bool isArray; |
| bool isUnsigned; |
| bool isBool; |
| }; |
| |
| struct AttribIndexInfo { |
| bool validInProgram = false; |
| }; |
| |
| using UniformValidationInfo = android::base::HybridComponentManager<1000, uint32_t, UniformLocationInfo>; |
| using AttribValidationInfo = android::base::HybridComponentManager<16, uint32_t, AttribIndexInfo>; |
| |
| using LastQueryTargetInfo = android::base::HybridComponentManager<1000, uint32_t, uint32_t>; |
| |
| using ExistenceMap = PredicateMap<uint32_t, false>; |
| |
| struct RboProps { |
| GLenum format; |
| GLsizei multisamples; |
| GLsizei width; |
| GLsizei height; |
| bool previouslyBound; |
| bool boundEGLImage; |
| GLuint id; |
| }; |
| |
| struct SamplerProps { |
| uint32_t refcount; |
| }; |
| |
| template <class T> |
| class ScopedLockedView { |
| public: |
| ScopedLockedView(T* info) : mInfo(info) { |
| mInfo->lock(); |
| } |
| virtual ~ScopedLockedView() { |
| mInfo->unlock(); |
| } |
| protected: |
| T* mInfo; |
| |
| T* internalInfo() { return mInfo; } |
| const T* internalInfo_const() const { return mInfo; } |
| }; |
| |
| struct RenderbufferInfo { |
| android::base::guest::Lock infoLock; |
| android::base::HybridComponentManager<1000, uint32_t, std::shared_ptr<RboProps>> component; |
| |
| void lock() { infoLock.lock(); } |
| void unlock() { infoLock.unlock(); } |
| |
| class ScopedView : public ScopedLockedView<RenderbufferInfo> { |
| public: |
| ScopedView(RenderbufferInfo* info) : ScopedLockedView<RenderbufferInfo>(info) { } |
| bool hasRbo(GLuint id) const { |
| return nullptr != internalInfo_const()->component.get_const(id); |
| } |
| virtual ~ScopedView() = default; |
| RboProps* get(GLuint id) { |
| auto rboPropPtr = internalInfo()->component.get(id); |
| if (!rboPropPtr) { |
| return nullptr; |
| } |
| return rboPropPtr->get(); |
| } |
| std::shared_ptr<RboProps> get_or_add_shared_ptr(GLuint id) { |
| auto rboPropPtr = internalInfo()->component.get(id); |
| if (!rboPropPtr) { |
| addFresh(id); |
| rboPropPtr = internalInfo()->component.get(id); |
| } |
| return *rboPropPtr; |
| } |
| std::shared_ptr<RboProps> get_shared_ptr(GLuint id) { |
| auto rboPropPtr = internalInfo()->component.get(id); |
| if (!internalInfo()->component.get(id)) { |
| return nullptr; |
| } |
| return *rboPropPtr; |
| } |
| const RboProps* get_const(GLuint id) { |
| auto rboPropPtr = internalInfo()->component.get_const(id); |
| if (!rboPropPtr) { |
| return nullptr; |
| } |
| return rboPropPtr->get(); |
| } |
| void addFresh(GLuint id) { |
| std::shared_ptr<RboProps> props(new RboProps()); |
| props->format = GL_NONE; |
| props->multisamples = 0; |
| props->width = 0; |
| props->height = 0; |
| props->previouslyBound = false; |
| props->boundEGLImage = false; |
| props->id = id; |
| internalInfo()->component.add(id, std::move(props)); |
| } |
| std::shared_ptr<RboProps> bind(GLuint id) { |
| auto res = get_shared_ptr(id); |
| if (!res) { |
| addFresh(id); |
| res = get_shared_ptr(id); |
| } |
| res->previouslyBound = true; |
| return res; |
| } |
| void remove(GLuint id) { |
| if (id == 0) { |
| return; |
| } |
| internalInfo()->component.remove(id); |
| } |
| }; |
| }; |
| |
| struct SamplerInfo { |
| android::base::guest::Lock infoLock; |
| android::base::HybridComponentManager<1000, uint32_t, SamplerProps> component; |
| |
| void lock() { infoLock.lock(); } |
| void unlock() { infoLock.unlock(); } |
| |
| class ScopedView : public ScopedLockedView<SamplerInfo> { |
| public: |
| ScopedView(SamplerInfo* info) : ScopedLockedView<SamplerInfo>(info) { } |
| bool samplerExists(GLuint id) const { |
| const SamplerProps* info = internalInfo_const()->component.get_const(id); |
| if (!info) return false; |
| return 0 != info->refcount; |
| } |
| virtual ~ScopedView() = default; |
| SamplerProps* get(GLuint id) { |
| return internalInfo()->component.get(id); |
| } |
| const SamplerProps* get_const(GLuint id) { |
| return internalInfo_const()->component.get_const(id); |
| } |
| void addFresh(GLuint id) { |
| SamplerProps props; |
| props.refcount = 1; |
| internalInfo()->component.add(id, props); |
| } |
| SamplerProps* bind(GLuint id) { |
| if (!samplerExists(id)) return 0; |
| ref(id); |
| SamplerProps* res = get(id); |
| return res; |
| } |
| void ref(GLuint id) { |
| SamplerProps* props = get(id); |
| if (!props) return; |
| ++props->refcount; |
| } |
| bool unref(GLuint id) { |
| SamplerProps* props = get(id); |
| if (!props) return false; |
| if (!props->refcount) return false; |
| --props->refcount; |
| bool gone = 0 == props->refcount; |
| return gone; |
| } |
| }; |
| }; |
| |
| |
| #endif |