From 875d8e1323536e16dcfc90c9674d7ad32116a69a Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Fri, 7 Jun 2013 15:35:48 -0700 Subject: [PATCH] Refactor SF. Move all GL operations in their own class. this is the first step to add support for GLES 2.x, this change breaks the dependency of SF on GLES 1.x by moving all operation into their own class. Bug: 8679321 Change-Id: I0d2741eca2cefe67dfd9cf837cac10c4d126928b --- services/surfaceflinger/Android.mk | 8 +- services/surfaceflinger/DisplayDevice.cpp | 44 +--- services/surfaceflinger/DisplayDevice.h | 6 +- services/surfaceflinger/Layer.cpp | 176 +++----------- services/surfaceflinger/Layer.h | 11 +- services/surfaceflinger/LayerDim.cpp | 28 +-- services/surfaceflinger/LayerDim.h | 3 - .../RenderEngine/GLES10RenderEngine.cpp | 61 +++++ .../RenderEngine/GLES10RenderEngine.h | 40 ++++ .../RenderEngine/GLES11RenderEngine.cpp | 217 ++++++++++++++++++ .../RenderEngine/GLES11RenderEngine.h | 67 ++++++ .../{ => RenderEngine}/GLExtensions.cpp | 59 +---- .../{ => RenderEngine}/GLExtensions.h | 24 +- .../RenderEngine/RenderEngine.cpp | 145 ++++++++++++ .../RenderEngine/RenderEngine.h | 78 +++++++ services/surfaceflinger/SurfaceFlinger.cpp | 194 ++++------------ services/surfaceflinger/SurfaceFlinger.h | 29 +-- 17 files changed, 714 insertions(+), 476 deletions(-) create mode 100644 services/surfaceflinger/RenderEngine/GLES10RenderEngine.cpp create mode 100644 services/surfaceflinger/RenderEngine/GLES10RenderEngine.h create mode 100644 services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp create mode 100644 services/surfaceflinger/RenderEngine/GLES11RenderEngine.h rename services/surfaceflinger/{ => RenderEngine}/GLExtensions.cpp (58%) rename services/surfaceflinger/{ => RenderEngine}/GLExtensions.h (73%) create mode 100644 services/surfaceflinger/RenderEngine/RenderEngine.cpp create mode 100644 services/surfaceflinger/RenderEngine/RenderEngine.h diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk index f2051dded..2ec575ecb 100644 --- a/services/surfaceflinger/Android.mk +++ b/services/surfaceflinger/Android.mk @@ -6,7 +6,6 @@ LOCAL_SRC_FILES:= \ DisplayDevice.cpp \ EventThread.cpp \ FrameTracker.cpp \ - GLExtensions.cpp \ Layer.cpp \ LayerDim.cpp \ MessageQueue.cpp \ @@ -19,7 +18,12 @@ LOCAL_SRC_FILES:= \ DisplayHardware/PowerHAL.cpp \ DisplayHardware/VirtualDisplaySurface.cpp \ EventLog/EventLogTags.logtags \ - EventLog/EventLog.cpp + EventLog/EventLog.cpp \ + RenderEngine/GLExtensions.cpp \ + RenderEngine/RenderEngine.cpp \ + RenderEngine/GLES10RenderEngine.cpp \ + RenderEngine/GLES11RenderEngine.cpp + LOCAL_CFLAGS:= -DLOG_TAG=\"SurfaceFlinger\" LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index b001bdb0f..2eae9c297 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -29,18 +29,14 @@ #include -#include -#include -#include - #include #include "DisplayHardware/DisplaySurface.h" #include "DisplayHardware/HWComposer.h" +#include "RenderEngine/RenderEngine.h" #include "clz.h" #include "DisplayDevice.h" -#include "GLExtensions.h" #include "SurfaceFlinger.h" #include "Layer.h" @@ -48,20 +44,6 @@ using namespace android; // ---------------------------------------------------------------------------- -static __attribute__((noinline)) -void checkGLErrors() -{ - do { - // there could be more than one error flag - GLenum error = glGetError(); - if (error == GL_NO_ERROR) - break; - ALOGE("GL error 0x%04x", int(error)); - } while(true); -} - -// ---------------------------------------------------------------------------- - /* * Initialize the display to the specified values. * @@ -189,7 +171,7 @@ status_t DisplayDevice::compositionComplete() const { void DisplayDevice::flip(const Region& dirty) const { - checkGLErrors(); + mFlinger->getRenderEngine().checkErrors(); EGLDisplay dpy = mDisplay; EGLSurface surface = mSurface; @@ -246,28 +228,22 @@ uint32_t DisplayDevice::getFlags() const return mFlags; } -EGLBoolean DisplayDevice::makeCurrent(EGLDisplay dpy, - const sp& hw, EGLContext ctx) { +EGLBoolean DisplayDevice::makeCurrent(EGLDisplay dpy, EGLContext ctx) const { EGLBoolean result = EGL_TRUE; EGLSurface sur = eglGetCurrentSurface(EGL_DRAW); - if (sur != hw->mSurface) { - result = eglMakeCurrent(dpy, hw->mSurface, hw->mSurface, ctx); + if (sur != mSurface) { + result = eglMakeCurrent(dpy, mSurface, mSurface, ctx); if (result == EGL_TRUE) { - setViewportAndProjection(hw); + setViewportAndProjection(); } } return result; } -void DisplayDevice::setViewportAndProjection(const sp& hw) { - GLsizei w = hw->mDisplayWidth; - GLsizei h = hw->mDisplayHeight; - glViewport(0, 0, w, h); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - // put the origin in the left-bottom corner - glOrthof(0, w, 0, h, 0, 1); // l=0, r=w ; b=0, t=h - glMatrixMode(GL_MODELVIEW); +void DisplayDevice::setViewportAndProjection() const { + size_t w = mDisplayWidth; + size_t h = mDisplayHeight; + mFlinger->getRenderEngine().setViewportAndProjection(w, h); } // ---------------------------------------------------------------------------- diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 047eecdc9..eefc10709 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -133,10 +133,8 @@ public: void setDisplayName(const String8& displayName); const String8& getDisplayName() const { return mDisplayName; } - static EGLBoolean makeCurrent(EGLDisplay dpy, - const sp& hw, EGLContext ctx); - - static void setViewportAndProjection(const sp& hw); + EGLBoolean makeCurrent(EGLDisplay dpy, EGLContext ctx) const; + void setViewportAndProjection() const; /* ------------------------------------------------------------------------ * blank / unblank management diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index b08b8d104..3605dd451 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -38,13 +38,14 @@ #include "clz.h" #include "Colorizer.h" #include "DisplayDevice.h" -#include "GLExtensions.h" #include "Layer.h" #include "SurfaceFlinger.h" #include "SurfaceTextureLayer.h" #include "DisplayHardware/HWComposer.h" +#include "RenderEngine/RenderEngine.h" + #define DEBUG_RESIZE 0 namespace android { @@ -63,7 +64,6 @@ Layer::Layer(SurfaceFlinger* flinger, const sp& client, mName("unnamed"), mDebug(false), mFormat(PIXEL_FORMAT_NONE), - mGLExtensions(GLExtensions::getInstance()), mOpaqueLayer(true), mTransactionFlags(0), mQueuedFrames(0), @@ -236,15 +236,6 @@ sp Layer::getBufferQueue() const { return mSurfaceFlingerConsumer->getBufferQueue(); } -//virtual sp getSurfaceTexture() const { -// sp res; -// sp that( mOwner.promote() ); -// if (that != NULL) { -// res = that->mSurfaceFlingerConsumer->getBufferQueue(); -// } -// return res; -//} - // --------------------------------------------------------------------------- // h/w composer set-up // --------------------------------------------------------------------------- @@ -499,6 +490,8 @@ void Layer::onDraw(const sp& hw, const Region& clip) const bool blackOutLayer = isProtected() || (isSecure() && !hw->isSecure()); + RenderEngine& engine(mFlinger->getRenderEngine()); + if (!blackOutLayer) { // TODO: we could be more subtle with isFixedSize() const bool useFiltering = getFiltering() || needsFiltering(hw) || isFixedSize(); @@ -509,49 +502,24 @@ void Layer::onDraw(const sp& hw, const Region& clip) const mSurfaceFlingerConsumer->getTransformMatrix(textureMatrix); // Set things up for texturing. - glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTextureName); - GLenum filter = GL_NEAREST; - if (useFiltering) { - filter = GL_LINEAR; - } - glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, filter); - glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, filter); - glMatrixMode(GL_TEXTURE); - glLoadMatrixf(textureMatrix); - glMatrixMode(GL_MODELVIEW); - glDisable(GL_TEXTURE_2D); - glEnable(GL_TEXTURE_EXTERNAL_OES); + engine.setupLayerTexturing(mTextureName, useFiltering, textureMatrix); } else { - glBindTexture(GL_TEXTURE_2D, mFlinger->getProtectedTexName()); - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glDisable(GL_TEXTURE_EXTERNAL_OES); - glEnable(GL_TEXTURE_2D); + engine.setupLayerBlackedOut(); } - drawWithOpenGL(hw, clip); - - glDisable(GL_TEXTURE_EXTERNAL_OES); - glDisable(GL_TEXTURE_2D); + engine.disableTexturing(); } void Layer::clearWithOpenGL(const sp& hw, const Region& clip, GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) const { - const uint32_t fbHeight = hw->getHeight(); - glColor4f(red,green,blue,alpha); - - glDisable(GL_TEXTURE_EXTERNAL_OES); - glDisable(GL_TEXTURE_2D); - glDisable(GL_BLEND); - LayerMesh mesh; computeGeometry(hw, &mesh); - glVertexPointer(2, GL_FLOAT, 0, mesh.getVertices()); - glDrawArrays(GL_TRIANGLE_FAN, 0, mesh.getVertexCount()); + mFlinger->getRenderEngine().clearWithColor( + mesh.getVertices(), mesh.getVertexCount(), + red, green, blue, alpha); } void Layer::clearWithOpenGL( @@ -559,102 +527,14 @@ void Layer::clearWithOpenGL( clearWithOpenGL(hw, clip, 0,0,0,0); } -static void setupOpenGL10(bool premultipliedAlpha, bool opaque, int alpha) { - // OpenGL ES 1.0 doesn't support texture combiners. - // This path doesn't properly handle opaque layers that have non-opaque - // alpha values. The alpha channel will be copied into the framebuffer or - // screenshot, so if the framebuffer or screenshot is blended on top of - // something else, whatever is below the window will incorrectly show - // through. - if (CC_UNLIKELY(alpha < 0xFF)) { - GLfloat floatAlpha = alpha * (1.0f / 255.0f); - if (premultipliedAlpha) { - glColor4f(floatAlpha, floatAlpha, floatAlpha, floatAlpha); - } else { - glColor4f(1.0f, 1.0f, 1.0f, floatAlpha); - } - glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - } else { - glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - } -} - -static void setupOpenGL11(bool premultipliedAlpha, bool opaque, int alpha) { - GLenum combineRGB; - GLenum combineAlpha; - GLenum src0Alpha; - GLfloat envColor[4]; - - if (CC_UNLIKELY(alpha < 0xFF)) { - // Cv = premultiplied ? Cs*alpha : Cs - // Av = !opaque ? alpha*As : 1.0 - combineRGB = premultipliedAlpha ? GL_MODULATE : GL_REPLACE; - combineAlpha = !opaque ? GL_MODULATE : GL_REPLACE; - src0Alpha = GL_CONSTANT; - envColor[0] = alpha * (1.0f / 255.0f); - } else { - // Cv = Cs - // Av = opaque ? 1.0 : As - combineRGB = GL_REPLACE; - combineAlpha = GL_REPLACE; - src0Alpha = opaque ? GL_CONSTANT : GL_TEXTURE; - envColor[0] = 1.0f; - } - - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, combineRGB); - glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); - if (combineRGB == GL_MODULATE) { - glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); - } - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, combineAlpha); - glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, src0Alpha); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); - if (combineAlpha == GL_MODULATE) { - glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA); - } - if (combineRGB == GL_MODULATE || src0Alpha == GL_CONSTANT) { - envColor[1] = envColor[0]; - envColor[2] = envColor[0]; - envColor[3] = envColor[0]; - glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, envColor); - } -} - void Layer::drawWithOpenGL( const sp& hw, const Region& clip) const { const uint32_t fbHeight = hw->getHeight(); const State& s(getDrawingState()); - if (mFlinger->getGlesVersion() == GLES_VERSION_1_0) { - setupOpenGL10(mPremultipliedAlpha, isOpaque(), s.alpha); - } else { - setupOpenGL11(mPremultipliedAlpha, isOpaque(), s.alpha); - } - - if (s.alpha < 0xFF || !isOpaque()) { - glEnable(GL_BLEND); - glBlendFunc(mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA, - GL_ONE_MINUS_SRC_ALPHA); - } else { - glDisable(GL_BLEND); - } - LayerMesh mesh; computeGeometry(hw, &mesh); - // TODO: we probably want to generate the texture coords with the mesh - // here we assume that we only have 4 vertices - - struct TexCoords { - GLfloat u; - GLfloat v; - }; - - /* * NOTE: the way we compute the texture coordinates here produces * different results than when we take the HWC path -- in the later case @@ -676,26 +556,25 @@ void Layer::drawWithOpenGL( GLfloat right = GLfloat(win.right) / GLfloat(s.active.w); GLfloat bottom = GLfloat(win.bottom) / GLfloat(s.active.h); - TexCoords texCoords[4]; - texCoords[0].u = left; - texCoords[0].v = top; - texCoords[1].u = left; - texCoords[1].v = bottom; - texCoords[2].u = right; - texCoords[2].v = bottom; - texCoords[3].u = right; - texCoords[3].v = top; + // TODO: we probably want to generate the texture coords with the mesh + // here we assume that we only have 4 vertices + float texCoords[4][2]; + texCoords[0][0] = left; + texCoords[0][1] = top; + texCoords[1][0] = left; + texCoords[1][1] = bottom; + texCoords[2][0] = right; + texCoords[2][1] = bottom; + texCoords[3][0] = right; + texCoords[3][1] = top; for (int i = 0; i < 4; i++) { - texCoords[i].v = 1.0f - texCoords[i].v; + texCoords[i][1] = 1.0f - texCoords[i][1]; } - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(2, GL_FLOAT, 0, texCoords); - glVertexPointer(2, GL_FLOAT, 0, mesh.getVertices()); - glDrawArrays(GL_TRIANGLE_FAN, 0, mesh.getVertexCount()); - - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisable(GL_BLEND); + RenderEngine& engine(mFlinger->getRenderEngine()); + engine.setupLayerBlending(mPremultipliedAlpha, isOpaque(), s.alpha); + engine.drawMesh2D(mesh.getVertices(), texCoords, mesh.getVertexCount()); + engine.disableBlending(); } void Layer::setFiltering(bool filtering) { @@ -1209,9 +1088,6 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions) recomputeVisibleRegions = true; } - glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - // FIXME: postedRegion should be dirty & bounds const Layer::State& s(getDrawingState()); Region dirtyRegion(Rect(s.active.w, s.active.h)); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index f79bf2d87..e7e958549 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -22,8 +22,6 @@ #include #include -#include -#include #include #include @@ -55,7 +53,6 @@ class Colorizer; class DisplayDevice; class GraphicBuffer; class SurfaceFlinger; -class GLExtensions; // --------------------------------------------------------------------------- @@ -113,14 +110,15 @@ public: class LayerMesh { friend class Layer; - GLfloat mVertices[4][2]; + typedef GLfloat float2[2]; + float2 mVertices[4]; size_t mNumVertices; public: LayerMesh() : mNumVertices(4) { } - GLfloat const* getVertices() const { - return &mVertices[0][0]; + float2 const* getVertices() const { + return mVertices; } size_t getVertexCount() const { return mNumVertices; @@ -355,7 +353,6 @@ private: String8 mName; mutable bool mDebug; PixelFormat mFormat; - const GLExtensions& mGLExtensions; bool mOpaqueLayer; // these are protected by an external lock diff --git a/services/surfaceflinger/LayerDim.cpp b/services/surfaceflinger/LayerDim.cpp index f4adeebc3..062ad46a6 100644 --- a/services/surfaceflinger/LayerDim.cpp +++ b/services/surfaceflinger/LayerDim.cpp @@ -18,9 +18,6 @@ #include #include -#include -#include - #include #include @@ -29,6 +26,7 @@ #include "LayerDim.h" #include "SurfaceFlinger.h" #include "DisplayDevice.h" +#include "RenderEngine/RenderEngine.h" namespace android { // --------------------------------------------------------------------------- @@ -45,28 +43,12 @@ void LayerDim::onDraw(const sp& hw, const Region& clip) con { const State& s(getDrawingState()); if (s.alpha>0) { - const GLfloat alpha = s.alpha/255.0f; - const uint32_t fbHeight = hw->getHeight(); - glDisable(GL_TEXTURE_EXTERNAL_OES); - glDisable(GL_TEXTURE_2D); - - if (s.alpha == 0xFF) { - glDisable(GL_BLEND); - } else { - glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - } - - glColor4f(0, 0, 0, alpha); - LayerMesh mesh; computeGeometry(hw, &mesh); - - glVertexPointer(2, GL_FLOAT, 0, mesh.getVertices()); - glDrawArrays(GL_TRIANGLE_FAN, 0, mesh.getVertexCount()); - - glDisable(GL_BLEND); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); + RenderEngine& engine(mFlinger->getRenderEngine()); + engine.setupDimLayerBlending(s.alpha); + engine.drawMesh2D(mesh.getVertices(), NULL, mesh.getVertexCount()); + engine.disableBlending(); } } diff --git a/services/surfaceflinger/LayerDim.h b/services/surfaceflinger/LayerDim.h index 2a9614954..6561d7f74 100644 --- a/services/surfaceflinger/LayerDim.h +++ b/services/surfaceflinger/LayerDim.h @@ -20,9 +20,6 @@ #include #include -#include -#include - #include "Layer.h" // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/RenderEngine/GLES10RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES10RenderEngine.cpp new file mode 100644 index 000000000..9a47568f5 --- /dev/null +++ b/services/surfaceflinger/RenderEngine/GLES10RenderEngine.cpp @@ -0,0 +1,61 @@ +/* + * Copyright 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +#include "GLES10RenderEngine.h" + +// --------------------------------------------------------------------------- +namespace android { +// --------------------------------------------------------------------------- + +GLES10RenderEngine::~GLES10RenderEngine() { +} + +void GLES10RenderEngine::setupLayerBlending( + bool premultipliedAlpha, bool opaque, int alpha) { + // OpenGL ES 1.0 doesn't support texture combiners. + // This path doesn't properly handle opaque layers that have non-opaque + // alpha values. The alpha channel will be copied into the framebuffer or + // screenshot, so if the framebuffer or screenshot is blended on top of + // something else, whatever is below the window will incorrectly show + // through. + if (CC_UNLIKELY(alpha < 0xFF)) { + GLfloat floatAlpha = alpha * (1.0f / 255.0f); + if (premultipliedAlpha) { + glColor4f(floatAlpha, floatAlpha, floatAlpha, floatAlpha); + } else { + glColor4f(1.0f, 1.0f, 1.0f, floatAlpha); + } + glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + } else { + glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + } + + if (alpha < 0xFF || !opaque) { + glEnable(GL_BLEND); + glBlendFunc(premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA, + GL_ONE_MINUS_SRC_ALPHA); + } else { + glDisable(GL_BLEND); + } +} + +// --------------------------------------------------------------------------- +}; // namespace android +// --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/RenderEngine/GLES10RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES10RenderEngine.h new file mode 100644 index 000000000..f9c7c0455 --- /dev/null +++ b/services/surfaceflinger/RenderEngine/GLES10RenderEngine.h @@ -0,0 +1,40 @@ +/* + * Copyright 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef SF_GLES10RENDERENGINE_H_ +#define SF_GLES10RENDERENGINE_H_ + +#include +#include + +#include "GLES11RenderEngine.h" + +// --------------------------------------------------------------------------- +namespace android { +// --------------------------------------------------------------------------- + +class GLES10RenderEngine : public GLES11RenderEngine { + virtual ~GLES10RenderEngine(); +protected: + virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, int alpha); +}; + +// --------------------------------------------------------------------------- +}; // namespace android +// --------------------------------------------------------------------------- + +#endif /* SF_GLES10RENDERENGINE_H_ */ diff --git a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp new file mode 100644 index 000000000..19499c9d6 --- /dev/null +++ b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp @@ -0,0 +1,217 @@ +/* + * Copyright 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include + +#include "GLES11RenderEngine.h" +#include "GLExtensions.h" + +// --------------------------------------------------------------------------- +namespace android { +// --------------------------------------------------------------------------- + +GLES11RenderEngine::GLES11RenderEngine() { + + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); + glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims); + + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + glPixelStorei(GL_PACK_ALIGNMENT, 4); + glEnableClientState(GL_VERTEX_ARRAY); + glShadeModel(GL_FLAT); + glDisable(GL_DITHER); + glDisable(GL_CULL_FACE); + + struct pack565 { + inline uint16_t operator() (int r, int g, int b) const { + return (r<<11)|(g<<5)|b; + } + } pack565; + + const uint16_t protTexData[] = { pack565(0x03, 0x03, 0x03) }; + glGenTextures(1, &mProtectedTexName); + glBindTexture(GL_TEXTURE_2D, mProtectedTexName); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, + GL_RGB, GL_UNSIGNED_SHORT_5_6_5, protTexData); +} + +GLES11RenderEngine::~GLES11RenderEngine() { +} + + +size_t GLES11RenderEngine::getMaxTextureSize() const { + return mMaxTextureSize; +} + +size_t GLES11RenderEngine::getMaxViewportDims() const { + return + mMaxViewportDims[0] < mMaxViewportDims[1] ? + mMaxViewportDims[0] : mMaxViewportDims[1]; +} + +void GLES11RenderEngine::setViewportAndProjection(size_t w, size_t h) { + glViewport(0, 0, w, h); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + // put the origin in the left-bottom corner + glOrthof(0, w, 0, h, 0, 1); // l=0, r=w ; b=0, t=h + glMatrixMode(GL_MODELVIEW); +} + +void GLES11RenderEngine::setupLayerBlending( + bool premultipliedAlpha, bool opaque, int alpha) { + GLenum combineRGB; + GLenum combineAlpha; + GLenum src0Alpha; + GLfloat envColor[4]; + + if (CC_UNLIKELY(alpha < 0xFF)) { + // Cv = premultiplied ? Cs*alpha : Cs + // Av = !opaque ? alpha*As : 1.0 + combineRGB = premultipliedAlpha ? GL_MODULATE : GL_REPLACE; + combineAlpha = !opaque ? GL_MODULATE : GL_REPLACE; + src0Alpha = GL_CONSTANT; + envColor[0] = alpha * (1.0f / 255.0f); + } else { + // Cv = Cs + // Av = opaque ? 1.0 : As + combineRGB = GL_REPLACE; + combineAlpha = GL_REPLACE; + src0Alpha = opaque ? GL_CONSTANT : GL_TEXTURE; + envColor[0] = 1.0f; + } + + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, combineRGB); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); + if (combineRGB == GL_MODULATE) { + glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); + } + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, combineAlpha); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, src0Alpha); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); + if (combineAlpha == GL_MODULATE) { + glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA); + } + if (combineRGB == GL_MODULATE || src0Alpha == GL_CONSTANT) { + envColor[1] = envColor[0]; + envColor[2] = envColor[0]; + envColor[3] = envColor[0]; + glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, envColor); + } + + if (alpha < 0xFF || !opaque) { + glEnable(GL_BLEND); + glBlendFunc(premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA, + GL_ONE_MINUS_SRC_ALPHA); + } else { + glDisable(GL_BLEND); + } +} + +void GLES11RenderEngine::setupDimLayerBlending(int alpha) { + glDisable(GL_TEXTURE_EXTERNAL_OES); + glDisable(GL_TEXTURE_2D); + if (alpha == 0xFF) { + glDisable(GL_BLEND); + } else { + glEnable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + } + glColor4f(0, 0, 0, alpha/255.0f); +} + +void GLES11RenderEngine::setupLayerTexturing(size_t textureName, + bool useFiltering, const float* textureMatrix) { + glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureName); + GLenum filter = GL_NEAREST; + if (useFiltering) { + filter = GL_LINEAR; + } + glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, filter); + glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, filter); + glMatrixMode(GL_TEXTURE); + glLoadMatrixf(textureMatrix); + glMatrixMode(GL_MODELVIEW); + glDisable(GL_TEXTURE_2D); + glEnable(GL_TEXTURE_EXTERNAL_OES); +} + +void GLES11RenderEngine::setupLayerBlackedOut() { + glBindTexture(GL_TEXTURE_2D, mProtectedTexName); + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glDisable(GL_TEXTURE_EXTERNAL_OES); + glEnable(GL_TEXTURE_2D); +} + +void GLES11RenderEngine::disableTexturing() { + glDisable(GL_TEXTURE_EXTERNAL_OES); + glDisable(GL_TEXTURE_2D); +} + +void GLES11RenderEngine::disableBlending() { + glDisable(GL_BLEND); +} + +void GLES11RenderEngine::clearWithColor(const float vertices[][2] , size_t count, + float red, float green, float blue, float alpha) { + glColor4f(red, green, blue, alpha); + glDisable(GL_TEXTURE_EXTERNAL_OES); + glDisable(GL_TEXTURE_2D); + glDisable(GL_BLEND); + glVertexPointer(2, GL_FLOAT, 0, vertices); + glDrawArrays(GL_TRIANGLE_FAN, 0, count); +} + +void GLES11RenderEngine::drawMesh2D( + const float vertices[][2], const float texCoords[][2], size_t count) { + if (texCoords) { + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2, GL_FLOAT, 0, texCoords); + } + glVertexPointer(2, GL_FLOAT, 0, vertices); + glDrawArrays(GL_TRIANGLE_FAN, 0, count); + if (texCoords) { + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } +} + +void GLES11RenderEngine::dump(String8& result) { + const GLExtensions& extensions(GLExtensions::getInstance()); + result.appendFormat("GLES: %s, %s, %s\n", + extensions.getVendor(), + extensions.getRenderer(), + extensions.getVersion()); + result.appendFormat("%s\n", extensions.getExtension()); +} + +// --------------------------------------------------------------------------- +}; // namespace android +// --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h new file mode 100644 index 000000000..15054bd2e --- /dev/null +++ b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h @@ -0,0 +1,67 @@ +/* + * Copyright 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef SF_GLES11RENDERENGINE_H_ +#define SF_GLES11RENDERENGINE_H_ + +#include +#include + +#include + +#include "RenderEngine.h" + +// --------------------------------------------------------------------------- +namespace android { +// --------------------------------------------------------------------------- + +class String8; + +class GLES11RenderEngine : public RenderEngine { + GLuint mProtectedTexName; + GLint mMaxViewportDims[2]; + GLint mMaxTextureSize; + +public: + GLES11RenderEngine(); + +protected: + virtual ~GLES11RenderEngine(); + + virtual void dump(String8& result); + virtual void setViewportAndProjection(size_t w, size_t h); + virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, int alpha); + virtual void setupDimLayerBlending(int alpha); + virtual void setupLayerTexturing(size_t textureName, bool useFiltering, const float* textureMatrix); + virtual void setupLayerBlackedOut(); + virtual void disableTexturing(); + virtual void disableBlending(); + + virtual void clearWithColor(const float vertices[][2], size_t count, + float red, float green, float blue, float alpha); + + virtual void drawMesh2D(const float vertices[][2], const float texCoords[][2], size_t count); + + virtual size_t getMaxTextureSize() const; + virtual size_t getMaxViewportDims() const; +}; + +// --------------------------------------------------------------------------- +}; // namespace android +// --------------------------------------------------------------------------- + +#endif /* SF_GLES11RENDERENGINE_H_ */ diff --git a/services/surfaceflinger/GLExtensions.cpp b/services/surfaceflinger/RenderEngine/GLExtensions.cpp similarity index 58% rename from services/surfaceflinger/GLExtensions.cpp rename to services/surfaceflinger/RenderEngine/GLExtensions.cpp index e5fb083a8..76bbcc1bf 100644 --- a/services/surfaceflinger/GLExtensions.cpp +++ b/services/surfaceflinger/RenderEngine/GLExtensions.cpp @@ -26,10 +26,7 @@ namespace android { ANDROID_SINGLETON_STATIC_INSTANCE( GLExtensions ) GLExtensions::GLExtensions() - : mHaveTextureExternal(false), - mHaveNpot(false), - mHaveDirectTexture(false), - mHaveFramebufferObject(false) + : mHaveFramebufferObject(false) { } @@ -37,18 +34,12 @@ void GLExtensions::initWithGLStrings( GLubyte const* vendor, GLubyte const* renderer, GLubyte const* version, - GLubyte const* extensions, - char const* egl_vendor, - char const* egl_version, - char const* egl_extensions) + GLubyte const* extensions) { mVendor = (char const*)vendor; mRenderer = (char const*)renderer; mVersion = (char const*)version; mExtensions = (char const*)extensions; - mEglVendor = egl_vendor; - mEglVersion = egl_version; - mEglExtensions = egl_extensions; char const* curr = (char const*)extensions; char const* head = curr; @@ -61,39 +52,6 @@ void GLExtensions::initWithGLStrings( curr = head+1; } while (head); - curr = egl_extensions; - head = curr; - do { - head = strchr(curr, ' '); - String8 s(curr, head ? head-curr : strlen(curr)); - if (s.length()) { - mExtensionList.add(s); - } - curr = head+1; - } while (head); - -#ifdef EGL_ANDROID_image_native_buffer - if (hasExtension("GL_OES_EGL_image") && - (hasExtension("EGL_KHR_image_base") || hasExtension("EGL_KHR_image")) && - hasExtension("EGL_ANDROID_image_native_buffer")) - { - mHaveDirectTexture = true; - } -#else -#error "EGL_ANDROID_image_native_buffer not supported" -#endif - - if (hasExtension("GL_ARB_texture_non_power_of_two")) { - mHaveNpot = true; - } - - if (hasExtension("GL_OES_EGL_image_external")) { - mHaveTextureExternal = true; - } else if (strstr(mRenderer.string(), "Adreno")) { - // hack for Adreno 200 - mHaveTextureExternal = true; - } - if (hasExtension("GL_OES_framebuffer_object")) { mHaveFramebufferObject = true; } @@ -121,18 +79,5 @@ char const* GLExtensions::getExtension() const { return mExtensions.string(); } -char const* GLExtensions::getEglVendor() const { - return mEglVendor.string(); -} - -char const* GLExtensions::getEglVersion() const { - return mEglVersion.string(); -} - -char const* GLExtensions::getEglExtension() const { - return mEglExtensions.string(); -} - - // --------------------------------------------------------------------------- }; // namespace android diff --git a/services/surfaceflinger/GLExtensions.h b/services/surfaceflinger/RenderEngine/GLExtensions.h similarity index 73% rename from services/surfaceflinger/GLExtensions.h rename to services/surfaceflinger/RenderEngine/GLExtensions.h index c86c66a88..d81ed2a7b 100644 --- a/services/surfaceflinger/GLExtensions.h +++ b/services/surfaceflinger/RenderEngine/GLExtensions.h @@ -36,18 +36,12 @@ class GLExtensions : public Singleton { friend class Singleton; - bool mHaveTextureExternal : 1; - bool mHaveNpot : 1; - bool mHaveDirectTexture : 1; bool mHaveFramebufferObject : 1; String8 mVendor; String8 mRenderer; String8 mVersion; String8 mExtensions; - String8 mEglVendor; - String8 mEglVersion; - String8 mEglExtensions; SortedVector mExtensionList; GLExtensions(const GLExtensions&); @@ -57,15 +51,6 @@ protected: GLExtensions(); public: - inline bool haveTextureExternal() const { - return mHaveTextureExternal; - } - inline bool haveNpot() const { - return mHaveNpot; - } - inline bool haveDirectTexture() const { - return mHaveDirectTexture; - } inline bool haveFramebufferObject() const { return mHaveFramebufferObject; @@ -75,20 +60,13 @@ public: GLubyte const* vendor, GLubyte const* renderer, GLubyte const* version, - GLubyte const* extensions, - char const* egl_vendor, - char const* egl_version, - char const* egl_extensions); + GLubyte const* extensions); char const* getVendor() const; char const* getRenderer() const; char const* getVersion() const; char const* getExtension() const; - char const* getEglVendor() const; - char const* getEglVersion() const; - char const* getEglExtension() const; - bool hasExtension(char const* extension) const; }; diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp new file mode 100644 index 000000000..cb77e389e --- /dev/null +++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp @@ -0,0 +1,145 @@ +/* + * Copyright 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "RenderEngine.h" +#include "GLES10RenderEngine.h" +#include "GLES11RenderEngine.h" +#include "GLExtensions.h" + +// --------------------------------------------------------------------------- +namespace android { +// --------------------------------------------------------------------------- + +RenderEngine* RenderEngine::create(EGLDisplay display, EGLConfig config) { + // Also create our EGLContext + EGLint contextAttributes[] = { +// EGL_CONTEXT_CLIENT_VERSION, 2, +#ifdef EGL_IMG_context_priority +#ifdef HAS_CONTEXT_PRIORITY +#warning "using EGL_IMG_context_priority" + EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG, +#endif +#endif + EGL_NONE, EGL_NONE + }; + + EGLContext ctxt = eglCreateContext(display, config, NULL, contextAttributes); + if (ctxt == EGL_NO_CONTEXT) { + // maybe ES 2.x is not supported + ALOGW("can't create an ES 2.x context, trying 1.x"); + ctxt = eglCreateContext(display, config, NULL, contextAttributes + 2); + } + + // if can't create a GL context, we can only abort. + LOG_ALWAYS_FATAL_IF(ctxt==EGL_NO_CONTEXT, "EGLContext creation failed"); + + + // now figure out what version of GL did we actually get + // NOTE: a dummy surface is not needed if KHR_create_context is supported + + EGLint attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE, EGL_NONE }; + EGLSurface dummy = eglCreatePbufferSurface(display, config, attribs); + LOG_ALWAYS_FATAL_IF(dummy==EGL_NO_SURFACE, "can't create dummy pbuffer"); + EGLBoolean success = eglMakeCurrent(display, dummy, dummy, ctxt); + LOG_ALWAYS_FATAL_IF(!success, "can't make dummy pbuffer current"); + + GLExtensions& extensions(GLExtensions::getInstance()); + extensions.initWithGLStrings( + glGetString(GL_VENDOR), + glGetString(GL_RENDERER), + glGetString(GL_VERSION), + glGetString(GL_EXTENSIONS)); + + GlesVersion version = parseGlesVersion( extensions.getVersion() ); + + // initialize the renderer while GL is current + + RenderEngine* engine = NULL; + switch (version) { + case GLES_VERSION_1_0: + engine = new GLES10RenderEngine(); + break; + case GLES_VERSION_1_1: + engine = new GLES11RenderEngine(); + break; + case GLES_VERSION_2_0: + case GLES_VERSION_3_0: + //engine = new GLES20RenderEngine(); + break; + } + engine->setEGLContext(ctxt); + + ALOGI("OpenGL ES informations:"); + ALOGI("vendor : %s", extensions.getVendor()); + ALOGI("renderer : %s", extensions.getRenderer()); + ALOGI("version : %s", extensions.getVersion()); + ALOGI("extensions: %s", extensions.getExtension()); + ALOGI("GL_MAX_TEXTURE_SIZE = %d", engine->getMaxTextureSize()); + ALOGI("GL_MAX_VIEWPORT_DIMS = %d", engine->getMaxViewportDims()); + + eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroySurface(display, dummy); + + return engine; +} + +RenderEngine::RenderEngine() : mEGLContext(EGL_NO_CONTEXT) { +} + +RenderEngine::~RenderEngine() { +} + +void RenderEngine::setEGLContext(EGLContext ctxt) { + mEGLContext = ctxt; +} + +EGLContext RenderEngine::getEGLContext() const { + return mEGLContext; +} + +void RenderEngine::checkErrors() const { + do { + // there could be more than one error flag + GLenum error = glGetError(); + if (error == GL_NO_ERROR) + break; + ALOGE("GL error 0x%04x", int(error)); + } while (true); +} + +RenderEngine::GlesVersion RenderEngine::parseGlesVersion(const char* str) { + int major, minor; + if (sscanf(str, "OpenGL ES-CM %d.%d", &major, &minor) != 2) { + if (sscanf(str, "OpenGL ES %d.%d", &major, &minor) != 2) { + ALOGW("Unable to parse GL_VERSION string: \"%s\"", str); + return GLES_VERSION_1_0; + } + } + + if (major == 1 && minor == 0) return GLES_VERSION_1_0; + if (major == 1 && minor >= 1) return GLES_VERSION_1_1; + if (major == 2 && minor >= 0) return GLES_VERSION_2_0; + if (major == 3 && minor >= 0) return GLES_VERSION_3_0; + + ALOGW("Unrecognized OpenGL ES version: %d.%d", major, minor); + return GLES_VERSION_1_0; +} + +// --------------------------------------------------------------------------- +}; // namespace android +// --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h new file mode 100644 index 000000000..e43bfa490 --- /dev/null +++ b/services/surfaceflinger/RenderEngine/RenderEngine.h @@ -0,0 +1,78 @@ +/* + * Copyright 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef SF_RENDERENGINE_H_ +#define SF_RENDERENGINE_H_ + +#include +#include + +#include + +// --------------------------------------------------------------------------- +namespace android { +// --------------------------------------------------------------------------- + +class String8; + +class RenderEngine { + enum GlesVersion { + GLES_VERSION_1_0 = 0x10000, + GLES_VERSION_1_1 = 0x10001, + GLES_VERSION_2_0 = 0x20000, + GLES_VERSION_3_0 = 0x30000, + }; + static GlesVersion parseGlesVersion(const char* str); + + EGLContext mEGLContext; + void setEGLContext(EGLContext ctxt); + +protected: + RenderEngine(); + virtual ~RenderEngine() = 0; + +public: + static RenderEngine* create(EGLDisplay display, EGLConfig config); + + virtual void checkErrors() const; + + virtual void dump(String8& result) = 0; + virtual void setViewportAndProjection(size_t w, size_t h) = 0; + virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, int alpha) = 0; + virtual void setupDimLayerBlending(int alpha) = 0; + virtual void setupLayerTexturing(size_t textureName, bool useFiltering, const float* textureMatrix) = 0; + virtual void setupLayerBlackedOut() = 0; + + virtual void disableTexturing() = 0; + virtual void disableBlending() = 0; + + virtual void clearWithColor(const float vertices[][2], size_t count, + float red, float green, float blue, float alpha) = 0; + + virtual void drawMesh2D(const float vertices[][2], const float texCoords[][2], size_t count) = 0; + + virtual size_t getMaxTextureSize() const = 0; + virtual size_t getMaxViewportDims() const = 0; + + EGLContext getEGLContext() const; +}; + +// --------------------------------------------------------------------------- +}; // namespace android +// --------------------------------------------------------------------------- + +#endif /* SF_RENDERENGINE_H_ */ diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index fc193e553..5d138d140 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -61,7 +62,6 @@ #include "DdmConnection.h" #include "DisplayDevice.h" #include "EventThread.h" -#include "GLExtensions.h" #include "Layer.h" #include "LayerDim.h" #include "SurfaceFlinger.h" @@ -70,6 +70,8 @@ #include "DisplayHardware/HWComposer.h" #include "DisplayHardware/VirtualDisplaySurface.h" +#include "RenderEngine/RenderEngine.h" + #define DISPLAY_COUNT 1 EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); @@ -91,6 +93,7 @@ SurfaceFlinger::SurfaceFlinger() mAnimTransactionPending(false), mLayersRemoved(false), mRepaintEverything(0), + mRenderEngine(NULL), mBootTime(systemTime()), mVisibleRegionsDirty(false), mHwWorkListDirty(false), @@ -349,7 +352,9 @@ EGLConfig SurfaceFlinger::selectEGLConfig(EGLDisplay display, EGLint nativeVisua status_t err; EGLAttributeVector attribs; - attribs[EGL_SURFACE_TYPE] = EGL_WINDOW_BIT; + // TODO: enable ES2 + //attribs[EGL_RENDERABLE_TYPE] = EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT; + attribs[EGL_SURFACE_TYPE] = EGL_WINDOW_BIT | EGL_PBUFFER_BIT; attribs[EGL_RECORDABLE_ANDROID] = EGL_TRUE; attribs[EGL_FRAMEBUFFER_TARGET_ANDROID] = EGL_TRUE; attribs[EGL_RED_SIZE] = 8; @@ -360,25 +365,12 @@ EGLConfig SurfaceFlinger::selectEGLConfig(EGLDisplay display, EGLint nativeVisua if (!err) goto success; - // maybe we failed because of EGL_FRAMEBUFFER_TARGET_ANDROID - ALOGW("no suitable EGLConfig found, trying without EGL_FRAMEBUFFER_TARGET_ANDROID"); + // this didn't work, probably because we're on the emulator... + // try a simplified query + ALOGW("no suitable EGLConfig found, trying a simpler query"); + attribs.remove(EGL_RENDERABLE_TYPE); attribs.remove(EGL_FRAMEBUFFER_TARGET_ANDROID); - err = selectConfigForAttribute(display, attribs, - EGL_NATIVE_VISUAL_ID, nativeVisualId, &config); - if (!err) - goto success; - - // maybe we failed because of EGL_RECORDABLE_ANDROID - ALOGW("no suitable EGLConfig found, trying without EGL_RECORDABLE_ANDROID"); attribs.remove(EGL_RECORDABLE_ANDROID); - err = selectConfigForAttribute(display, attribs, - EGL_NATIVE_VISUAL_ID, nativeVisualId, &config); - if (!err) - goto success; - - // allow less than 24-bit color; the non-gpu-accelerated emulator only - // supports 16-bit color - ALOGW("no suitable EGLConfig found, trying with 16-bit color allowed"); attribs.remove(EGL_RED_SIZE); attribs.remove(EGL_GREEN_SIZE); attribs.remove(EGL_BLUE_SIZE); @@ -388,8 +380,7 @@ EGLConfig SurfaceFlinger::selectEGLConfig(EGLDisplay display, EGLint nativeVisua goto success; // this EGL is too lame for Android - ALOGE("no suitable EGLConfig found, giving up"); - + LOG_ALWAYS_FATAL("no suitable EGLConfig found, giving up"); return 0; success: @@ -398,97 +389,6 @@ success: return config; } -EGLContext SurfaceFlinger::createGLContext(EGLDisplay display, EGLConfig config) { - // Also create our EGLContext - EGLint contextAttributes[] = { -#ifdef EGL_IMG_context_priority -#ifdef HAS_CONTEXT_PRIORITY -#warning "using EGL_IMG_context_priority" - EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG, -#endif -#endif - EGL_NONE, EGL_NONE - }; - EGLContext ctxt = eglCreateContext(display, config, NULL, contextAttributes); - ALOGE_IF(ctxt==EGL_NO_CONTEXT, "EGLContext creation failed"); - return ctxt; -} - -static GlesVersion parseGlesVersion(const char* str) { - int major, minor; - if (sscanf(str, "OpenGL ES-CM %d.%d", &major, &minor) != 2) { - ALOGW("Unable to parse GL_VERSION string: \"%s\"", str); - return GLES_VERSION_1_0; - } - - if (major == 1 && minor == 0) return GLES_VERSION_1_0; - if (major == 1 && minor >= 1) return GLES_VERSION_1_1; - if (major == 2 && minor >= 0) return GLES_VERSION_2_0; - if (major == 3 && minor >= 0) return GLES_VERSION_3_0; - - ALOGW("Unrecognized OpenGL ES version: %d.%d", major, minor); - return GLES_VERSION_1_0; -} - -void SurfaceFlinger::initializeGL(EGLDisplay display) { - GLExtensions& extensions(GLExtensions::getInstance()); - extensions.initWithGLStrings( - glGetString(GL_VENDOR), - glGetString(GL_RENDERER), - glGetString(GL_VERSION), - glGetString(GL_EXTENSIONS), - eglQueryString(display, EGL_VENDOR), - eglQueryString(display, EGL_VERSION), - eglQueryString(display, EGL_EXTENSIONS)); - - mGlesVersion = parseGlesVersion(extensions.getVersion()); - - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); - glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims); - - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - glPixelStorei(GL_PACK_ALIGNMENT, 4); - glEnableClientState(GL_VERTEX_ARRAY); - glShadeModel(GL_FLAT); - glDisable(GL_DITHER); - glDisable(GL_CULL_FACE); - - struct pack565 { - inline uint16_t operator() (int r, int g, int b) const { - return (r<<11)|(g<<5)|b; - } - } pack565; - - const uint16_t protTexData[] = { pack565(0x03, 0x03, 0x03) }; - glGenTextures(1, &mProtectedTexName); - glBindTexture(GL_TEXTURE_2D, mProtectedTexName); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, - GL_RGB, GL_UNSIGNED_SHORT_5_6_5, protTexData); - - // print some debugging info - EGLint r,g,b,a; - eglGetConfigAttrib(display, mEGLConfig, EGL_RED_SIZE, &r); - eglGetConfigAttrib(display, mEGLConfig, EGL_GREEN_SIZE, &g); - eglGetConfigAttrib(display, mEGLConfig, EGL_BLUE_SIZE, &b); - eglGetConfigAttrib(display, mEGLConfig, EGL_ALPHA_SIZE, &a); - ALOGI("EGL informations:"); - ALOGI("vendor : %s", extensions.getEglVendor()); - ALOGI("version : %s", extensions.getEglVersion()); - ALOGI("extensions: %s", extensions.getEglExtension()); - ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported"); - ALOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, mEGLConfig); - ALOGI("OpenGL ES informations:"); - ALOGI("vendor : %s", extensions.getVendor()); - ALOGI("renderer : %s", extensions.getRenderer()); - ALOGI("version : %s", extensions.getVersion()); - ALOGI("extensions: %s", extensions.getExtension()); - ALOGI("GL_MAX_TEXTURE_SIZE = %d", mMaxTextureSize); - ALOGI("GL_MAX_VIEWPORT_DIMS = %d x %d", mMaxViewportDims[0], mMaxViewportDims[1]); -} status_t SurfaceFlinger::readyToRun() { @@ -506,10 +406,27 @@ status_t SurfaceFlinger::readyToRun() mHwc = new HWComposer(this, *static_cast(this)); - // initialize the config and context - EGLint format = mHwc->getVisualID(); - mEGLConfig = selectEGLConfig(mEGLDisplay, format); - mEGLContext = createGLContext(mEGLDisplay, mEGLConfig); + // initialize the config and context (can't fail) + mEGLConfig = selectEGLConfig(mEGLDisplay, mHwc->getVisualID()); + + // print some debugging info + EGLint r,g,b,a; + eglGetConfigAttrib(mEGLDisplay, mEGLConfig, EGL_RED_SIZE, &r); + eglGetConfigAttrib(mEGLDisplay, mEGLConfig, EGL_GREEN_SIZE, &g); + eglGetConfigAttrib(mEGLDisplay, mEGLConfig, EGL_BLUE_SIZE, &b); + eglGetConfigAttrib(mEGLDisplay, mEGLConfig, EGL_ALPHA_SIZE, &a); + ALOGI("EGL informations:"); + ALOGI("vendor : %s", eglQueryString(mEGLDisplay, EGL_VENDOR)); + ALOGI("version : %s", eglQueryString(mEGLDisplay, EGL_VERSION)); + ALOGI("extensions: %s", eglQueryString(mEGLDisplay, EGL_EXTENSIONS)); + ALOGI("Client API: %s", eglQueryString(mEGLDisplay, EGL_CLIENT_APIS)?:"Not Supported"); + ALOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, mEGLConfig); + + // get a RenderEngine for the given display / config (can't fail) + mRenderEngine = RenderEngine::create(mEGLDisplay, mEGLConfig); + + // retrieve the EGL context that was selected/created + mEGLContext = mRenderEngine->getEGLContext(); // figure out which format we got eglGetConfigAttrib(mEGLDisplay, mEGLConfig, @@ -543,17 +460,6 @@ status_t SurfaceFlinger::readyToRun() } } - // we need a GL context current in a few places, when initializing - // OpenGL ES (see below), or creating a layer, - // or when a texture is (asynchronously) destroyed, and for that - // we need a valid surface, so it's convenient to use the main display - // for that. - sp hw(getDefaultDisplayDevice()); - - // initialize OpenGL ES - DisplayDevice::makeCurrent(mEGLDisplay, hw, mEGLContext); - initializeGL(mEGLDisplay); - // start the EventThread mEventThread = new EventThread(this); mEventQueue.setEventThread(mEventThread); @@ -561,7 +467,6 @@ status_t SurfaceFlinger::readyToRun() // initialize our drawing state mDrawingState = mCurrentState; - // We're now ready to accept clients... mReadyToRunBarrier.open(); @@ -585,13 +490,12 @@ void SurfaceFlinger::startBootAnim() { property_set("ctl.start", "bootanim"); } -uint32_t SurfaceFlinger::getMaxTextureSize() const { - return mMaxTextureSize; +size_t SurfaceFlinger::getMaxTextureSize() const { + return mRenderEngine->getMaxTextureSize(); } -uint32_t SurfaceFlinger::getMaxViewportDims() const { - return mMaxViewportDims[0] < mMaxViewportDims[1] ? - mMaxViewportDims[0] : mMaxViewportDims[1]; +size_t SurfaceFlinger::getMaxViewportDims() const { + return mRenderEngine->getMaxViewportDims(); } // ---------------------------------------------------------------------------- @@ -1023,8 +927,7 @@ void SurfaceFlinger::postFramebuffer() // EGL spec says: // "surface must be bound to the calling thread's current context, // for the current rendering API." - DisplayDevice::makeCurrent(mEGLDisplay, - getDefaultDisplayDevice(), mEGLContext); + getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext); } hwc.commit(); } @@ -1131,7 +1034,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) // be sure that nothing associated with this display // is current. const sp defaultDisplay(getDefaultDisplayDevice()); - DisplayDevice::makeCurrent(mEGLDisplay, defaultDisplay, mEGLContext); + defaultDisplay->makeCurrent(mEGLDisplay, mEGLContext); sp hw(getDisplayDevice(draw.keyAt(i))); if (hw != NULL) hw->disconnect(getHwComposer()); @@ -1562,7 +1465,7 @@ void SurfaceFlinger::doComposeSurfaces(const sp& hw, const const bool hasGlesComposition = hwc.hasGlesComposition(id) || (cur==end); if (hasGlesComposition) { - if (!DisplayDevice::makeCurrent(mEGLDisplay, hw, mEGLContext)) { + if (!hw->makeCurrent(mEGLDisplay, mEGLContext)) { ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s", hw->getDisplayName().string()); return; @@ -2383,7 +2286,6 @@ void SurfaceFlinger::dumpAllLocked(const Vector& args, size_t& index, HWComposer& hwc(getHwComposer()); sp hw(getDefaultDisplayDevice()); - const GLExtensions& extensions(GLExtensions::getInstance()); colorizer.bold(result); result.appendFormat("EGL implementation : %s\n", @@ -2392,13 +2294,7 @@ void SurfaceFlinger::dumpAllLocked(const Vector& args, size_t& index, result.appendFormat("%s\n", eglQueryStringImplementationANDROID(mEGLDisplay, EGL_EXTENSIONS)); - colorizer.bold(result); - result.appendFormat("GLES: %s, %s, %s\n", - extensions.getVendor(), - extensions.getRenderer(), - extensions.getVersion()); - colorizer.reset(result); - result.appendFormat("%s\n", extensions.getExtension()); + mRenderEngine->dump(result); hw->undefinedRegion.dump(result, "undefinedRegion"); result.appendFormat(" orientation=%d, canDraw=%d\n", @@ -2731,10 +2627,6 @@ status_t SurfaceFlinger::captureScreenImplLocked( { ATRACE_CALL(); - if (!GLExtensions::getInstance().haveFramebufferObject()) { - return INVALID_OPERATION; - } - // get screen geometry const uint32_t hw_w = hw->getWidth(); const uint32_t hw_h = hw->getHeight(); @@ -2793,7 +2685,7 @@ status_t SurfaceFlinger::captureScreenImplLocked( glGenFramebuffersOES(1, &name); glBindFramebufferOES(GL_FRAMEBUFFER_OES, name); glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, - GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tname, 0); + GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, tname, 0); } else { // since we're going to use glReadPixels() anyways, // use an intermediate renderbuffer instead @@ -2851,7 +2743,7 @@ status_t SurfaceFlinger::captureScreenImplLocked( native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL); } - DisplayDevice::setViewportAndProjection(hw); + hw->setViewportAndProjection(); return result; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 089c2659d..c0815f8d2 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -21,7 +21,7 @@ #include #include -#include +#include // needed for GLuint #include @@ -62,6 +62,7 @@ class IGraphicBufferAlloc; class Layer; class LayerDim; class Surface; +class RenderEngine; // --------------------------------------------------------------------------- @@ -72,13 +73,6 @@ enum { eTransactionMask = 0x07 }; -enum GlesVersion { - GLES_VERSION_1_0 = 0x10000, - GLES_VERSION_1_1 = 0x10001, - GLES_VERSION_2_0 = 0x20000, - GLES_VERSION_3_0 = 0x30000, -}; - class SurfaceFlinger : public BinderService, public BnSurfaceComposer, private IBinder::DeathRecipient, @@ -128,9 +122,8 @@ public: // TODO: this should be made accessible only to HWComposer const Vector< sp >& getLayerSortedByZForHwcDisplay(int id); - // return the version of the OpenGL ES composition context - GlesVersion getGlesVersion() const { - return mGlesVersion; + RenderEngine& getRenderEngine() const { + return *mRenderEngine; } private: @@ -319,10 +312,8 @@ private: static status_t selectConfigForAttribute(EGLDisplay dpy, EGLint const* attrs, EGLint attribute, EGLint value, EGLConfig* outConfig); static EGLConfig selectEGLConfig(EGLDisplay disp, EGLint visualId); - static EGLContext createGLContext(EGLDisplay disp, EGLConfig config); - void initializeGL(EGLDisplay display); - uint32_t getMaxTextureSize() const; - uint32_t getMaxViewportDims() const; + size_t getMaxTextureSize() const; + size_t getMaxViewportDims() const; /* ------------------------------------------------------------------------ * Display and layer stack management @@ -378,9 +369,6 @@ private: void postFramebuffer(); void drawWormhole(const sp& hw, const Region& region) const; - GLuint getProtectedTexName() const { - return mProtectedTexName; - } /* ------------------------------------------------------------------------ * Display management @@ -423,17 +411,14 @@ private: // constant members (no synchronization needed for access) HWComposer* mHwc; - GLuint mProtectedTexName; + RenderEngine* mRenderEngine; nsecs_t mBootTime; bool mGpuToCpuSupported; sp mEventThread; - GLint mMaxViewportDims[2]; - GLint mMaxTextureSize; EGLContext mEGLContext; EGLConfig mEGLConfig; EGLDisplay mEGLDisplay; EGLint mEGLNativeVisualId; - GlesVersion mGlesVersion; sp mBuiltinDisplays[DisplayDevice::NUM_DISPLAY_TYPES]; // Can only accessed from the main thread, these members