OffscreenBufferPool.cpp revision 9fded232a9548a304e0145011df8849fba0dcda7
1/* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "OffscreenBufferPool.h" 18 19#include "Caches.h" 20#include "Properties.h" 21#include "renderstate/RenderState.h" 22#include "utils/FatVector.h" 23 24#include <utils/Log.h> 25 26#include <GLES2/gl2.h> 27 28namespace android { 29namespace uirenderer { 30 31//////////////////////////////////////////////////////////////////////////////// 32// OffscreenBuffer 33//////////////////////////////////////////////////////////////////////////////// 34 35OffscreenBuffer::OffscreenBuffer(RenderState& renderState, Caches& caches, 36 uint32_t viewportWidth, uint32_t viewportHeight) 37 : renderState(renderState) 38 , viewportWidth(viewportWidth) 39 , viewportHeight(viewportHeight) 40 , texture(caches) { 41 texture.width = computeIdealDimension(viewportWidth); 42 texture.height = computeIdealDimension(viewportHeight); 43 texture.blend = true; 44 45 caches.textureState().activateTexture(0); 46 glGenTextures(1, &texture.id); 47 caches.textureState().bindTexture(GL_TEXTURE_2D, texture.id); 48 49 texture.setWrap(GL_CLAMP_TO_EDGE, false, false, GL_TEXTURE_2D); 50 // not setting filter on texture, since it's set when drawing, based on transform 51 52 glPixelStorei(GL_UNPACK_ALIGNMENT, 4); 53 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture.width, texture.height, 0, 54 GL_RGBA, GL_UNSIGNED_BYTE, nullptr); 55} 56 57void OffscreenBuffer::updateMeshFromRegion() { 58 // avoid T-junctions as they cause artifacts in between the resultant 59 // geometry when complex transforms occur. 60 // TODO: generate the safeRegion only if necessary based on drawing transform 61 Region safeRegion = Region::createTJunctionFreeRegion(region); 62 63 size_t count; 64 const android::Rect* rects = safeRegion.getArray(&count); 65 66 const float texX = 1.0f / float(texture.width); 67 const float texY = 1.0f / float(texture.height); 68 69 FatVector<TextureVertex, 64> meshVector(count * 4); // uses heap if more than 64 vertices needed 70 TextureVertex* mesh = &meshVector[0]; 71 for (size_t i = 0; i < count; i++) { 72 const android::Rect* r = &rects[i]; 73 74 const float u1 = r->left * texX; 75 const float v1 = (viewportHeight - r->top) * texY; 76 const float u2 = r->right * texX; 77 const float v2 = (viewportHeight - r->bottom) * texY; 78 79 TextureVertex::set(mesh++, r->left, r->top, u1, v1); 80 TextureVertex::set(mesh++, r->right, r->top, u2, v1); 81 TextureVertex::set(mesh++, r->left, r->bottom, u1, v2); 82 TextureVertex::set(mesh++, r->right, r->bottom, u2, v2); 83 } 84 elementCount = count * 6; 85 renderState.meshState().genOrUpdateMeshBuffer(&vbo, 86 sizeof(TextureVertex) * count * 4, 87 &meshVector[0], 88 GL_DYNAMIC_DRAW); // TODO: GL_STATIC_DRAW if savelayer 89} 90 91uint32_t OffscreenBuffer::computeIdealDimension(uint32_t dimension) { 92 return uint32_t(ceilf(dimension / float(LAYER_SIZE)) * LAYER_SIZE); 93} 94 95OffscreenBuffer::~OffscreenBuffer() { 96 texture.deleteTexture(); 97 renderState.meshState().deleteMeshBuffer(vbo); 98 elementCount = 0; 99 vbo = 0; 100} 101 102/////////////////////////////////////////////////////////////////////////////// 103// OffscreenBufferPool 104/////////////////////////////////////////////////////////////////////////////// 105 106OffscreenBufferPool::OffscreenBufferPool() 107 : mMaxSize(Properties::layerPoolSize) { 108} 109 110OffscreenBufferPool::~OffscreenBufferPool() { 111 clear(); // TODO: unique_ptr? 112} 113 114int OffscreenBufferPool::Entry::compare(const Entry& lhs, const Entry& rhs) { 115 int deltaInt = int(lhs.width) - int(rhs.width); 116 if (deltaInt != 0) return deltaInt; 117 118 return int(lhs.height) - int(rhs.height); 119} 120 121void OffscreenBufferPool::clear() { 122 for (auto entry : mPool) { 123 delete entry.layer; 124 } 125 mPool.clear(); 126 mSize = 0; 127} 128 129OffscreenBuffer* OffscreenBufferPool::get(RenderState& renderState, 130 const uint32_t width, const uint32_t height) { 131 OffscreenBuffer* layer = nullptr; 132 133 Entry entry(width, height); 134 auto iter = mPool.find(entry); 135 136 if (iter != mPool.end()) { 137 entry = *iter; 138 mPool.erase(iter); 139 140 layer = entry.layer; 141 layer->viewportWidth = width; 142 layer->viewportHeight = height; 143 mSize -= layer->getSizeInBytes(); 144 } else { 145 layer = new OffscreenBuffer(renderState, Caches::getInstance(), width, height); 146 } 147 148 return layer; 149} 150 151OffscreenBuffer* OffscreenBufferPool::resize(OffscreenBuffer* layer, 152 const uint32_t width, const uint32_t height) { 153 RenderState& renderState = layer->renderState; 154 if (layer->texture.width == OffscreenBuffer::computeIdealDimension(width) 155 && layer->texture.height == OffscreenBuffer::computeIdealDimension(height)) { 156 // resize in place 157 layer->viewportWidth = width; 158 layer->viewportHeight = height; 159 return layer; 160 } 161 putOrDelete(layer); 162 return get(renderState, width, height); 163} 164 165void OffscreenBufferPool::dump() { 166 for (auto entry : mPool) { 167 ALOGD(" Layer size %dx%d", entry.width, entry.height); 168 } 169} 170 171void OffscreenBufferPool::putOrDelete(OffscreenBuffer* layer) { 172 const uint32_t size = layer->getSizeInBytes(); 173 // Don't even try to cache a layer that's bigger than the cache 174 if (size < mMaxSize) { 175 // TODO: Use an LRU 176 while (mSize + size > mMaxSize) { 177 OffscreenBuffer* victim = mPool.begin()->layer; 178 mSize -= victim->getSizeInBytes(); 179 delete victim; 180 mPool.erase(mPool.begin()); 181 } 182 183 // clear region, since it's no longer valid 184 layer->region.clear(); 185 186 Entry entry(layer); 187 188 mPool.insert(entry); 189 mSize += size; 190 } else { 191 delete layer; 192 } 193} 194 195}; // namespace uirenderer 196}; // namespace android 197