blob: e08861d371a5a5fb8a02da03c46338ce34a7c8c4 [file] [log] [blame]
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001/*
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
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080017#include <stdlib.h>
18#include <stdint.h>
19#include <sys/types.h>
20
21#include <utils/Errors.h>
22#include <utils/Log.h>
Mathias Agopian310f8da2009-05-22 01:27:01 -070023#include <binder/IPCThreadState.h>
24#include <binder/IServiceManager.h>
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080025
26#include <GLES/gl.h>
27#include <GLES/glext.h>
28
29#include <hardware/hardware.h>
30
31#include "clz.h"
32#include "LayerBase.h"
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080033#include "SurfaceFlinger.h"
34#include "DisplayHardware/DisplayHardware.h"
35
36
37// We don't honor the premultiplied alpha flags, which means that
38// premultiplied surface may be composed using a non-premultiplied
39// equation. We do this because it may be a lot faster on some hardware
40// The correct value is HONOR_PREMULTIPLIED_ALPHA = 1
41#define HONOR_PREMULTIPLIED_ALPHA 0
42
43namespace android {
44
45// ---------------------------------------------------------------------------
46
47const uint32_t LayerBase::typeInfo = 1;
48const char* const LayerBase::typeID = "LayerBase";
49
50const uint32_t LayerBaseClient::typeInfo = LayerBase::typeInfo | 2;
51const char* const LayerBaseClient::typeID = "LayerBaseClient";
52
53// ---------------------------------------------------------------------------
54
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080055LayerBase::LayerBase(SurfaceFlinger* flinger, DisplayID display)
56 : dpy(display), contentDirty(false),
57 mFlinger(flinger),
58 mTransformed(false),
59 mOrientation(0),
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080060 mTransactionFlags(0),
61 mPremultipliedAlpha(true),
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080062 mInvalidate(0)
63{
64 const DisplayHardware& hw(flinger->graphicPlane(0).displayHardware());
65 mFlags = hw.getFlags();
66}
67
68LayerBase::~LayerBase()
69{
70}
71
72const GraphicPlane& LayerBase::graphicPlane(int dpy) const
73{
74 return mFlinger->graphicPlane(dpy);
75}
76
77GraphicPlane& LayerBase::graphicPlane(int dpy)
78{
79 return mFlinger->graphicPlane(dpy);
80}
81
82void LayerBase::initStates(uint32_t w, uint32_t h, uint32_t flags)
83{
84 uint32_t layerFlags = 0;
85 if (flags & ISurfaceComposer::eHidden)
86 layerFlags = ISurfaceComposer::eLayerHidden;
87
88 if (flags & ISurfaceComposer::eNonPremultiplied)
89 mPremultipliedAlpha = false;
90
91 mCurrentState.z = 0;
92 mCurrentState.w = w;
93 mCurrentState.h = h;
94 mCurrentState.alpha = 0xFF;
95 mCurrentState.flags = layerFlags;
96 mCurrentState.sequence = 0;
97 mCurrentState.transform.set(0, 0);
98
99 // drawing state & current state are identical
100 mDrawingState = mCurrentState;
101}
102
103void LayerBase::commitTransaction(bool skipSize) {
104 const uint32_t w = mDrawingState.w;
105 const uint32_t h = mDrawingState.h;
106 mDrawingState = mCurrentState;
107 if (skipSize) {
108 mDrawingState.w = w;
109 mDrawingState.h = h;
110 }
111}
112void LayerBase::forceVisibilityTransaction() {
113 // this can be called without SurfaceFlinger.mStateLock, but if we
114 // can atomically increment the sequence number, it doesn't matter.
115 android_atomic_inc(&mCurrentState.sequence);
116 requestTransaction();
117}
118bool LayerBase::requestTransaction() {
119 int32_t old = setTransactionFlags(eTransactionNeeded);
120 return ((old & eTransactionNeeded) == 0);
121}
122uint32_t LayerBase::getTransactionFlags(uint32_t flags) {
123 return android_atomic_and(~flags, &mTransactionFlags) & flags;
124}
125uint32_t LayerBase::setTransactionFlags(uint32_t flags) {
126 return android_atomic_or(flags, &mTransactionFlags);
127}
128
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800129bool LayerBase::setPosition(int32_t x, int32_t y) {
130 if (mCurrentState.transform.tx() == x && mCurrentState.transform.ty() == y)
131 return false;
132 mCurrentState.sequence++;
133 mCurrentState.transform.set(x, y);
134 requestTransaction();
135 return true;
136}
137bool LayerBase::setLayer(uint32_t z) {
138 if (mCurrentState.z == z)
139 return false;
140 mCurrentState.sequence++;
141 mCurrentState.z = z;
142 requestTransaction();
143 return true;
144}
145bool LayerBase::setSize(uint32_t w, uint32_t h) {
146 if (mCurrentState.w == w && mCurrentState.h == h)
147 return false;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800148 mCurrentState.w = w;
149 mCurrentState.h = h;
150 requestTransaction();
151 return true;
152}
153bool LayerBase::setAlpha(uint8_t alpha) {
154 if (mCurrentState.alpha == alpha)
155 return false;
156 mCurrentState.sequence++;
157 mCurrentState.alpha = alpha;
158 requestTransaction();
159 return true;
160}
161bool LayerBase::setMatrix(const layer_state_t::matrix22_t& matrix) {
162 // TODO: check the matrix has changed
163 mCurrentState.sequence++;
164 mCurrentState.transform.set(
165 matrix.dsdx, matrix.dsdy, matrix.dtdx, matrix.dtdy);
166 requestTransaction();
167 return true;
168}
169bool LayerBase::setTransparentRegionHint(const Region& transparent) {
170 // TODO: check the region has changed
171 mCurrentState.sequence++;
172 mCurrentState.transparentRegion = transparent;
173 requestTransaction();
174 return true;
175}
176bool LayerBase::setFlags(uint8_t flags, uint8_t mask) {
177 const uint32_t newFlags = (mCurrentState.flags & ~mask) | (flags & mask);
178 if (mCurrentState.flags == newFlags)
179 return false;
180 mCurrentState.sequence++;
181 mCurrentState.flags = newFlags;
182 requestTransaction();
183 return true;
184}
185
186Rect LayerBase::visibleBounds() const
187{
188 return mTransformedBounds;
189}
190
191void LayerBase::setVisibleRegion(const Region& visibleRegion) {
192 // always called from main thread
193 visibleRegionScreen = visibleRegion;
194}
195
196void LayerBase::setCoveredRegion(const Region& coveredRegion) {
197 // always called from main thread
198 coveredRegionScreen = coveredRegion;
199}
200
201uint32_t LayerBase::doTransaction(uint32_t flags)
202{
203 const Layer::State& front(drawingState());
204 const Layer::State& temp(currentState());
205
206 if (temp.sequence != front.sequence) {
207 // invalidate and recompute the visible regions if needed
208 flags |= eVisibleRegion;
209 this->contentDirty = true;
210 }
211
212 // Commit the transaction
213 commitTransaction(flags & eRestartTransaction);
214 return flags;
215}
216
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800217void LayerBase::validateVisibility(const Transform& planeTransform)
218{
219 const Layer::State& s(drawingState());
220 const Transform tr(planeTransform * s.transform);
221 const bool transformed = tr.transformed();
222
Mathias Agopiancbb288b2009-09-07 16:32:45 -0700223 uint32_t w = s.w;
224 uint32_t h = s.h;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800225 tr.transform(mVertices[0], 0, 0);
226 tr.transform(mVertices[1], 0, h);
227 tr.transform(mVertices[2], w, h);
228 tr.transform(mVertices[3], w, 0);
229 if (UNLIKELY(transformed)) {
230 // NOTE: here we could also punt if we have too many rectangles
231 // in the transparent region
232 if (tr.preserveRects()) {
233 // transform the transparent region
234 transparentRegionScreen = tr.transform(s.transparentRegion);
235 } else {
236 // transformation too complex, can't do the transparent region
237 // optimization.
238 transparentRegionScreen.clear();
239 }
240 } else {
241 transparentRegionScreen = s.transparentRegion;
242 }
243
244 // cache a few things...
245 mOrientation = tr.getOrientation();
246 mTransformedBounds = tr.makeBounds(w, h);
247 mTransformed = transformed;
248 mLeft = tr.tx();
249 mTop = tr.ty();
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800250}
251
252void LayerBase::lockPageFlip(bool& recomputeVisibleRegions)
253{
254}
255
256void LayerBase::unlockPageFlip(
257 const Transform& planeTransform, Region& outDirtyRegion)
258{
259 if ((android_atomic_and(~1, &mInvalidate)&1) == 1) {
260 outDirtyRegion.orSelf(visibleRegionScreen);
261 }
262}
263
264void LayerBase::finishPageFlip()
265{
266}
267
268void LayerBase::invalidate()
269{
270 if ((android_atomic_or(1, &mInvalidate)&1) == 0) {
271 mFlinger->signalEvent();
272 }
273}
274
275void LayerBase::drawRegion(const Region& reg) const
276{
Mathias Agopian20f68782009-05-11 00:03:41 -0700277 Region::const_iterator it = reg.begin();
278 Region::const_iterator const end = reg.end();
279 if (it != end) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800280 Rect r;
281 const DisplayHardware& hw(graphicPlane(0).displayHardware());
282 const int32_t fbWidth = hw.getWidth();
283 const int32_t fbHeight = hw.getHeight();
284 const GLshort vertices[][2] = { { 0, 0 }, { fbWidth, 0 },
285 { fbWidth, fbHeight }, { 0, fbHeight } };
286 glVertexPointer(2, GL_SHORT, 0, vertices);
Mathias Agopian20f68782009-05-11 00:03:41 -0700287 while (it != end) {
288 const Rect& r = *it++;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800289 const GLint sy = fbHeight - (r.top + r.height());
290 glScissor(r.left, sy, r.width(), r.height());
291 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
292 }
293 }
294}
295
296void LayerBase::draw(const Region& inClip) const
297{
298 // invalidate the region we'll update
299 Region clip(inClip); // copy-on-write, so no-op most of the time
300
301 // Remove the transparent area from the clipping region
302 const State& s = drawingState();
303 if (LIKELY(!s.transparentRegion.isEmpty())) {
304 clip.subtract(transparentRegionScreen);
305 if (clip.isEmpty()) {
306 // usually this won't happen because this should be taken care of
307 // by SurfaceFlinger::computeVisibleRegions()
308 return;
309 }
310 }
311
312 // reset GL state
313 glEnable(GL_SCISSOR_TEST);
314
315 onDraw(clip);
316
317 /*
318 glDisable(GL_TEXTURE_2D);
319 glDisable(GL_DITHER);
320 glEnable(GL_BLEND);
321 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
322 glColor4x(0, 0x8000, 0, 0x10000);
323 drawRegion(transparentRegionScreen);
324 glDisable(GL_BLEND);
325 */
326}
327
328GLuint LayerBase::createTexture() const
329{
330 GLuint textureName = -1;
331 glGenTextures(1, &textureName);
332 glBindTexture(GL_TEXTURE_2D, textureName);
333 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
334 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
335 if (mFlags & DisplayHardware::SLOW_CONFIG) {
336 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
337 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
338 } else {
339 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
340 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
341 }
342 return textureName;
343}
344
Rebecca Schultz Zavin29aa74c2009-09-01 23:06:45 -0700345void LayerBase::clearWithOpenGL(const Region& clip, GLclampx red,
346 GLclampx green, GLclampx blue,
347 GLclampx alpha) const
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800348{
349 const DisplayHardware& hw(graphicPlane(0).displayHardware());
350 const uint32_t fbHeight = hw.getHeight();
Rebecca Schultz Zavin29aa74c2009-09-01 23:06:45 -0700351 glColor4x(red,green,blue,alpha);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800352 glDisable(GL_TEXTURE_2D);
353 glDisable(GL_BLEND);
354 glDisable(GL_DITHER);
Mathias Agopian20f68782009-05-11 00:03:41 -0700355
356 Region::const_iterator it = clip.begin();
357 Region::const_iterator const end = clip.end();
358 if (it != end) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800359 glEnable(GL_SCISSOR_TEST);
360 glVertexPointer(2, GL_FIXED, 0, mVertices);
Mathias Agopian20f68782009-05-11 00:03:41 -0700361 while (it != end) {
362 const Rect& r = *it++;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800363 const GLint sy = fbHeight - (r.top + r.height());
364 glScissor(r.left, sy, r.width(), r.height());
365 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
366 }
367 }
368}
369
Rebecca Schultz Zavin29aa74c2009-09-01 23:06:45 -0700370void LayerBase::clearWithOpenGL(const Region& clip) const
371{
372 clearWithOpenGL(clip,0,0,0,0);
373}
374
Mathias Agopian1fed11c2009-06-23 18:08:22 -0700375void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800376{
377 const DisplayHardware& hw(graphicPlane(0).displayHardware());
378 const uint32_t fbHeight = hw.getHeight();
379 const State& s(drawingState());
Mathias Agopian0926f502009-05-04 14:17:04 -0700380
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800381 // bind our texture
Mathias Agopian1fed11c2009-06-23 18:08:22 -0700382 validateTexture(texture.name);
383 uint32_t width = texture.width;
384 uint32_t height = texture.height;
385
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800386 glEnable(GL_TEXTURE_2D);
387
388 // Dithering...
Mathias Agopian888eee62009-09-04 17:27:16 -0700389 bool fast = !(mFlags & DisplayHardware::SLOW_CONFIG);
390 if (fast || s.flags & ISurfaceComposer::eLayerDither) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800391 glEnable(GL_DITHER);
392 } else {
393 glDisable(GL_DITHER);
394 }
395
396 if (UNLIKELY(s.alpha < 0xFF)) {
397 // We have an alpha-modulation. We need to modulate all
398 // texture components by alpha because we're always using
399 // premultiplied alpha.
400
401 // If the texture doesn't have an alpha channel we can
402 // use REPLACE and switch to non premultiplied alpha
403 // blending (SRCA/ONE_MINUS_SRCA).
404
405 GLenum env, src;
406 if (needsBlending()) {
407 env = GL_MODULATE;
408 src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
409 } else {
410 env = GL_REPLACE;
411 src = GL_SRC_ALPHA;
412 }
413 const GGLfixed alpha = (s.alpha << 16)/255;
414 glColor4x(alpha, alpha, alpha, alpha);
415 glEnable(GL_BLEND);
416 glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);
417 glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, env);
418 } else {
419 glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
420 glColor4x(0x10000, 0x10000, 0x10000, 0x10000);
421 if (needsBlending()) {
422 GLenum src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
423 glEnable(GL_BLEND);
424 glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);
425 } else {
426 glDisable(GL_BLEND);
427 }
428 }
429
430 if (UNLIKELY(transformed()
431 || !(mFlags & DisplayHardware::DRAW_TEXTURE_EXTENSION) ))
432 {
433 //StopWatch watch("GL transformed");
Mathias Agopian20f68782009-05-11 00:03:41 -0700434 Region::const_iterator it = clip.begin();
435 Region::const_iterator const end = clip.end();
436 if (it != end) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800437 // always use high-quality filtering with fast configurations
438 bool fast = !(mFlags & DisplayHardware::SLOW_CONFIG);
439 if (!fast && s.flags & ISurfaceComposer::eLayerFilter) {
440 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
441 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
442 }
443 const GLfixed texCoords[4][2] = {
444 { 0, 0 },
445 { 0, 0x10000 },
446 { 0x10000, 0x10000 },
447 { 0x10000, 0 }
448 };
449
450 glMatrixMode(GL_TEXTURE);
451 glLoadIdentity();
452
Mathias Agopian1fed11c2009-06-23 18:08:22 -0700453 // the texture's source is rotated
454 if (texture.transform == HAL_TRANSFORM_ROT_90) {
455 // TODO: handle the other orientations
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800456 glTranslatef(0, 1, 0);
457 glRotatef(-90, 0, 0, 1);
458 }
459
Mathias Agopianf9cd64b2009-07-30 12:19:10 -0700460 if (!(mFlags & (DisplayHardware::NPOT_EXTENSION |
461 DisplayHardware::DIRECT_TEXTURE))) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800462 // find the smallest power-of-two that will accommodate our surface
Mathias Agopian0926f502009-05-04 14:17:04 -0700463 GLuint tw = 1 << (31 - clz(width));
464 GLuint th = 1 << (31 - clz(height));
465 if (tw < width) tw <<= 1;
466 if (th < height) th <<= 1;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800467 // this divide should be relatively fast because it's
468 // a power-of-two (optimized path in libgcc)
Mathias Agopian0926f502009-05-04 14:17:04 -0700469 GLfloat ws = GLfloat(width) /tw;
470 GLfloat hs = GLfloat(height)/th;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800471 glScalef(ws, hs, 1.0f);
472 }
473
474 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
475 glVertexPointer(2, GL_FIXED, 0, mVertices);
476 glTexCoordPointer(2, GL_FIXED, 0, texCoords);
477
Mathias Agopian20f68782009-05-11 00:03:41 -0700478 while (it != end) {
479 const Rect& r = *it++;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800480 const GLint sy = fbHeight - (r.top + r.height());
481 glScissor(r.left, sy, r.width(), r.height());
482 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
483 }
484
485 if (!fast && s.flags & ISurfaceComposer::eLayerFilter) {
486 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
487 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
488 }
489 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
490 }
491 } else {
Mathias Agopian20f68782009-05-11 00:03:41 -0700492 Region::const_iterator it = clip.begin();
493 Region::const_iterator const end = clip.end();
494 if (it != end) {
Mathias Agopian0926f502009-05-04 14:17:04 -0700495 GLint crop[4] = { 0, height, width, -height };
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800496 glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
497 int x = tx();
498 int y = ty();
Mathias Agopian0926f502009-05-04 14:17:04 -0700499 y = fbHeight - (y + height);
Mathias Agopian20f68782009-05-11 00:03:41 -0700500 while (it != end) {
501 const Rect& r = *it++;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800502 const GLint sy = fbHeight - (r.top + r.height());
503 glScissor(r.left, sy, r.width(), r.height());
Mathias Agopian0926f502009-05-04 14:17:04 -0700504 glDrawTexiOES(x, y, 0, width, height);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800505 }
506 }
507 }
508}
509
510void LayerBase::validateTexture(GLint textureName) const
511{
512 glBindTexture(GL_TEXTURE_2D, textureName);
513 // TODO: reload the texture if needed
514 // this is currently done in loadTexture() below
515}
516
Mathias Agopian1fed11c2009-06-23 18:08:22 -0700517void LayerBase::loadTexture(Texture* texture, GLint textureName,
518 const Region& dirty, const GGLSurface& t) const
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800519{
520 // TODO: defer the actual texture reload until LayerBase::validateTexture
521 // is called.
522
Mathias Agopian1fed11c2009-06-23 18:08:22 -0700523 texture->name = textureName;
524 GLuint& textureWidth(texture->width);
525 GLuint& textureHeight(texture->height);
526
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800527 uint32_t flags = mFlags;
528 glBindTexture(GL_TEXTURE_2D, textureName);
529
530 GLuint tw = t.width;
531 GLuint th = t.height;
532
533 /*
534 * In OpenGL ES we can't specify a stride with glTexImage2D (however,
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700535 * GL_UNPACK_ALIGNMENT is a limited form of stride).
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800536 * So if the stride here isn't representable with GL_UNPACK_ALIGNMENT, we
537 * need to do something reasonable (here creating a bigger texture).
538 *
539 * extra pixels = (((stride - width) * pixelsize) / GL_UNPACK_ALIGNMENT);
540 *
541 * This situation doesn't happen often, but some h/w have a limitation
542 * for their framebuffer (eg: must be multiple of 8 pixels), and
543 * we need to take that into account when using these buffers as
544 * textures.
545 *
546 * This should never be a problem with POT textures
547 */
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700548
549 int unpack = __builtin_ctz(t.stride * bytesPerPixel(t.format));
550 unpack = 1 << ((unpack > 3) ? 3 : unpack);
551 glPixelStorei(GL_UNPACK_ALIGNMENT, unpack);
552
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800553 /*
554 * round to POT if needed
555 */
556
557 GLuint texture_w = tw;
558 GLuint texture_h = th;
559 if (!(flags & DisplayHardware::NPOT_EXTENSION)) {
560 // find the smallest power-of-two that will accommodate our surface
561 texture_w = 1 << (31 - clz(t.width));
562 texture_h = 1 << (31 - clz(t.height));
563 if (texture_w < t.width) texture_w <<= 1;
564 if (texture_h < t.height) texture_h <<= 1;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800565 }
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700566
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800567regular:
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700568 Rect bounds(dirty.bounds());
569 GLvoid* data = 0;
570 if (texture_w!=textureWidth || texture_h!=textureHeight) {
571 // texture size changed, we need to create a new one
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800572
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700573 if (!textureWidth || !textureHeight) {
574 // this is the first time, load the whole texture
575 if (texture_w==tw && texture_h==th) {
576 // we can do it one pass
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800577 data = t.data;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800578 } else {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700579 // we have to create the texture first because it
580 // doesn't match the size of the buffer
581 bounds.set(Rect(tw, th));
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800582 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800583 }
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700584
585 if (t.format == GGL_PIXEL_FORMAT_RGB_565) {
586 glTexImage2D(GL_TEXTURE_2D, 0,
587 GL_RGB, texture_w, texture_h, 0,
588 GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data);
589 } else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) {
590 glTexImage2D(GL_TEXTURE_2D, 0,
591 GL_RGBA, texture_w, texture_h, 0,
592 GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data);
Mathias Agopian816d7d02009-09-14 18:10:30 -0700593 } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888 ||
594 t.format == GGL_PIXEL_FORMAT_RGBX_8888) {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700595 glTexImage2D(GL_TEXTURE_2D, 0,
596 GL_RGBA, texture_w, texture_h, 0,
597 GL_RGBA, GL_UNSIGNED_BYTE, data);
598 } else if ( t.format == GGL_PIXEL_FORMAT_YCbCr_422_SP ||
599 t.format == GGL_PIXEL_FORMAT_YCbCr_420_SP) {
600 // just show the Y plane of YUV buffers
601 glTexImage2D(GL_TEXTURE_2D, 0,
602 GL_LUMINANCE, texture_w, texture_h, 0,
603 GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
604 } else {
605 // oops, we don't handle this format!
606 LOGE("layer %p, texture=%d, using format %d, which is not "
607 "supported by the GL", this, textureName, t.format);
608 textureName = -1;
609 }
610 textureWidth = texture_w;
611 textureHeight = texture_h;
612 }
613 if (!data && textureName>=0) {
614 if (t.format == GGL_PIXEL_FORMAT_RGB_565) {
615 glTexSubImage2D(GL_TEXTURE_2D, 0,
616 0, bounds.top, t.width, bounds.height(),
617 GL_RGB, GL_UNSIGNED_SHORT_5_6_5,
618 t.data + bounds.top*t.stride*2);
619 } else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) {
620 glTexSubImage2D(GL_TEXTURE_2D, 0,
621 0, bounds.top, t.width, bounds.height(),
622 GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4,
623 t.data + bounds.top*t.stride*2);
Mathias Agopian816d7d02009-09-14 18:10:30 -0700624 } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888 ||
625 t.format == GGL_PIXEL_FORMAT_RGBX_8888) {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700626 glTexSubImage2D(GL_TEXTURE_2D, 0,
627 0, bounds.top, t.width, bounds.height(),
628 GL_RGBA, GL_UNSIGNED_BYTE,
629 t.data + bounds.top*t.stride*4);
630 } else if ( t.format == GGL_PIXEL_FORMAT_YCbCr_422_SP ||
631 t.format == GGL_PIXEL_FORMAT_YCbCr_420_SP) {
632 // just show the Y plane of YUV buffers
633 glTexSubImage2D(GL_TEXTURE_2D, 0,
634 0, bounds.top, t.width, bounds.height(),
635 GL_LUMINANCE, GL_UNSIGNED_BYTE,
636 t.data + bounds.top*t.stride);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800637 }
638 }
639}
640
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800641// ---------------------------------------------------------------------------
642
Mathias Agopian2e123242009-06-23 20:06:46 -0700643int32_t LayerBaseClient::sIdentity = 0;
644
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800645LayerBaseClient::LayerBaseClient(SurfaceFlinger* flinger, DisplayID display,
Mathias Agopianf9d93272009-06-19 17:00:27 -0700646 const sp<Client>& client, int32_t i)
Mathias Agopian48d819a2009-09-10 19:41:18 -0700647 : LayerBase(flinger, display), lcblk(NULL), client(client),
Mathias Agopiancbb288b2009-09-07 16:32:45 -0700648 mIndex(i), mIdentity(uint32_t(android_atomic_inc(&sIdentity)))
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800649{
Mathias Agopian48d819a2009-09-10 19:41:18 -0700650 lcblk = new SharedBufferServer(
651 client->ctrlblk, i, NUM_BUFFERS,
652 mIdentity);
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700653}
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800654
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700655void LayerBaseClient::onFirstRef()
656{
Mathias Agopianf9d93272009-06-19 17:00:27 -0700657 sp<Client> client(this->client.promote());
658 if (client != 0) {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700659 client->bindLayer(this, mIndex);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800660 }
661}
662
663LayerBaseClient::~LayerBaseClient()
664{
Mathias Agopianf9d93272009-06-19 17:00:27 -0700665 sp<Client> client(this->client.promote());
666 if (client != 0) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800667 client->free(mIndex);
668 }
Mathias Agopian48d819a2009-09-10 19:41:18 -0700669 delete lcblk;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800670}
671
Mathias Agopianf9d93272009-06-19 17:00:27 -0700672int32_t LayerBaseClient::serverIndex() const
673{
674 sp<Client> client(this->client.promote());
675 if (client != 0) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800676 return (client->cid<<16)|mIndex;
677 }
678 return 0xFFFF0000 | mIndex;
679}
680
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700681sp<LayerBaseClient::Surface> LayerBaseClient::getSurface()
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800682{
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700683 sp<Surface> s;
684 Mutex::Autolock _l(mLock);
685 s = mClientSurface.promote();
686 if (s == 0) {
687 s = createSurface();
688 mClientSurface = s;
689 }
690 return s;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800691}
692
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700693sp<LayerBaseClient::Surface> LayerBaseClient::createSurface() const
694{
Mathias Agopian9a112062009-04-17 19:36:26 -0700695 return new Surface(mFlinger, clientIndex(), mIdentity,
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700696 const_cast<LayerBaseClient *>(this));
697}
698
699// ---------------------------------------------------------------------------
700
Mathias Agopian9a112062009-04-17 19:36:26 -0700701LayerBaseClient::Surface::Surface(
702 const sp<SurfaceFlinger>& flinger,
703 SurfaceID id, int identity,
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700704 const sp<LayerBaseClient>& owner)
Mathias Agopian9a112062009-04-17 19:36:26 -0700705 : mFlinger(flinger), mToken(id), mIdentity(identity), mOwner(owner)
706{
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700707}
708
709
Mathias Agopian9a112062009-04-17 19:36:26 -0700710LayerBaseClient::Surface::~Surface()
711{
712 /*
713 * This is a good place to clean-up all client resources
714 */
715
716 // destroy client resources
717 sp<LayerBaseClient> layer = getOwner();
718 if (layer != 0) {
719 mFlinger->destroySurface(layer);
720 }
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700721}
722
723sp<LayerBaseClient> LayerBaseClient::Surface::getOwner() const {
724 sp<LayerBaseClient> owner(mOwner.promote());
725 return owner;
726}
727
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700728status_t LayerBaseClient::Surface::onTransact(
Mathias Agopian375f5632009-06-15 18:24:59 -0700729 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700730{
731 switch (code) {
732 case REGISTER_BUFFERS:
733 case UNREGISTER_BUFFERS:
734 case CREATE_OVERLAY:
735 {
Mathias Agopian375f5632009-06-15 18:24:59 -0700736 if (!mFlinger->mAccessSurfaceFlinger.checkCalling()) {
737 IPCThreadState* ipc = IPCThreadState::self();
738 const int pid = ipc->getCallingPid();
739 const int uid = ipc->getCallingUid();
740 LOGE("Permission Denial: "
741 "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
742 return PERMISSION_DENIED;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700743 }
744 }
745 }
746 return BnSurface::onTransact(code, data, reply, flags);
747}
748
Mathias Agopiancbb288b2009-09-07 16:32:45 -0700749sp<SurfaceBuffer> LayerBaseClient::Surface::requestBuffer(int index, int usage)
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700750{
751 return NULL;
752}
753
754status_t LayerBaseClient::Surface::registerBuffers(
755 const ISurface::BufferHeap& buffers)
756{
757 return INVALID_OPERATION;
758}
759
760void LayerBaseClient::Surface::postBuffer(ssize_t offset)
761{
762}
763
764void LayerBaseClient::Surface::unregisterBuffers()
765{
766}
767
768sp<OverlayRef> LayerBaseClient::Surface::createOverlay(
769 uint32_t w, uint32_t h, int32_t format)
770{
771 return NULL;
772};
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800773
774// ---------------------------------------------------------------------------
775
776}; // namespace android