blob: 9277a64daa4c4430b86c70f5e3dc7c3d199519ff [file] [log] [blame]
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001/*
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#define LOG_TAG "SurfaceFlinger"
18
19#include <stdlib.h>
20#include <stdint.h>
21#include <sys/types.h>
22
23#include <utils/Errors.h>
24#include <utils/Log.h>
25
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -080026#include <GLES/gl.h>
27#include <GLES/glext.h>
28
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -070029#include "clz.h"
30#include "LayerBase.h"
31#include "LayerBlur.h"
32#include "SurfaceFlinger.h"
33#include "DisplayHardware/DisplayHardware.h"
34
35
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -080036// We don't honor the premultiplied alpha flags, which means that
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -070037// premultiplied surface may be composed using a non-premultiplied
38// equation. We do this because it may be a lot faster on some hardware
39// The correct value is HONOR_PREMULTIPLIED_ALPHA = 1
40#define HONOR_PREMULTIPLIED_ALPHA 0
41
42namespace android {
43
44// ---------------------------------------------------------------------------
45
46const uint32_t LayerBase::typeInfo = 1;
47const char* const LayerBase::typeID = "LayerBase";
48
49const uint32_t LayerBaseClient::typeInfo = LayerBase::typeInfo | 2;
50const char* const LayerBaseClient::typeID = "LayerBaseClient";
51
52// ---------------------------------------------------------------------------
53
54Vector<GLuint> LayerBase::deletedTextures;
55
56int32_t LayerBase::sIdentity = 0;
57
58LayerBase::LayerBase(SurfaceFlinger* flinger, DisplayID display)
The Android Open Source Project27629322009-01-09 17:51:23 -080059 : dpy(display), contentDirty(false),
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -070060 mFlinger(flinger),
61 mTransformed(false),
62 mOrientation(0),
63 mCanUseCopyBit(false),
64 mTransactionFlags(0),
65 mPremultipliedAlpha(true),
The Android Open Source Project27629322009-01-09 17:51:23 -080066 mIdentity(uint32_t(android_atomic_inc(&sIdentity))),
67 mInvalidate(0)
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -070068{
69 const DisplayHardware& hw(flinger->graphicPlane(0).displayHardware());
70 mFlags = hw.getFlags();
71}
72
73LayerBase::~LayerBase()
74{
75}
76
77const GraphicPlane& LayerBase::graphicPlane(int dpy) const
78{
79 return mFlinger->graphicPlane(dpy);
80}
81
82GraphicPlane& LayerBase::graphicPlane(int dpy)
83{
84 return mFlinger->graphicPlane(dpy);
85}
86
87void LayerBase::initStates(uint32_t w, uint32_t h, uint32_t flags)
88{
89 uint32_t layerFlags = 0;
90 if (flags & ISurfaceComposer::eHidden)
91 layerFlags = ISurfaceComposer::eLayerHidden;
92
93 if (flags & ISurfaceComposer::eNonPremultiplied)
94 mPremultipliedAlpha = false;
95
96 mCurrentState.z = 0;
97 mCurrentState.w = w;
98 mCurrentState.h = h;
99 mCurrentState.alpha = 0xFF;
100 mCurrentState.flags = layerFlags;
101 mCurrentState.sequence = 0;
102 mCurrentState.transform.set(0, 0);
103
104 // drawing state & current state are identical
105 mDrawingState = mCurrentState;
106}
107
108void LayerBase::commitTransaction(bool skipSize) {
109 const uint32_t w = mDrawingState.w;
110 const uint32_t h = mDrawingState.h;
111 mDrawingState = mCurrentState;
112 if (skipSize) {
113 mDrawingState.w = w;
114 mDrawingState.h = h;
115 }
116}
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800117void LayerBase::forceVisibilityTransaction() {
118 // this can be called without SurfaceFlinger.mStateLock, but if we
119 // can atomically increment the sequence number, it doesn't matter.
120 android_atomic_inc(&mCurrentState.sequence);
121 requestTransaction();
122}
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700123bool LayerBase::requestTransaction() {
124 int32_t old = setTransactionFlags(eTransactionNeeded);
125 return ((old & eTransactionNeeded) == 0);
126}
127uint32_t LayerBase::getTransactionFlags(uint32_t flags) {
128 return android_atomic_and(~flags, &mTransactionFlags) & flags;
129}
130uint32_t LayerBase::setTransactionFlags(uint32_t flags) {
131 return android_atomic_or(flags, &mTransactionFlags);
132}
133
134void LayerBase::setSizeChanged(uint32_t w, uint32_t h) {
135}
136
137bool LayerBase::setPosition(int32_t x, int32_t y) {
138 if (mCurrentState.transform.tx() == x && mCurrentState.transform.ty() == y)
139 return false;
140 mCurrentState.sequence++;
141 mCurrentState.transform.set(x, y);
142 requestTransaction();
143 return true;
144}
145bool LayerBase::setLayer(uint32_t z) {
146 if (mCurrentState.z == z)
147 return false;
148 mCurrentState.sequence++;
149 mCurrentState.z = z;
150 requestTransaction();
151 return true;
152}
153bool LayerBase::setSize(uint32_t w, uint32_t h) {
154 if (mCurrentState.w == w && mCurrentState.h == h)
155 return false;
156 setSizeChanged(w, h);
157 mCurrentState.w = w;
158 mCurrentState.h = h;
159 requestTransaction();
160 return true;
161}
162bool LayerBase::setAlpha(uint8_t alpha) {
163 if (mCurrentState.alpha == alpha)
164 return false;
165 mCurrentState.sequence++;
166 mCurrentState.alpha = alpha;
167 requestTransaction();
168 return true;
169}
170bool LayerBase::setMatrix(const layer_state_t::matrix22_t& matrix) {
171 // TODO: check the matrix has changed
172 mCurrentState.sequence++;
173 mCurrentState.transform.set(
174 matrix.dsdx, matrix.dsdy, matrix.dtdx, matrix.dtdy);
175 requestTransaction();
176 return true;
177}
178bool LayerBase::setTransparentRegionHint(const Region& transparent) {
179 // TODO: check the region has changed
180 mCurrentState.sequence++;
181 mCurrentState.transparentRegion = transparent;
182 requestTransaction();
183 return true;
184}
185bool LayerBase::setFlags(uint8_t flags, uint8_t mask) {
186 const uint32_t newFlags = (mCurrentState.flags & ~mask) | (flags & mask);
187 if (mCurrentState.flags == newFlags)
188 return false;
189 mCurrentState.sequence++;
190 mCurrentState.flags = newFlags;
191 requestTransaction();
192 return true;
193}
194
195Rect LayerBase::visibleBounds() const
196{
197 return mTransformedBounds;
198}
199
200void LayerBase::setVisibleRegion(const Region& visibleRegion) {
201 // always called from main thread
202 visibleRegionScreen = visibleRegion;
203}
204
205void LayerBase::setCoveredRegion(const Region& coveredRegion) {
206 // always called from main thread
207 coveredRegionScreen = coveredRegion;
208}
209
210uint32_t LayerBase::doTransaction(uint32_t flags)
211{
212 const Layer::State& front(drawingState());
213 const Layer::State& temp(currentState());
214
215 if (temp.sequence != front.sequence) {
216 // invalidate and recompute the visible regions if needed
217 flags |= eVisibleRegion;
The Android Open Source Project27629322009-01-09 17:51:23 -0800218 this->contentDirty = true;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700219 }
220
221 // Commit the transaction
222 commitTransaction(flags & eRestartTransaction);
223 return flags;
224}
225
226Point LayerBase::getPhysicalSize() const
227{
228 const Layer::State& front(drawingState());
229 return Point(front.w, front.h);
230}
231
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800232Transform LayerBase::getDrawingStateTransform() const
233{
234 return drawingState().transform;
235}
236
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700237void LayerBase::validateVisibility(const Transform& planeTransform)
238{
239 const Layer::State& s(drawingState());
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800240 const Transform tr(planeTransform * getDrawingStateTransform());
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700241 const bool transformed = tr.transformed();
242
243 const Point size(getPhysicalSize());
244 uint32_t w = size.x;
245 uint32_t h = size.y;
246 tr.transform(mVertices[0], 0, 0);
247 tr.transform(mVertices[1], 0, h);
248 tr.transform(mVertices[2], w, h);
249 tr.transform(mVertices[3], w, 0);
250 if (UNLIKELY(transformed)) {
251 // NOTE: here we could also punt if we have too many rectangles
252 // in the transparent region
253 if (tr.preserveRects()) {
254 // transform the transparent region
255 transparentRegionScreen = tr.transform(s.transparentRegion);
256 } else {
257 // transformation too complex, can't do the transparent region
258 // optimization.
259 transparentRegionScreen.clear();
260 }
261 } else {
262 transparentRegionScreen = s.transparentRegion;
263 }
264
265 // cache a few things...
266 mOrientation = tr.getOrientation();
267 mTransformedBounds = tr.makeBounds(w, h);
268 mTransformed = transformed;
269 mLeft = tr.tx();
270 mTop = tr.ty();
271
272 // see if we can/should use 2D h/w with the new configuration
273 mCanUseCopyBit = false;
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800274 copybit_device_t* copybit = mFlinger->getBlitEngine();
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700275 if (copybit) {
276 const int step = copybit->get(copybit, COPYBIT_ROTATION_STEP_DEG);
277 const int scaleBits = copybit->get(copybit, COPYBIT_SCALING_FRAC_BITS);
278 mCanUseCopyBit = true;
279 if ((mOrientation < 0) && (step > 1)) {
280 // arbitrary orientations not supported
281 mCanUseCopyBit = false;
282 } else if ((mOrientation > 0) && (step > 90)) {
283 // 90 deg rotations not supported
284 mCanUseCopyBit = false;
285 } else if ((tr.getType() & SkMatrix::kScale_Mask) && (scaleBits < 12)) {
286 // arbitrary scaling not supported
287 mCanUseCopyBit = false;
288 }
289#if HONOR_PREMULTIPLIED_ALPHA
290 else if (needsBlending() && mPremultipliedAlpha) {
291 // pre-multiplied alpha not supported
292 mCanUseCopyBit = false;
293 }
294#endif
295 else {
296 // here, we determined we can use copybit
297 if (tr.getType() & SkMatrix::kScale_Mask) {
298 // and we have scaling
299 if (!transparentRegionScreen.isRect()) {
300 // we punt because blending is cheap (h/w) and the region is
301 // complex, which may causes artifacts when copying
302 // scaled content
303 transparentRegionScreen.clear();
304 }
305 }
306 }
307 }
308}
309
310void LayerBase::lockPageFlip(bool& recomputeVisibleRegions)
311{
312}
313
314void LayerBase::unlockPageFlip(
315 const Transform& planeTransform, Region& outDirtyRegion)
316{
The Android Open Source Project27629322009-01-09 17:51:23 -0800317 if ((android_atomic_and(~1, &mInvalidate)&1) == 1) {
318 outDirtyRegion.orSelf(visibleRegionScreen);
319 }
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700320}
321
322void LayerBase::finishPageFlip()
323{
324}
325
The Android Open Source Project27629322009-01-09 17:51:23 -0800326void LayerBase::invalidate()
327{
328 if ((android_atomic_or(1, &mInvalidate)&1) == 0) {
329 mFlinger->signalEvent();
330 }
331}
332
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700333void LayerBase::drawRegion(const Region& reg) const
334{
335 Region::iterator iterator(reg);
336 if (iterator) {
337 Rect r;
338 const DisplayHardware& hw(graphicPlane(0).displayHardware());
339 const int32_t fbWidth = hw.getWidth();
340 const int32_t fbHeight = hw.getHeight();
341 const GLshort vertices[][2] = { { 0, 0 }, { fbWidth, 0 },
342 { fbWidth, fbHeight }, { 0, fbHeight } };
343 glVertexPointer(2, GL_SHORT, 0, vertices);
344 while (iterator.iterate(&r)) {
345 const GLint sy = fbHeight - (r.top + r.height());
346 glScissor(r.left, sy, r.width(), r.height());
347 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
348 }
349 }
350}
351
352void LayerBase::draw(const Region& inClip) const
353{
354 // invalidate the region we'll update
355 Region clip(inClip); // copy-on-write, so no-op most of the time
356
357 // Remove the transparent area from the clipping region
358 const State& s = drawingState();
359 if (LIKELY(!s.transparentRegion.isEmpty())) {
360 clip.subtract(transparentRegionScreen);
361 if (clip.isEmpty()) {
362 // usually this won't happen because this should be taken care of
363 // by SurfaceFlinger::computeVisibleRegions()
364 return;
365 }
366 }
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800367
368 // reset GL state
369 glEnable(GL_SCISSOR_TEST);
370
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700371 onDraw(clip);
372
373 /*
374 glDisable(GL_TEXTURE_2D);
375 glDisable(GL_DITHER);
376 glEnable(GL_BLEND);
377 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
378 glColor4x(0, 0x8000, 0, 0x10000);
379 drawRegion(transparentRegionScreen);
380 glDisable(GL_BLEND);
381 */
382}
383
384GLuint LayerBase::createTexture() const
385{
386 GLuint textureName = -1;
387 glGenTextures(1, &textureName);
388 glBindTexture(GL_TEXTURE_2D, textureName);
389 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
390 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
391 if (mFlags & DisplayHardware::SLOW_CONFIG) {
392 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
393 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
394 } else {
395 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
396 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
397 }
398 return textureName;
399}
400
401void LayerBase::clearWithOpenGL(const Region& clip) const
402{
403 const DisplayHardware& hw(graphicPlane(0).displayHardware());
404 const uint32_t fbHeight = hw.getHeight();
405 glColor4x(0,0,0,0);
406 glDisable(GL_TEXTURE_2D);
407 glDisable(GL_BLEND);
408 glDisable(GL_DITHER);
409 Rect r;
410 Region::iterator iterator(clip);
411 if (iterator) {
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800412 glEnable(GL_SCISSOR_TEST);
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700413 glVertexPointer(2, GL_FIXED, 0, mVertices);
414 while (iterator.iterate(&r)) {
415 const GLint sy = fbHeight - (r.top + r.height());
416 glScissor(r.left, sy, r.width(), r.height());
417 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
418 }
419 }
420}
421
422void LayerBase::drawWithOpenGL(const Region& clip,
423 GLint textureName, const GGLSurface& t) const
424{
425 const DisplayHardware& hw(graphicPlane(0).displayHardware());
426 const uint32_t fbHeight = hw.getHeight();
427 const State& s(drawingState());
428
429 // bind our texture
430 validateTexture(textureName);
431 glEnable(GL_TEXTURE_2D);
432
433 // Dithering...
434 if (s.flags & ISurfaceComposer::eLayerDither) {
435 glEnable(GL_DITHER);
436 } else {
437 glDisable(GL_DITHER);
438 }
439
440 if (UNLIKELY(s.alpha < 0xFF)) {
441 // We have an alpha-modulation. We need to modulate all
442 // texture components by alpha because we're always using
443 // premultiplied alpha.
444
445 // If the texture doesn't have an alpha channel we can
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800446 // use REPLACE and switch to non premultiplied alpha
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700447 // blending (SRCA/ONE_MINUS_SRCA).
448
449 GLenum env, src;
450 if (needsBlending()) {
451 env = GL_MODULATE;
452 src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
453 } else {
454 env = GL_REPLACE;
455 src = GL_SRC_ALPHA;
456 }
457 const GGLfixed alpha = (s.alpha << 16)/255;
458 glColor4x(alpha, alpha, alpha, alpha);
459 glEnable(GL_BLEND);
460 glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);
461 glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, env);
462 } else {
463 glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800464 glColor4x(0x10000, 0x10000, 0x10000, 0x10000);
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700465 if (needsBlending()) {
466 GLenum src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
467 glEnable(GL_BLEND);
468 glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700469 } else {
470 glDisable(GL_BLEND);
471 }
472 }
473
474 if (UNLIKELY(transformed()
475 || !(mFlags & DisplayHardware::DRAW_TEXTURE_EXTENSION) ))
476 {
477 //StopWatch watch("GL transformed");
478 Region::iterator iterator(clip);
479 if (iterator) {
480 // always use high-quality filtering with fast configurations
481 bool fast = !(mFlags & DisplayHardware::SLOW_CONFIG);
482 if (!fast && s.flags & ISurfaceComposer::eLayerFilter) {
483 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
484 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
485 }
486 const GLfixed texCoords[4][2] = {
487 { 0, 0 },
488 { 0, 0x10000 },
489 { 0x10000, 0x10000 },
490 { 0x10000, 0 }
491 };
492
493 glMatrixMode(GL_TEXTURE);
494 glLoadIdentity();
495 if (!(mFlags & DisplayHardware::NPOT_EXTENSION)) {
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800496 // find the smallest power-of-two that will accommodate our surface
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700497 GLuint tw = 1 << (31 - clz(t.width));
498 GLuint th = 1 << (31 - clz(t.height));
499 if (tw < t.width) tw <<= 1;
500 if (th < t.height) th <<= 1;
501 // this divide should be relatively fast because it's
502 // a power-of-two (optimized path in libgcc)
503 GLfloat ws = GLfloat(t.width) /tw;
504 GLfloat hs = GLfloat(t.height)/th;
505 glScalef(ws, hs, 1.0f);
506 }
507
508 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
509 glVertexPointer(2, GL_FIXED, 0, mVertices);
510 glTexCoordPointer(2, GL_FIXED, 0, texCoords);
511
512 Rect r;
513 while (iterator.iterate(&r)) {
514 const GLint sy = fbHeight - (r.top + r.height());
515 glScissor(r.left, sy, r.width(), r.height());
516 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
517 }
518
519 if (!fast && s.flags & ISurfaceComposer::eLayerFilter) {
520 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
521 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
522 }
523 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
524 }
525 } else {
526 Region::iterator iterator(clip);
527 if (iterator) {
528 Rect r;
529 GLint crop[4] = { 0, t.height, t.width, -t.height };
530 glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
531 int x = tx();
532 int y = ty();
533 y = fbHeight - (y + t.height);
534 while (iterator.iterate(&r)) {
535 const GLint sy = fbHeight - (r.top + r.height());
536 glScissor(r.left, sy, r.width(), r.height());
537 glDrawTexiOES(x, y, 0, t.width, t.height);
538 }
539 }
540 }
541}
542
543void LayerBase::validateTexture(GLint textureName) const
544{
545 glBindTexture(GL_TEXTURE_2D, textureName);
546 // TODO: reload the texture if needed
547 // this is currently done in loadTexture() below
548}
549
550void LayerBase::loadTexture(const Region& dirty,
551 GLint textureName, const GGLSurface& t,
552 GLuint& textureWidth, GLuint& textureHeight) const
553{
554 // TODO: defer the actual texture reload until LayerBase::validateTexture
555 // is called.
556
557 uint32_t flags = mFlags;
558 glBindTexture(GL_TEXTURE_2D, textureName);
559
560 GLuint tw = t.width;
561 GLuint th = t.height;
562
563 /*
564 * In OpenGL ES we can't specify a stride with glTexImage2D (however,
565 * GL_UNPACK_ALIGNMENT is 4, which in essence allows a limited form of
566 * stride).
567 * So if the stride here isn't representable with GL_UNPACK_ALIGNMENT, we
568 * need to do something reasonable (here creating a bigger texture).
569 *
570 * extra pixels = (((stride - width) * pixelsize) / GL_UNPACK_ALIGNMENT);
571 *
572 * This situation doesn't happen often, but some h/w have a limitation
573 * for their framebuffer (eg: must be multiple of 8 pixels), and
574 * we need to take that into account when using these buffers as
575 * textures.
576 *
577 * This should never be a problem with POT textures
578 */
579
580 tw += (((t.stride - tw) * bytesPerPixel(t.format)) / 4);
581
582 /*
583 * round to POT if needed
584 */
585
586 GLuint texture_w = tw;
587 GLuint texture_h = th;
588 if (!(flags & DisplayHardware::NPOT_EXTENSION)) {
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800589 // find the smallest power-of-two that will accommodate our surface
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700590 texture_w = 1 << (31 - clz(t.width));
591 texture_h = 1 << (31 - clz(t.height));
592 if (texture_w < t.width) texture_w <<= 1;
593 if (texture_h < t.height) texture_h <<= 1;
594 if (texture_w != tw || texture_h != th) {
595 // we can't use DIRECT_TEXTURE since we changed the size
596 // of the texture
597 flags &= ~DisplayHardware::DIRECT_TEXTURE;
598 }
599 }
600
601 if (flags & DisplayHardware::DIRECT_TEXTURE) {
602 // here we're guaranteed that texture_{w|h} == t{w|h}
603 if (t.format == GGL_PIXEL_FORMAT_RGB_565) {
604 glTexImage2D(GL_DIRECT_TEXTURE_2D_QUALCOMM, 0,
605 GL_RGB, tw, th, 0,
606 GL_RGB, GL_UNSIGNED_SHORT_5_6_5, t.data);
607 } else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) {
608 glTexImage2D(GL_DIRECT_TEXTURE_2D_QUALCOMM, 0,
609 GL_RGBA, tw, th, 0,
610 GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, t.data);
611 } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) {
612 glTexImage2D(GL_DIRECT_TEXTURE_2D_QUALCOMM, 0,
613 GL_RGBA, tw, th, 0,
614 GL_RGBA, GL_UNSIGNED_BYTE, t.data);
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800615 } else if (t.format == GGL_PIXEL_FORMAT_BGRA_8888) {
616 // TODO: add GL_BGRA extension
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700617 } else {
618 // oops, we don't handle this format, try the regular path
619 goto regular;
620 }
621 textureWidth = tw;
622 textureHeight = th;
623 } else {
624regular:
625 Rect bounds(dirty.bounds());
626 GLvoid* data = 0;
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800627 if (texture_w!=textureWidth || texture_h!=textureHeight) {
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700628 // texture size changed, we need to create a new one
629
630 if (!textureWidth || !textureHeight) {
631 // this is the first time, load the whole texture
632 if (texture_w==tw && texture_h==th) {
633 // we can do it one pass
634 data = t.data;
635 } else {
636 // we have to create the texture first because it
637 // doesn't match the size of the buffer
638 bounds.set(Rect(tw, th));
639 }
640 }
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800641
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700642 if (t.format == GGL_PIXEL_FORMAT_RGB_565) {
643 glTexImage2D(GL_TEXTURE_2D, 0,
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800644 GL_RGB, texture_w, texture_h, 0,
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700645 GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data);
646 } else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) {
647 glTexImage2D(GL_TEXTURE_2D, 0,
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800648 GL_RGBA, texture_w, texture_h, 0,
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700649 GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data);
650 } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) {
651 glTexImage2D(GL_TEXTURE_2D, 0,
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800652 GL_RGBA, texture_w, texture_h, 0,
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700653 GL_RGBA, GL_UNSIGNED_BYTE, data);
654 } else if ( t.format == GGL_PIXEL_FORMAT_YCbCr_422_SP ||
655 t.format == GGL_PIXEL_FORMAT_YCbCr_420_SP) {
656 // just show the Y plane of YUV buffers
657 data = t.data;
658 glTexImage2D(GL_TEXTURE_2D, 0,
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800659 GL_LUMINANCE, texture_w, texture_h, 0,
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700660 GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800661 } else {
662 // oops, we don't handle this format!
663 LOGE("layer %p, texture=%d, using format %d, which is not "
664 "supported by the GL", this, textureName, t.format);
665 textureName = -1;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700666 }
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800667 textureWidth = texture_w;
668 textureHeight = texture_h;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700669 }
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800670 if (!data && textureName>=0) {
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700671 if (t.format == GGL_PIXEL_FORMAT_RGB_565) {
672 glTexSubImage2D(GL_TEXTURE_2D, 0,
673 0, bounds.top, t.width, bounds.height(),
674 GL_RGB, GL_UNSIGNED_SHORT_5_6_5,
675 t.data + bounds.top*t.width*2);
676 } else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) {
677 glTexSubImage2D(GL_TEXTURE_2D, 0,
678 0, bounds.top, t.width, bounds.height(),
679 GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4,
680 t.data + bounds.top*t.width*2);
681 } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) {
682 glTexSubImage2D(GL_TEXTURE_2D, 0,
683 0, bounds.top, t.width, bounds.height(),
684 GL_RGBA, GL_UNSIGNED_BYTE,
685 t.data + bounds.top*t.width*4);
686 }
687 }
688 }
689}
690
691bool LayerBase::canUseCopybit() const
692{
693 return mCanUseCopyBit;
694}
695
696// ---------------------------------------------------------------------------
697
698LayerBaseClient::LayerBaseClient(SurfaceFlinger* flinger, DisplayID display,
699 Client* c, int32_t i)
700 : LayerBase(flinger, display), client(c),
701 lcblk( c ? &(c->ctrlblk->layers[i]) : 0 ),
702 mIndex(i)
703{
704 if (client) {
705 client->bindLayer(this, i);
706
707 // Initialize this layer's control block
708 memset(this->lcblk, 0, sizeof(layer_cblk_t));
709 this->lcblk->identity = mIdentity;
710 Region::writeEmpty(&(this->lcblk->region[0]), sizeof(flat_region_t));
711 Region::writeEmpty(&(this->lcblk->region[1]), sizeof(flat_region_t));
712 }
713}
714
715LayerBaseClient::~LayerBaseClient()
716{
717 if (client) {
718 client->free(mIndex);
719 }
720}
721
722int32_t LayerBaseClient::serverIndex() const {
723 if (client) {
724 return (client->cid<<16)|mIndex;
725 }
726 return 0xFFFF0000 | mIndex;
727}
728
729sp<LayerBaseClient::Surface> LayerBaseClient::getSurface() const
730{
731 return new Surface(clientIndex(), mIdentity);
732}
733
734
735// ---------------------------------------------------------------------------
736
737}; // namespace android