1/* 2 * Copyright (C) 2007 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 <stdlib.h> 18#include <stdint.h> 19#include <sys/types.h> 20 21#include <utils/Errors.h> 22#include <utils/Log.h> 23 24#include <GLES/gl.h> 25#include <GLES/glext.h> 26 27#include "clz.h" 28#include "BlurFilter.h" 29#include "LayerBlur.h" 30#include "SurfaceFlinger.h" 31#include "DisplayHardware/DisplayHardware.h" 32 33namespace android { 34// --------------------------------------------------------------------------- 35 36const uint32_t LayerBlur::typeInfo = LayerBaseClient::typeInfo | 8; 37const char* const LayerBlur::typeID = "LayerBlur"; 38 39// --------------------------------------------------------------------------- 40 41LayerBlur::LayerBlur(SurfaceFlinger* flinger, DisplayID display, 42 const sp<Client>& client, int32_t i) 43 : LayerBaseClient(flinger, display, client, i), mCacheDirty(true), 44 mRefreshCache(true), mCacheAge(0), mTextureName(-1U), 45 mWidthScale(1.0f), mHeightScale(1.0f), 46 mBlurFormat(GGL_PIXEL_FORMAT_RGB_565) 47{ 48} 49 50LayerBlur::~LayerBlur() 51{ 52 if (mTextureName != -1U) { 53 glDeleteTextures(1, &mTextureName); 54 } 55} 56 57void LayerBlur::setVisibleRegion(const Region& visibleRegion) 58{ 59 LayerBaseClient::setVisibleRegion(visibleRegion); 60 if (visibleRegionScreen.isEmpty()) { 61 if (mTextureName != -1U) { 62 // We're not visible, free the texture up. 63 glBindTexture(GL_TEXTURE_2D, 0); 64 glDeleteTextures(1, &mTextureName); 65 mTextureName = -1U; 66 } 67 } 68} 69 70uint32_t LayerBlur::doTransaction(uint32_t flags) 71{ 72 // we're doing a transaction, refresh the cache! 73 if (!mFlinger->isFrozen()) { 74 mRefreshCache = true; 75 mCacheDirty = true; 76 flags |= eVisibleRegion; 77 this->contentDirty = true; 78 } 79 return LayerBase::doTransaction(flags); 80} 81 82void LayerBlur::unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion) 83{ 84 // this code-path must be as tight as possible, it's called each time 85 // the screen is composited. 86 if (UNLIKELY(!visibleRegionScreen.isEmpty())) { 87 // if anything visible below us is invalidated, the cache becomes dirty 88 if (!mCacheDirty && 89 !visibleRegionScreen.intersect(outDirtyRegion).isEmpty()) { 90 mCacheDirty = true; 91 } 92 if (mCacheDirty) { 93 if (!mFlinger->isFrozen()) { 94 // update everything below us that is visible 95 outDirtyRegion.orSelf(visibleRegionScreen); 96 nsecs_t now = systemTime(); 97 if ((now - mCacheAge) >= ms2ns(500)) { 98 mCacheAge = now; 99 mRefreshCache = true; 100 mCacheDirty = false; 101 } else { 102 if (!mAutoRefreshPending) { 103 mFlinger->signalDelayedEvent(ms2ns(500)); 104 mAutoRefreshPending = true; 105 } 106 } 107 } 108 } 109 } 110 LayerBase::unlockPageFlip(planeTransform, outDirtyRegion); 111} 112 113void LayerBlur::onDraw(const Region& clip) const 114{ 115 const DisplayHardware& hw(graphicPlane(0).displayHardware()); 116 const uint32_t fbHeight = hw.getHeight(); 117 int x = mTransformedBounds.left; 118 int y = mTransformedBounds.top; 119 int w = mTransformedBounds.width(); 120 int h = mTransformedBounds.height(); 121 GLint X = x; 122 GLint Y = fbHeight - (y + h); 123 if (X < 0) { 124 w += X; 125 X = 0; 126 } 127 if (Y < 0) { 128 h += Y; 129 Y = 0; 130 } 131 if (w<0 || h<0) { 132 // we're outside of the framebuffer 133 return; 134 } 135 136 if (mTextureName == -1U) { 137 // create the texture name the first time 138 // can't do that in the ctor, because it runs in another thread. 139 glGenTextures(1, &mTextureName); 140 glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES, &mReadFormat); 141 glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE_OES, &mReadType); 142 if (mReadFormat != GL_RGB || mReadType != GL_UNSIGNED_SHORT_5_6_5) { 143 mReadFormat = GL_RGBA; 144 mReadType = GL_UNSIGNED_BYTE; 145 mBlurFormat = GGL_PIXEL_FORMAT_RGBX_8888; 146 } 147 } 148 149 Region::const_iterator it = clip.begin(); 150 Region::const_iterator const end = clip.end(); 151 if (it != end) { 152 glEnable(GL_TEXTURE_2D); 153 glBindTexture(GL_TEXTURE_2D, mTextureName); 154 155 if (mRefreshCache) { 156 mRefreshCache = false; 157 mAutoRefreshPending = false; 158 159 int32_t pixelSize = 4; 160 int32_t s = w; 161 if (mReadType == GL_UNSIGNED_SHORT_5_6_5) { 162 // allocate enough memory for 4-bytes (2 pixels) aligned data 163 s = (w + 1) & ~1; 164 pixelSize = 2; 165 } 166 167 uint16_t* const pixels = (uint16_t*)malloc(s*h*pixelSize); 168 169 // This reads the frame-buffer, so a h/w GL would have to 170 // finish() its rendering first. we don't want to do that 171 // too often. Read data is 4-bytes aligned. 172 glReadPixels(X, Y, w, h, mReadFormat, mReadType, pixels); 173 174 // blur that texture. 175 GGLSurface bl; 176 bl.version = sizeof(GGLSurface); 177 bl.width = w; 178 bl.height = h; 179 bl.stride = s; 180 bl.format = mBlurFormat; 181 bl.data = (GGLubyte*)pixels; 182 blurFilter(&bl, 8, 2); 183 184 if (mFlags & (DisplayHardware::NPOT_EXTENSION)) { 185 glTexImage2D(GL_TEXTURE_2D, 0, mReadFormat, w, h, 0, 186 mReadFormat, mReadType, pixels); 187 mWidthScale = 1.0f / w; 188 mHeightScale =-1.0f / h; 189 mYOffset = 0; 190 } else { 191 GLuint tw = 1 << (31 - clz(w)); 192 GLuint th = 1 << (31 - clz(h)); 193 if (tw < GLuint(w)) tw <<= 1; 194 if (th < GLuint(h)) th <<= 1; 195 glTexImage2D(GL_TEXTURE_2D, 0, mReadFormat, tw, th, 0, 196 mReadFormat, mReadType, NULL); 197 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, 198 mReadFormat, mReadType, pixels); 199 mWidthScale = 1.0f / tw; 200 mHeightScale =-1.0f / th; 201 mYOffset = th-h; 202 } 203 204 free((void*)pixels); 205 } 206 207 const State& s = drawingState(); 208 if (UNLIKELY(s.alpha < 0xFF)) { 209 const GGLfixed alpha = (s.alpha << 16)/255; 210 glColor4x(0, 0, 0, alpha); 211 glEnable(GL_BLEND); 212 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 213 glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); 214 } else { 215 glDisable(GL_BLEND); 216 } 217 218 if (mFlags & DisplayHardware::SLOW_CONFIG) { 219 glDisable(GL_DITHER); 220 } else { 221 glEnable(GL_DITHER); 222 } 223 224 glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); 225 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 226 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 227 228 if (UNLIKELY(transformed() 229 || !(mFlags & DisplayHardware::DRAW_TEXTURE_EXTENSION) )) { 230 // This is a very rare scenario. 231 glMatrixMode(GL_TEXTURE); 232 glLoadIdentity(); 233 glScalef(mWidthScale, mHeightScale, 1); 234 glTranslatef(-x, mYOffset - y, 0); 235 glEnableClientState(GL_TEXTURE_COORD_ARRAY); 236 glVertexPointer(2, GL_FIXED, 0, mVertices); 237 glTexCoordPointer(2, GL_FIXED, 0, mVertices); 238 while (it != end) { 239 const Rect& r = *it++; 240 const GLint sy = fbHeight - (r.top + r.height()); 241 glScissor(r.left, sy, r.width(), r.height()); 242 glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 243 } 244 glDisableClientState(GL_TEXTURE_COORD_ARRAY); 245 } else { 246 // NOTE: this is marginally faster with the software gl, because 247 // glReadPixels() reads the fb bottom-to-top, however we'll 248 // skip all the jaccobian computations. 249 Rect r; 250 GLint crop[4] = { 0, 0, w, h }; 251 glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop); 252 y = fbHeight - (y + h); 253 while (it != end) { 254 const Rect& r = *it++; 255 const GLint sy = fbHeight - (r.top + r.height()); 256 glScissor(r.left, sy, r.width(), r.height()); 257 glDrawTexiOES(x, y, 0, w, h); 258 } 259 } 260 } 261} 262 263// --------------------------------------------------------------------------- 264 265}; // namespace android 266