212 lines
8.2 KiB
C++
Executable File
212 lines
8.2 KiB
C++
Executable File
/*
|
|
* GPUImage-x
|
|
*
|
|
* Copyright (C) 2017 Yijin Wang, Yiqian Wang
|
|
*
|
|
* 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 "FramebufferCache.hpp"
|
|
#include "GPUImageUtil.h"
|
|
|
|
#if defined(__APPLE__)
|
|
#include "CVFramebuffer.hpp"
|
|
#endif
|
|
|
|
NS_GI_BEGIN
|
|
|
|
FramebufferCache::FramebufferCache(Context *context)
|
|
: _context(context) {
|
|
}
|
|
|
|
FramebufferCache::~FramebufferCache() {
|
|
purge();
|
|
}
|
|
|
|
Framebuffer* FramebufferCache::fetchFramebufferUseTextureId(Context *context,
|
|
int width,
|
|
int height,
|
|
int textureId,
|
|
bool onlyTexture,
|
|
const TextureAttributes textureAttributes,
|
|
bool useTextureCache) {
|
|
Framebuffer* framebufferFromCache = 0;
|
|
if (useTextureCache) {
|
|
#if defined(__APPLE__)
|
|
//分平台创建 TextureCache
|
|
framebufferFromCache = new CVFramebuffer(context,
|
|
width,
|
|
height,
|
|
textureAttributes,
|
|
textureId);
|
|
#elif defined(__ANDROID__) || defined(ANDROID)
|
|
assert("Android HardwareBuffer not support reuse now");
|
|
#endif
|
|
} else {
|
|
framebufferFromCache = new Framebuffer(context,
|
|
width,
|
|
height,
|
|
textureAttributes,
|
|
textureId);
|
|
}
|
|
return framebufferFromCache;
|
|
|
|
}
|
|
|
|
|
|
|
|
Framebuffer* FramebufferCache::fetchFramebuffer(Context *context,
|
|
int width,
|
|
int height,
|
|
bool onlyTexture/* = false*/,
|
|
const TextureAttributes textureAttributes/* = defaultTextureAttribure*/,
|
|
bool useTextureCache) {
|
|
|
|
Framebuffer* framebufferFromCache = 0;
|
|
std::string lookupHash = _getHash(width, height, onlyTexture, textureAttributes, useTextureCache);
|
|
|
|
auto matchFramebuffersHashCode = _framebufferTypeMap[lookupHash];
|
|
|
|
if (matchFramebuffersHashCode.size() > 0) {
|
|
for (const auto &framebufferHashCodeKey : matchFramebuffersHashCode) {
|
|
auto *framebuffer = _framebuffers[framebufferHashCodeKey.first];
|
|
if (framebuffer == NULL) {
|
|
framebuffer = 0;
|
|
break;
|
|
}
|
|
if (framebuffer->getWidth() != width || framebuffer->getHeight() != height) {
|
|
forceCleanFramebuffer(framebuffer);
|
|
framebuffer = 0;
|
|
} else if (framebuffer->framebufferRetainCount() == 0 && !framebuffer->isDealloc) {
|
|
Log("Framebuffer 【命中缓存】", "hashcode:%s count:%d",
|
|
framebufferHashCodeKey.first.c_str(),
|
|
framebuffer->framebufferRetainCount());
|
|
return framebuffer;
|
|
}
|
|
}
|
|
}
|
|
Log("Framebuffer 所有缓存【未命中】", "hashcode:%s count:%d",
|
|
lookupHash.c_str(),
|
|
matchFramebuffersHashCode.size());
|
|
// 如果都被占用了 或者找不到对应的Framebuffer 则需要创建一个新的
|
|
|
|
if (useTextureCache) {
|
|
#if defined(__APPLE__)
|
|
//分平台创建 TextureCache
|
|
framebufferFromCache = new CVFramebuffer(context,
|
|
width,
|
|
height,
|
|
onlyTexture,
|
|
textureAttributes);
|
|
#elif defined(__ANDROID__) || defined(ANDROID)
|
|
assert("Android HardwareBuffer not support reuse now");
|
|
#endif
|
|
} else {
|
|
framebufferFromCache = new Framebuffer(context,
|
|
width,
|
|
height,
|
|
onlyTexture,
|
|
textureAttributes);
|
|
}
|
|
|
|
std::string framebufferHash = str_format("%s-%ld", lookupHash.c_str(),
|
|
framebufferFromCache->getTexture());
|
|
Log("Framebuffer 创建新的Framebuffer", "hashcode:%s numberOfMatchingFramebuffers:%d",
|
|
framebufferHash.c_str(),
|
|
matchFramebuffersHashCode.size());
|
|
framebufferFromCache->_hashCode = framebufferHash;
|
|
framebufferFromCache->_typeCode = lookupHash;
|
|
_framebuffers[framebufferHash] = framebufferFromCache;
|
|
_framebufferTypeMap[lookupHash][framebufferHash] = 0;
|
|
return framebufferFromCache;
|
|
}
|
|
|
|
void FramebufferCache::forceCleanFramebuffer(Framebuffer *framebuffer) {
|
|
if (_framebuffers.find(framebuffer->_hashCode) != _framebuffers.end()) {
|
|
_framebuffers.erase(framebuffer->_hashCode);
|
|
}
|
|
|
|
if (_framebufferTypeMap[framebuffer->_typeCode].find(framebuffer->_hashCode) !=
|
|
_framebufferTypeMap[framebuffer->_typeCode].end()) {
|
|
_framebufferTypeMap[framebuffer->_typeCode].erase(framebuffer->_hashCode);
|
|
}
|
|
|
|
delete framebuffer;
|
|
framebuffer = 0;
|
|
}
|
|
|
|
void FramebufferCache::returnFramebuffer(Framebuffer* framebuffer, int maxCacheSize) {
|
|
if (framebuffer->framebufferRetainCount() == 0) {
|
|
Log("准备回收 retainCount == 0 的Framebuffer", "cacheHash:%s cacheReferenceCount:%d",
|
|
framebuffer->_hashCode.c_str(),
|
|
framebuffer->framebufferRetainCount());
|
|
if (_framebuffers.find(framebuffer->_hashCode) != _framebuffers.end()) {
|
|
|
|
if (_framebufferTypeMap[framebuffer->_typeCode].size() > maxCacheSize) {
|
|
_framebuffers.erase(framebuffer->_hashCode);
|
|
if (_framebufferTypeMap[framebuffer->_typeCode].find(framebuffer->_hashCode) !=
|
|
_framebufferTypeMap[framebuffer->_typeCode].end()) {
|
|
_framebufferTypeMap[framebuffer->_typeCode].erase(framebuffer->_hashCode);
|
|
}
|
|
delete framebuffer;
|
|
framebuffer = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
std::string FramebufferCache::_getHash(int width,
|
|
int height,
|
|
bool onlyTexture,
|
|
const TextureAttributes textureAttributes,
|
|
bool useTextureCache) const {
|
|
const char *formatStr = "";
|
|
if (onlyTexture) {
|
|
formatStr = "%.1dx%.1d-%d:%d:%d:%d:%d:%d:%d-NOFB";
|
|
} else {
|
|
formatStr = "%.1dx%.1d-%d:%d:%d:%d:%d:%d:%d";
|
|
}
|
|
|
|
return str_format(formatStr,
|
|
width, height,
|
|
textureAttributes.minFilter, textureAttributes.magFilter,
|
|
textureAttributes.wrapS, textureAttributes.wrapT,
|
|
textureAttributes.internalFormat, textureAttributes.format,
|
|
textureAttributes.type);
|
|
}
|
|
|
|
Framebuffer* FramebufferCache::_getFramebufferByHash(const std::string& hash) {
|
|
return _framebuffers[hash];
|
|
}
|
|
|
|
void FramebufferCache::purge(bool force) {
|
|
if (_framebuffers.size() == 0) {
|
|
return;
|
|
}
|
|
for(auto &kvp : _framebuffers) {
|
|
if (kvp.second && !kvp.second->isDealloc) {
|
|
delete kvp.second;
|
|
kvp.second = nullptr;
|
|
}
|
|
}
|
|
_framebuffers.clear();
|
|
_framebufferTypeMap.clear();
|
|
}
|
|
|
|
void FramebufferCache::clearCache() {
|
|
_framebuffers.clear();
|
|
_framebufferTypeMap.clear();
|
|
}
|
|
|
|
NS_GI_END
|