2 * Copyright (C) 2010 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #define LOG_TAG "OpenGLRenderer"
21 #include "DisplayListRenderer.h"
22 #include "GammaFontRenderer.h"
23 #include "LayerRenderer.h"
24 #include "Properties.h"
25 #include "renderstate/RenderState.h"
26 #include "ShadowTessellator.h"
28 #include <utils/Log.h>
29 #include <utils/String8.h>
32 namespace uirenderer {
34 Caches* Caches::sInstance = nullptr;
36 ///////////////////////////////////////////////////////////////////////////////
38 ///////////////////////////////////////////////////////////////////////////////
41 #define FLUSH_LOGD(...) ALOGD(__VA_ARGS__)
43 #define FLUSH_LOGD(...)
46 ///////////////////////////////////////////////////////////////////////////////
47 // Constructors/destructor
48 ///////////////////////////////////////////////////////////////////////////////
50 Caches::Caches(RenderState& renderState)
51 : gradientCache(mExtensions)
52 , patchCache(renderState)
53 , programCache(mExtensions)
55 , mRenderState(&renderState)
56 , mInitialized(false) {
57 INIT_LOGD("Creating OpenGL renderer caches");
62 initStaticProperties();
66 mDebugLevel = readDebugLevel();
67 ALOGD_IF(mDebugLevel != kDebugDisabled,
68 "Enabling debug mode %d", mDebugLevel);
72 if (mInitialized) return false;
74 ATRACE_NAME("Caches::init");
76 mRegionMesh = nullptr;
81 debugLayersUpdates = false;
82 debugOverdraw = false;
83 debugStencilClip = kStencilHide;
89 mPixelBufferState = new PixelBufferState();
90 mTextureState = new TextureState();
95 void Caches::initFont() {
96 fontRenderer = GammaFontRenderer::createRenderer();
99 void Caches::initExtensions() {
100 if (mExtensions.hasDebugMarker()) {
101 eventMark = glInsertEventMarkerEXT;
103 startMark = glPushGroupMarkerEXT;
104 endMark = glPopGroupMarkerEXT;
106 eventMark = eventMarkNull;
107 startMark = startMarkNull;
108 endMark = endMarkNull;
112 void Caches::initConstraints() {
113 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
116 void Caches::initStaticProperties() {
117 gpuPixelBuffersEnabled = false;
119 // OpenGL ES 3.0+ specific features
120 if (mExtensions.hasPixelBufferObjects()) {
121 char property[PROPERTY_VALUE_MAX];
122 if (property_get(PROPERTY_ENABLE_GPU_PIXEL_BUFFERS, property, "true") > 0) {
123 gpuPixelBuffersEnabled = !strcmp(property, "true");
128 bool Caches::initProperties() {
129 bool prevDebugLayersUpdates = debugLayersUpdates;
130 bool prevDebugOverdraw = debugOverdraw;
131 StencilClipDebug prevDebugStencilClip = debugStencilClip;
133 char property[PROPERTY_VALUE_MAX];
134 if (property_get(PROPERTY_DEBUG_LAYERS_UPDATES, property, nullptr) > 0) {
135 INIT_LOGD(" Layers updates debug enabled: %s", property);
136 debugLayersUpdates = !strcmp(property, "true");
138 debugLayersUpdates = false;
141 debugOverdraw = false;
142 if (property_get(PROPERTY_DEBUG_OVERDRAW, property, nullptr) > 0) {
143 INIT_LOGD(" Overdraw debug enabled: %s", property);
144 if (!strcmp(property, "show")) {
145 debugOverdraw = true;
146 mOverdrawDebugColorSet = kColorSet_Default;
147 } else if (!strcmp(property, "show_deuteranomaly")) {
148 debugOverdraw = true;
149 mOverdrawDebugColorSet = kColorSet_Deuteranomaly;
153 // See Properties.h for valid values
154 if (property_get(PROPERTY_DEBUG_STENCIL_CLIP, property, nullptr) > 0) {
155 INIT_LOGD(" Stencil clip debug enabled: %s", property);
156 if (!strcmp(property, "hide")) {
157 debugStencilClip = kStencilHide;
158 } else if (!strcmp(property, "highlight")) {
159 debugStencilClip = kStencilShowHighlight;
160 } else if (!strcmp(property, "region")) {
161 debugStencilClip = kStencilShowRegion;
164 debugStencilClip = kStencilHide;
167 if (property_get(PROPERTY_DISABLE_DRAW_DEFER, property, "false")) {
168 drawDeferDisabled = !strcasecmp(property, "true");
169 INIT_LOGD(" Draw defer %s", drawDeferDisabled ? "disabled" : "enabled");
171 drawDeferDisabled = false;
172 INIT_LOGD(" Draw defer enabled");
175 if (property_get(PROPERTY_DISABLE_DRAW_REORDER, property, "false")) {
176 drawReorderDisabled = !strcasecmp(property, "true");
177 INIT_LOGD(" Draw reorder %s", drawReorderDisabled ? "disabled" : "enabled");
179 drawReorderDisabled = false;
180 INIT_LOGD(" Draw reorder enabled");
183 return (prevDebugLayersUpdates != debugLayersUpdates)
184 || (prevDebugOverdraw != debugOverdraw)
185 || (prevDebugStencilClip != debugStencilClip);
188 void Caches::terminate() {
189 if (!mInitialized) return;
190 mRegionMesh.release();
194 programCache.clear();
201 delete mPixelBufferState;
202 mPixelBufferState = nullptr;
203 delete mTextureState;
204 mTextureState = nullptr;
205 mInitialized = false;
208 void Caches::setProgram(const ProgramDescription& description) {
209 setProgram(programCache.get(description));
212 void Caches::setProgram(Program* program) {
213 if (!program || !program->isInUse()) {
224 ///////////////////////////////////////////////////////////////////////////////
226 ///////////////////////////////////////////////////////////////////////////////
228 uint32_t Caches::getOverdrawColor(uint32_t amount) const {
229 static uint32_t sOverdrawColors[2][4] = {
230 { 0x2f0000ff, 0x2f00ff00, 0x3fff0000, 0x7fff0000 },
231 { 0x2f0000ff, 0x4fffff00, 0x5fff8ad8, 0x7fff0000 }
233 if (amount < 1) amount = 1;
234 if (amount > 4) amount = 4;
235 return sOverdrawColors[mOverdrawDebugColorSet][amount - 1];
238 void Caches::dumpMemoryUsage() {
240 dumpMemoryUsage(stringLog);
241 ALOGD("%s", stringLog.string());
244 void Caches::dumpMemoryUsage(String8 &log) {
246 log.appendFormat("Current memory usage / total memory usage (bytes):\n");
247 log.appendFormat(" TextureCache %8d / %8d\n",
248 textureCache.getSize(), textureCache.getMaxSize());
249 log.appendFormat(" LayerCache %8d / %8d (numLayers = %zu)\n",
250 layerCache.getSize(), layerCache.getMaxSize(), layerCache.getCount());
253 for (std::set<Layer*>::iterator it = mRenderState->mActiveLayers.begin();
254 it != mRenderState->mActiveLayers.end(); it++) {
255 const Layer* layer = *it;
256 log.appendFormat(" Layer size %dx%d; isTextureLayer()=%d; texid=%u fbo=%u; refs=%d\n",
257 layer->getWidth(), layer->getHeight(),
258 layer->isTextureLayer(), layer->getTextureId(),
259 layer->getFbo(), layer->getStrongCount());
260 memused += layer->getWidth() * layer->getHeight() * 4;
262 log.appendFormat(" Layers total %8d (numLayers = %zu)\n",
263 memused, mRenderState->mActiveLayers.size());
266 log.appendFormat(" RenderBufferCache %8d / %8d\n",
267 renderBufferCache.getSize(), renderBufferCache.getMaxSize());
268 log.appendFormat(" GradientCache %8d / %8d\n",
269 gradientCache.getSize(), gradientCache.getMaxSize());
270 log.appendFormat(" PathCache %8d / %8d\n",
271 pathCache.getSize(), pathCache.getMaxSize());
272 log.appendFormat(" TessellationCache %8d / %8d\n",
273 tessellationCache.getSize(), tessellationCache.getMaxSize());
274 log.appendFormat(" TextDropShadowCache %8d / %8d\n", dropShadowCache.getSize(),
275 dropShadowCache.getMaxSize());
276 log.appendFormat(" PatchCache %8d / %8d\n",
277 patchCache.getSize(), patchCache.getMaxSize());
278 for (uint32_t i = 0; i < fontRenderer->getFontRendererCount(); i++) {
279 const uint32_t sizeA8 = fontRenderer->getFontRendererSize(i, GL_ALPHA);
280 const uint32_t sizeRGBA = fontRenderer->getFontRendererSize(i, GL_RGBA);
281 log.appendFormat(" FontRenderer %d A8 %8d / %8d\n", i, sizeA8, sizeA8);
282 log.appendFormat(" FontRenderer %d RGBA %8d / %8d\n", i, sizeRGBA, sizeRGBA);
283 log.appendFormat(" FontRenderer %d total %8d / %8d\n", i, sizeA8 + sizeRGBA,
286 log.appendFormat("Other:\n");
287 log.appendFormat(" FboCache %8d / %8d\n",
288 fboCache.getSize(), fboCache.getMaxSize());
290 total += textureCache.getSize();
291 total += renderBufferCache.getSize();
292 total += gradientCache.getSize();
293 total += pathCache.getSize();
294 total += tessellationCache.getSize();
295 total += dropShadowCache.getSize();
296 total += patchCache.getSize();
297 for (uint32_t i = 0; i < fontRenderer->getFontRendererCount(); i++) {
298 total += fontRenderer->getFontRendererSize(i, GL_ALPHA);
299 total += fontRenderer->getFontRendererSize(i, GL_RGBA);
302 log.appendFormat("Total memory usage:\n");
303 log.appendFormat(" %d bytes, %.2f MB\n", total, total / 1024.0f / 1024.0f);
306 ///////////////////////////////////////////////////////////////////////////////
308 ///////////////////////////////////////////////////////////////////////////////
310 void Caches::clearGarbage() {
311 textureCache.clearGarbage();
312 pathCache.clearGarbage();
313 patchCache.clearGarbage();
316 void Caches::flush(FlushMode mode) {
317 FLUSH_LOGD("Flushing caches (mode %d)", mode);
319 // We must stop tasks before clearing caches
320 if (mode > kFlushMode_Layers) {
325 case kFlushMode_Full:
326 textureCache.clear();
328 dropShadowCache.clear();
329 gradientCache.clear();
330 fontRenderer->clear();
334 case kFlushMode_Moderate:
335 fontRenderer->flush();
336 textureCache.flush();
338 tessellationCache.clear();
340 case kFlushMode_Layers:
342 renderBufferCache.clear();
350 ///////////////////////////////////////////////////////////////////////////////
352 ///////////////////////////////////////////////////////////////////////////////
354 void Caches::startTiling(GLuint x, GLuint y, GLuint width, GLuint height, bool discard) {
355 if (mExtensions.hasTiledRendering() && !debugOverdraw) {
356 glStartTilingQCOM(x, y, width, height, (discard ? GL_NONE : GL_COLOR_BUFFER_BIT0_QCOM));
360 void Caches::endTiling() {
361 if (mExtensions.hasTiledRendering() && !debugOverdraw) {
362 glEndTilingQCOM(GL_COLOR_BUFFER_BIT0_QCOM);
366 bool Caches::hasRegisteredFunctors() {
367 return mFunctorsCount > 0;
370 void Caches::registerFunctors(uint32_t functorCount) {
371 mFunctorsCount += functorCount;
374 void Caches::unregisterFunctors(uint32_t functorCount) {
375 if (functorCount > mFunctorsCount) {
378 mFunctorsCount -= functorCount;
382 ///////////////////////////////////////////////////////////////////////////////
384 ///////////////////////////////////////////////////////////////////////////////
386 TextureVertex* Caches::getRegionMesh() {
387 // Create the mesh, 2 triangles and 4 vertices per rectangle in the region
389 mRegionMesh.reset(new TextureVertex[kMaxNumberOfQuads * 4]);
392 return mRegionMesh.get();
395 ///////////////////////////////////////////////////////////////////////////////
396 // Temporary Properties
397 ///////////////////////////////////////////////////////////////////////////////
399 void Caches::initTempProperties() {
400 propertyLightRadius = -1.0f;
401 propertyLightPosY = -1.0f;
402 propertyLightPosZ = -1.0f;
403 propertyAmbientRatio = -1.0f;
404 propertyAmbientShadowStrength = -1;
405 propertySpotShadowStrength = -1;
408 void Caches::setTempProperty(const char* name, const char* value) {
409 ALOGD("setting property %s to %s", name, value);
410 if (!strcmp(name, "ambientRatio")) {
411 propertyAmbientRatio = fmin(fmax(atof(value), 0.0), 10.0);
412 ALOGD("ambientRatio = %.2f", propertyAmbientRatio);
414 } else if (!strcmp(name, "lightRadius")) {
415 propertyLightRadius = fmin(fmax(atof(value), 0.0), 3000.0);
416 ALOGD("lightRadius = %.2f", propertyLightRadius);
418 } else if (!strcmp(name, "lightPosY")) {
419 propertyLightPosY = fmin(fmax(atof(value), 0.0), 3000.0);
420 ALOGD("lightPos Y = %.2f", propertyLightPosY);
422 } else if (!strcmp(name, "lightPosZ")) {
423 propertyLightPosZ = fmin(fmax(atof(value), 0.0), 3000.0);
424 ALOGD("lightPos Z = %.2f", propertyLightPosZ);
426 } else if (!strcmp(name, "ambientShadowStrength")) {
427 propertyAmbientShadowStrength = atoi(value);
428 ALOGD("ambient shadow strength = 0x%x out of 0xff", propertyAmbientShadowStrength);
430 } else if (!strcmp(name, "spotShadowStrength")) {
431 propertySpotShadowStrength = atoi(value);
432 ALOGD("spot shadow strength = 0x%x out of 0xff", propertySpotShadowStrength);
438 }; // namespace uirenderer
439 }; // namespace android