Loading libs/hwui/FontRenderer.cpp +1 −0 Original line number Diff line number Diff line Loading @@ -327,6 +327,7 @@ void FontRenderer::initTextTexture() { mTextTexture = new unsigned char[mCacheWidth * mCacheHeight]; mUploadTexture = false; glActiveTexture(GL_TEXTURE0); glGenTextures(1, &mTextureId); glBindTexture(GL_TEXTURE_2D, mTextureId); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); Loading libs/hwui/Matrix.cpp +5 −0 Original line number Diff line number Diff line Loading @@ -152,6 +152,11 @@ void Matrix4::loadRotate(float angle, float x, float y, float z) { float s = sinf(angle); const float length = sqrtf(x * x + y * y + z * z); float recipLen = 1.0f / length; x *= recipLen; y *= recipLen; z *= recipLen; const float nc = 1.0f - c; const float xy = x * y; const float yz = y * z; Loading libs/hwui/OpenGLRenderer.cpp +117 −77 Original line number Diff line number Diff line Loading @@ -62,6 +62,15 @@ static const TextureVertex gMeshVertices[] = { static const GLsizei gMeshStride = sizeof(TextureVertex); static const GLsizei gMeshCount = 4; /** * Structure mapping Skia xfermodes to OpenGL blending factors. */ struct Blender { SkXfermode::Mode mode; GLenum src; GLenum dst; }; // struct Blender // In this array, the index of each Blender equals the value of the first // entry. For instance, gBlends[1] == gBlends[SkXfermode::kSrc_Mode] static const Blender gBlends[] = { Loading @@ -80,9 +89,15 @@ static const Blender gBlends[] = { }; static const GLint gTileModes[] = { GL_CLAMP_TO_EDGE, // == SkShader::kClamp_TileMode GL_REPEAT, // == SkShader::kRepeat_Mode GL_MIRRORED_REPEAT // == SkShader::kMirror_TileMode GL_CLAMP_TO_EDGE, // SkShader::kClamp_TileMode GL_REPEAT, // SkShader::kRepeat_Mode GL_MIRRORED_REPEAT // SkShader::kMirror_TileMode }; static const GLenum gTextureUnits[] = { GL_TEXTURE0, // Bitmap or text GL_TEXTURE1, // Gradient GL_TEXTURE2 // Bitmap shader }; /////////////////////////////////////////////////////////////////////////////// Loading Loading @@ -119,11 +134,7 @@ OpenGLRenderer::OpenGLRenderer(): LOGD(" Using default gradient cache size of %.2fMB", DEFAULT_GRADIENT_CACHE_SIZE); } mDrawColorProgram = new DrawColorProgram; mDrawTextureProgram = new DrawTextureProgram; mDrawTextProgram = new DrawTextProgram; mDrawLinearGradientProgram = new DrawLinearGradientProgram; mCurrentProgram = mDrawTextureProgram; mCurrentProgram = NULL; mShader = kShaderNone; mShaderTileX = GL_CLAMP_TO_EDGE; Loading @@ -131,20 +142,13 @@ OpenGLRenderer::OpenGLRenderer(): mShaderMatrix = NULL; mShaderBitmap = NULL; mLastTexture = 0; memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices)); ProgramDescription d; mProgramCache.get(d); d.hasTexture = true; mProgramCache.get(d); d.hasAlpha8Texture = true; d.hasGradient = true; d.hasBitmap = true; d.shadersMode = SkXfermode::kDstOut_Mode; d.colorOp = ProgramDescription::kColorMatrix; mProgramCache.get(d); glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &mMaxTextureUnits); if (mMaxTextureUnits < REQUIRED_TEXTURE_UNITS_COUNT) { LOGW("At least %d texture units are required!", REQUIRED_TEXTURE_UNITS_COUNT); } mLastTexture[0] = mLastTexture[1] = mLastTexture[2] = 0; } OpenGLRenderer::~OpenGLRenderer() { Loading Loading @@ -468,6 +472,7 @@ void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, const float u2 = srcRight / width; const float v2 = srcBottom / height; // TODO: Do this in the shader resetDrawTextureTexCoords(u1, v1, u2, v2); drawTextureRect(dstLeft, dstTop, dstRight, dstBottom, texture, paint); Loading Loading @@ -532,6 +537,8 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, return; } glActiveTexture(GL_TEXTURE0); float length; switch (paint->getTextAlign()) { case SkPaint::kCenter_Align: Loading @@ -558,22 +565,29 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, mModelView.loadIdentity(); useProgram(mDrawTextProgram); mDrawTextProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform); ProgramDescription description; description.hasTexture = true; description.hasAlpha8Texture = true; useProgram(mProgramCache.get(description)); mCurrentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform); chooseBlending(true, mode); bindTexture(mFontRenderer.getTexture(), GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); bindTexture(mFontRenderer.getTexture(), GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, 0); int texCoordsSlot = mCurrentProgram->getAttrib("texCoords"); glEnableVertexAttribArray(texCoordsSlot); // Always premultiplied glUniform4f(mDrawTextProgram->color, r, g, b, a); glUniform4f(mCurrentProgram->color, r, g, b, a); // TODO: Implement scale properly const Rect& clip = mSnapshot->getLocalClip(); mFontRenderer.setFont(paint, SkTypeface::UniqueID(paint->getTypeface()), paint->getTextSize()); mFontRenderer.renderText(paint, &clip, text, 0, bytesCount, count, x, y); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glDisableVertexAttribArray(texCoordsSlot); } /////////////////////////////////////////////////////////////////////////////// Loading @@ -599,8 +613,7 @@ void OpenGLRenderer::setupBitmapShader(SkBitmap* bitmap, SkShader::TileMode tile } void OpenGLRenderer::setupLinearGradientShader(SkShader* shader, float* bounds, uint32_t* colors, float* positions, int count, SkShader::TileMode tileMode, SkMatrix* matrix, bool hasAlpha) { float* positions, int count, SkShader::TileMode tileMode, SkMatrix* matrix, bool hasAlpha) { // TODO: We should use a struct to describe each shader mShader = OpenGLRenderer::kShaderLinearGradient; mShaderKey = shader; Loading Loading @@ -650,30 +663,31 @@ void OpenGLRenderer::drawColorRect(float left, float top, float right, float bot mModelView.loadTranslate(left, top, 0.0f); mModelView.scale(right - left, bottom - top, 1.0f); if (!useProgram(mDrawColorProgram)) { ProgramDescription description; Program* program = mProgramCache.get(description); if (!useProgram(program)) { const GLvoid* vertices = &mMeshVertices[0].position[0]; const GLvoid* texCoords = &mMeshVertices[0].texture[0]; glVertexAttribPointer(mDrawColorProgram->position, 2, GL_FLOAT, GL_FALSE, glVertexAttribPointer(mCurrentProgram->position, 2, GL_FLOAT, GL_FALSE, gMeshStride, vertices); glVertexAttribPointer(mDrawColorProgram->texCoords, 2, GL_FLOAT, GL_FALSE, gMeshStride, texCoords); } if (!ignoreTransform) { mDrawColorProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform); mCurrentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform); } else { mat4 identity; mDrawColorProgram->set(mOrthoMatrix, mModelView, identity); mCurrentProgram->set(mOrthoMatrix, mModelView, identity); } glUniform4f(mDrawColorProgram->color, r, g, b, a); glUniform4f(mCurrentProgram->color, r, g, b, a); glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); } void OpenGLRenderer::drawLinearGradientShader(float left, float top, float right, float bottom, float alpha, SkXfermode::Mode mode) { glActiveTexture(GL_TEXTURE1); Texture* texture = mGradientCache.get(mShaderKey); if (!texture) { SkShader::TileMode tileMode = SkShader::kClamp_TileMode; Loading @@ -690,14 +704,18 @@ void OpenGLRenderer::drawLinearGradientShader(float left, float top, float right mShaderPositions, mShaderCount, tileMode); } ProgramDescription description; description.hasGradient = true; mModelView.loadTranslate(left, top, 0.0f); mModelView.scale(right - left, bottom - top, 1.0f); useProgram(mDrawLinearGradientProgram); mDrawLinearGradientProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform); useProgram(mProgramCache.get(description)); mCurrentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform); chooseBlending(mShaderBlend || alpha < 1.0f, mode); bindTexture(texture->id, mShaderTileX, mShaderTileY); bindTexture(texture->id, mShaderTileX, mShaderTileY, 1); glUniform1i(mCurrentProgram->getUniform("gradientSampler"), 1); Rect start(mShaderBounds[0], mShaderBounds[1], mShaderBounds[2], mShaderBounds[3]); if (mShaderMatrix) { Loading @@ -713,15 +731,15 @@ void OpenGLRenderer::drawLinearGradientShader(float left, float top, float right screenSpace.multiply(mModelView); // Always premultiplied glUniform4f(mDrawLinearGradientProgram->color, alpha, alpha, alpha, alpha); glUniform2f(mDrawLinearGradientProgram->start, start.left, start.top); glUniform2f(mDrawLinearGradientProgram->gradient, gradientX, gradientY); glUniform1f(mDrawLinearGradientProgram->gradientLength, glUniform4f(mCurrentProgram->color, alpha, alpha, alpha, alpha); glUniform2f(mCurrentProgram->getUniform("gradientStart"), start.left, start.top); glUniform2f(mCurrentProgram->getUniform("gradient"), gradientX, gradientY); glUniform1f(mCurrentProgram->getUniform("gradientLength"), 1.0f / (gradientX * gradientX + gradientY * gradientY)); glUniformMatrix4fv(mDrawLinearGradientProgram->screenSpace, 1, GL_FALSE, glUniformMatrix4fv(mCurrentProgram->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]); glVertexAttribPointer(mDrawLinearGradientProgram->position, 2, GL_FLOAT, GL_FALSE, glVertexAttribPointer(mCurrentProgram->position, 2, GL_FLOAT, GL_FALSE, gMeshStride, &mMeshVertices[0].position[0]); glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); Loading @@ -729,42 +747,55 @@ void OpenGLRenderer::drawLinearGradientShader(float left, float top, float right void OpenGLRenderer::drawBitmapShader(float left, float top, float right, float bottom, float alpha, SkXfermode::Mode mode) { glActiveTexture(GL_TEXTURE2); const Texture* texture = mTextureCache.get(mShaderBitmap); const float width = texture->width; const float height = texture->height; // This could be done in the vertex shader but we have only 4 vertices float u1 = 0.0f; float v1 = 0.0f; float u2 = right - left; float v2 = bottom - top; mModelView.loadTranslate(left, top, 0.0f); mModelView.scale(right - left, bottom - top, 1.0f); // TODO: If the texture is not pow, use a shader to support repeat/mirror mat4 textureTransform; if (mShaderMatrix) { SkMatrix inverse; mShaderMatrix->invert(&inverse); mat4 m(inverse); Rect r(u1, v1, u2, v2); m.mapRect(r); textureTransform.load(inverse); textureTransform.multiply(mModelView); } else { textureTransform.load(mModelView); } u1 = r.left; u2 = r.right; v1 = r.top; v2 = r.bottom; ProgramDescription description; description.hasBitmap = true; // The driver does not support non-power of two mirrored/repeated // textures, so do it ourselves if (!mExtensions.hasNPot()) { description.isBitmapNpot = true; description.bitmapWrapS = mShaderTileX; description.bitmapWrapT = mShaderTileY; } u1 /= width; u2 /= width; v1 /= height; v2 /= height; useProgram(mProgramCache.get(description)); mCurrentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform); resetDrawTextureTexCoords(u1, v1, u2, v2); chooseBlending(texture->blend || alpha < 1.0f, mode); drawTextureMesh(left, top, right, bottom, texture->id, alpha, mode, texture->blend, &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0], NULL); // Texture bindTexture(texture->id, mShaderTileX, mShaderTileY, 2); glUniform1i(mCurrentProgram->getUniform("bitmapSampler"), 2); glUniformMatrix4fv(mCurrentProgram->getUniform("textureTransform"), 1, GL_FALSE, &textureTransform.data[0]); glUniform2f(mCurrentProgram->getUniform("textureDimension"), 1.0f / width, 1.0f / height); resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f); // Always premultiplied glUniform4f(mCurrentProgram->color, alpha, alpha, alpha, alpha); // Mesh glVertexAttribPointer(mCurrentProgram->position, 2, GL_FLOAT, GL_FALSE, gMeshStride, &mMeshVertices[0].position[0]); glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); } void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom, Loading @@ -786,28 +817,37 @@ void OpenGLRenderer::drawTextureRect(float left, float top, float right, float b void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float bottom, GLuint texture, float alpha, SkXfermode::Mode mode, bool blend, GLvoid* vertices, GLvoid* texCoords, GLvoid* indices, GLsizei elementsCount) { ProgramDescription description; description.hasTexture = true; mModelView.loadTranslate(left, top, 0.0f); mModelView.scale(right - left, bottom - top, 1.0f); useProgram(mDrawTextureProgram); mDrawTextureProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform); useProgram(mProgramCache.get(description)); mCurrentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform); chooseBlending(blend || alpha < 1.0f, mode); bindTexture(texture, mShaderTileX, mShaderTileY); // Texture bindTexture(texture, mShaderTileX, mShaderTileY, 0); glUniform1i(mCurrentProgram->getUniform("sampler"), 0); // Always premultiplied glUniform4f(mDrawTextureProgram->color, alpha, alpha, alpha, alpha); glUniform4f(mCurrentProgram->color, alpha, alpha, alpha, alpha); glVertexAttribPointer(mDrawTextureProgram->position, 2, GL_FLOAT, GL_FALSE, // Mesh int texCoordsSlot = mCurrentProgram->getAttrib("texCoords"); glEnableVertexAttribArray(texCoordsSlot); glVertexAttribPointer(mCurrentProgram->position, 2, GL_FLOAT, GL_FALSE, gMeshStride, vertices); glVertexAttribPointer(mDrawTextureProgram->texCoords, 2, GL_FLOAT, GL_FALSE, gMeshStride, texCoords); glVertexAttribPointer(texCoordsSlot, 2, GL_FLOAT, GL_FALSE, gMeshStride, texCoords); if (!indices) { glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); } else { glDrawElements(GL_TRIANGLES, elementsCount, GL_UNSIGNED_SHORT, indices); } glDisableVertexAttribArray(texCoordsSlot); } void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode, bool isPremultiplied) { Loading Loading @@ -836,9 +876,9 @@ void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode, bool isPr mBlend = blend; } bool OpenGLRenderer::useProgram(const sp<Program>& program) { bool OpenGLRenderer::useProgram(Program* program) { if (!program->isInUse()) { mCurrentProgram->remove(); if (mCurrentProgram != NULL) mCurrentProgram->remove(); program->use(); mCurrentProgram = program; return false; Loading Loading @@ -875,12 +915,12 @@ void OpenGLRenderer::getAlphaAndMode(const SkPaint* paint, int* alpha, SkXfermod } } void OpenGLRenderer::bindTexture(GLuint texture, GLenum wrapS, GLenum wrapT) { if (texture != mLastTexture) { void OpenGLRenderer::bindTexture(GLuint texture, GLenum wrapS, GLenum wrapT, GLuint textureUnit) { glActiveTexture(gTextureUnits[textureUnit]); if (texture != mLastTexture[textureUnit]) { glBindTexture(GL_TEXTURE_2D, texture); mLastTexture = texture; mLastTexture[textureUnit] = texture; } // TODO: Don't set the texture parameters every time glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT); } Loading libs/hwui/OpenGLRenderer.h +7 −21 Original line number Diff line number Diff line Loading @@ -46,23 +46,12 @@ namespace android { namespace uirenderer { /////////////////////////////////////////////////////////////////////////////// // Support /////////////////////////////////////////////////////////////////////////////// /** * Structure mapping Skia xfermodes to OpenGL blending factors. */ struct Blender { SkXfermode::Mode mode; GLenum src; GLenum dst; }; // struct Blender /////////////////////////////////////////////////////////////////////////////// // Renderer /////////////////////////////////////////////////////////////////////////////// #define REQUIRED_TEXTURE_UNITS_COUNT 3 /** * OpenGL renderer used to draw accelerated 2D graphics. The API is a * simplified version of Skia's Canvas API. Loading Loading @@ -294,7 +283,7 @@ private: /** * Binds the specified texture with the specified wrap modes. */ inline void bindTexture(GLuint texture, GLenum wrapS, GLenum wrapT); inline void bindTexture(GLuint texture, GLenum wrapS, GLenum wrapT, GLuint textureUnit = 0); /** * Enable or disable blending as necessary. This function sets the appropriate Loading @@ -312,7 +301,7 @@ private: * * @return true If the specified program was already in use, false otherwise. */ inline bool useProgram(const sp<Program>& program); inline bool useProgram(Program* program); // Dimensions of the drawing surface int mWidth, mHeight; Loading @@ -331,17 +320,14 @@ private: sp<Snapshot> mSnapshot; // Shaders sp<Program> mCurrentProgram; sp<DrawColorProgram> mDrawColorProgram; sp<DrawTextureProgram> mDrawTextureProgram; sp<DrawTextProgram> mDrawTextProgram; sp<DrawLinearGradientProgram> mDrawLinearGradientProgram; Program* mCurrentProgram; // Used to draw textured quads TextureVertex mMeshVertices[4]; // Current texture state GLuint mLastTexture; GLuint mLastTexture[REQUIRED_TEXTURE_UNITS_COUNT]; GLint mMaxTextureUnits; // Last known blend state bool mBlend; Loading libs/hwui/Program.cpp +22 −103 Original line number Diff line number Diff line Loading @@ -27,16 +27,6 @@ namespace uirenderer { #define SHADER_SOURCE(name, source) const char* name = #source #include "shaders/drawColor.frag" #include "shaders/drawTexture.vert" #include "shaders/drawTexture.frag" #include "shaders/drawText.frag" #include "shaders/drawLinearGradient.vert" #include "shaders/drawLinearGradient.frag" /////////////////////////////////////////////////////////////////////////////// // Base program /////////////////////////////////////////////////////////////////////////////// Loading Loading @@ -65,6 +55,10 @@ Program::Program(const char* vertex, const char* fragment) { } mUse = false; position = addAttrib("position"); color = addUniform("color"); transform = addUniform("transform"); } Program::~Program() { Loading @@ -73,15 +67,6 @@ Program::~Program() { glDeleteProgram(id); } void Program::use() { glUseProgram(id); mUse = true; } void Program::remove() { mUse = false; } int Program::addAttrib(const char* name) { int slot = glGetAttribLocation(id, name); attributes.add(name, slot); Loading @@ -89,7 +74,11 @@ int Program::addAttrib(const char* name) { } int Program::getAttrib(const char* name) { return attributes.valueFor(name); ssize_t index = attributes.indexOfKey(name); if (index >= 0) { return attributes.valueAt(index); } return addAttrib(name); } int Program::addUniform(const char* name) { Loading @@ -99,7 +88,11 @@ int Program::addUniform(const char* name) { } int Program::getUniform(const char* name) { return uniforms.valueFor(name); ssize_t index = uniforms.indexOfKey(name); if (index >= 0) { return uniforms.valueAt(index); } return addUniform(name); } GLuint Program::buildShader(const char* source, GLenum type) { Loading @@ -121,28 +114,7 @@ GLuint Program::buildShader(const char* source, GLenum type) { return shader; } /////////////////////////////////////////////////////////////////////////////// // Draw color /////////////////////////////////////////////////////////////////////////////// DrawColorProgram::DrawColorProgram(): Program(gDrawTextureVertexShader, gDrawColorFragmentShader) { getAttribsAndUniforms(); } DrawColorProgram::DrawColorProgram(const char* vertex, const char* fragment): Program(vertex, fragment) { getAttribsAndUniforms(); } void DrawColorProgram::getAttribsAndUniforms() { position = addAttrib("position"); texCoords = addAttrib("texCoords"); color = addUniform("color"); transform = addUniform("transform"); } void DrawColorProgram::set(const mat4& projectionMatrix, const mat4& modelViewMatrix, void Program::set(const mat4& projectionMatrix, const mat4& modelViewMatrix, const mat4& transformMatrix) { mat4 t(projectionMatrix); t.multiply(transformMatrix); Loading @@ -151,70 +123,17 @@ void DrawColorProgram::set(const mat4& projectionMatrix, const mat4& modelViewMa glUniformMatrix4fv(transform, 1, GL_FALSE, &t.data[0]); } void DrawColorProgram::use() { Program::use(); glEnableVertexAttribArray(position); glEnableVertexAttribArray(texCoords); } void DrawColorProgram::remove() { Program::remove(); glDisableVertexAttribArray(position); glDisableVertexAttribArray(texCoords); } /////////////////////////////////////////////////////////////////////////////// // Draw texture /////////////////////////////////////////////////////////////////////////////// DrawTextureProgram::DrawTextureProgram(): DrawColorProgram(gDrawTextureVertexShader, gDrawTextureFragmentShader) { sampler = addUniform("sampler"); } DrawTextureProgram::DrawTextureProgram(const char* vertex, const char* fragment): DrawColorProgram(vertex, fragment) { sampler = addUniform("sampler"); } void DrawTextureProgram::use() { DrawColorProgram::use(); glUniform1i(sampler, 0); } void DrawTextureProgram::remove() { DrawColorProgram::remove(); } /////////////////////////////////////////////////////////////////////////////// // Draw text /////////////////////////////////////////////////////////////////////////////// DrawTextProgram::DrawTextProgram(): DrawTextureProgram(gDrawTextureVertexShader, gDrawTextFragmentShader) { } /////////////////////////////////////////////////////////////////////////////// // Draw linear gradient /////////////////////////////////////////////////////////////////////////////// void Program::use() { glUseProgram(id); mUse = true; DrawLinearGradientProgram::DrawLinearGradientProgram(): DrawColorProgram(gDrawLinearGradientVertexShader, gDrawLinearGradientFragmentShader) { gradient = addUniform("gradient"); gradientLength = addUniform("gradientLength"); sampler = addUniform("sampler"); start = addUniform("start"); screenSpace = addUniform("screenSpace"); glEnableVertexAttribArray(position); } void DrawLinearGradientProgram::use() { DrawColorProgram::use(); glActiveTexture(GL_TEXTURE0); glUniform1i(sampler, 0); } void Program::remove() { mUse = false; void DrawLinearGradientProgram::remove() { DrawColorProgram::remove(); glDisableVertexAttribArray(position); } }; // namespace uirenderer Loading Loading
libs/hwui/FontRenderer.cpp +1 −0 Original line number Diff line number Diff line Loading @@ -327,6 +327,7 @@ void FontRenderer::initTextTexture() { mTextTexture = new unsigned char[mCacheWidth * mCacheHeight]; mUploadTexture = false; glActiveTexture(GL_TEXTURE0); glGenTextures(1, &mTextureId); glBindTexture(GL_TEXTURE_2D, mTextureId); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); Loading
libs/hwui/Matrix.cpp +5 −0 Original line number Diff line number Diff line Loading @@ -152,6 +152,11 @@ void Matrix4::loadRotate(float angle, float x, float y, float z) { float s = sinf(angle); const float length = sqrtf(x * x + y * y + z * z); float recipLen = 1.0f / length; x *= recipLen; y *= recipLen; z *= recipLen; const float nc = 1.0f - c; const float xy = x * y; const float yz = y * z; Loading
libs/hwui/OpenGLRenderer.cpp +117 −77 Original line number Diff line number Diff line Loading @@ -62,6 +62,15 @@ static const TextureVertex gMeshVertices[] = { static const GLsizei gMeshStride = sizeof(TextureVertex); static const GLsizei gMeshCount = 4; /** * Structure mapping Skia xfermodes to OpenGL blending factors. */ struct Blender { SkXfermode::Mode mode; GLenum src; GLenum dst; }; // struct Blender // In this array, the index of each Blender equals the value of the first // entry. For instance, gBlends[1] == gBlends[SkXfermode::kSrc_Mode] static const Blender gBlends[] = { Loading @@ -80,9 +89,15 @@ static const Blender gBlends[] = { }; static const GLint gTileModes[] = { GL_CLAMP_TO_EDGE, // == SkShader::kClamp_TileMode GL_REPEAT, // == SkShader::kRepeat_Mode GL_MIRRORED_REPEAT // == SkShader::kMirror_TileMode GL_CLAMP_TO_EDGE, // SkShader::kClamp_TileMode GL_REPEAT, // SkShader::kRepeat_Mode GL_MIRRORED_REPEAT // SkShader::kMirror_TileMode }; static const GLenum gTextureUnits[] = { GL_TEXTURE0, // Bitmap or text GL_TEXTURE1, // Gradient GL_TEXTURE2 // Bitmap shader }; /////////////////////////////////////////////////////////////////////////////// Loading Loading @@ -119,11 +134,7 @@ OpenGLRenderer::OpenGLRenderer(): LOGD(" Using default gradient cache size of %.2fMB", DEFAULT_GRADIENT_CACHE_SIZE); } mDrawColorProgram = new DrawColorProgram; mDrawTextureProgram = new DrawTextureProgram; mDrawTextProgram = new DrawTextProgram; mDrawLinearGradientProgram = new DrawLinearGradientProgram; mCurrentProgram = mDrawTextureProgram; mCurrentProgram = NULL; mShader = kShaderNone; mShaderTileX = GL_CLAMP_TO_EDGE; Loading @@ -131,20 +142,13 @@ OpenGLRenderer::OpenGLRenderer(): mShaderMatrix = NULL; mShaderBitmap = NULL; mLastTexture = 0; memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices)); ProgramDescription d; mProgramCache.get(d); d.hasTexture = true; mProgramCache.get(d); d.hasAlpha8Texture = true; d.hasGradient = true; d.hasBitmap = true; d.shadersMode = SkXfermode::kDstOut_Mode; d.colorOp = ProgramDescription::kColorMatrix; mProgramCache.get(d); glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &mMaxTextureUnits); if (mMaxTextureUnits < REQUIRED_TEXTURE_UNITS_COUNT) { LOGW("At least %d texture units are required!", REQUIRED_TEXTURE_UNITS_COUNT); } mLastTexture[0] = mLastTexture[1] = mLastTexture[2] = 0; } OpenGLRenderer::~OpenGLRenderer() { Loading Loading @@ -468,6 +472,7 @@ void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, const float u2 = srcRight / width; const float v2 = srcBottom / height; // TODO: Do this in the shader resetDrawTextureTexCoords(u1, v1, u2, v2); drawTextureRect(dstLeft, dstTop, dstRight, dstBottom, texture, paint); Loading Loading @@ -532,6 +537,8 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, return; } glActiveTexture(GL_TEXTURE0); float length; switch (paint->getTextAlign()) { case SkPaint::kCenter_Align: Loading @@ -558,22 +565,29 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, mModelView.loadIdentity(); useProgram(mDrawTextProgram); mDrawTextProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform); ProgramDescription description; description.hasTexture = true; description.hasAlpha8Texture = true; useProgram(mProgramCache.get(description)); mCurrentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform); chooseBlending(true, mode); bindTexture(mFontRenderer.getTexture(), GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); bindTexture(mFontRenderer.getTexture(), GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, 0); int texCoordsSlot = mCurrentProgram->getAttrib("texCoords"); glEnableVertexAttribArray(texCoordsSlot); // Always premultiplied glUniform4f(mDrawTextProgram->color, r, g, b, a); glUniform4f(mCurrentProgram->color, r, g, b, a); // TODO: Implement scale properly const Rect& clip = mSnapshot->getLocalClip(); mFontRenderer.setFont(paint, SkTypeface::UniqueID(paint->getTypeface()), paint->getTextSize()); mFontRenderer.renderText(paint, &clip, text, 0, bytesCount, count, x, y); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glDisableVertexAttribArray(texCoordsSlot); } /////////////////////////////////////////////////////////////////////////////// Loading @@ -599,8 +613,7 @@ void OpenGLRenderer::setupBitmapShader(SkBitmap* bitmap, SkShader::TileMode tile } void OpenGLRenderer::setupLinearGradientShader(SkShader* shader, float* bounds, uint32_t* colors, float* positions, int count, SkShader::TileMode tileMode, SkMatrix* matrix, bool hasAlpha) { float* positions, int count, SkShader::TileMode tileMode, SkMatrix* matrix, bool hasAlpha) { // TODO: We should use a struct to describe each shader mShader = OpenGLRenderer::kShaderLinearGradient; mShaderKey = shader; Loading Loading @@ -650,30 +663,31 @@ void OpenGLRenderer::drawColorRect(float left, float top, float right, float bot mModelView.loadTranslate(left, top, 0.0f); mModelView.scale(right - left, bottom - top, 1.0f); if (!useProgram(mDrawColorProgram)) { ProgramDescription description; Program* program = mProgramCache.get(description); if (!useProgram(program)) { const GLvoid* vertices = &mMeshVertices[0].position[0]; const GLvoid* texCoords = &mMeshVertices[0].texture[0]; glVertexAttribPointer(mDrawColorProgram->position, 2, GL_FLOAT, GL_FALSE, glVertexAttribPointer(mCurrentProgram->position, 2, GL_FLOAT, GL_FALSE, gMeshStride, vertices); glVertexAttribPointer(mDrawColorProgram->texCoords, 2, GL_FLOAT, GL_FALSE, gMeshStride, texCoords); } if (!ignoreTransform) { mDrawColorProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform); mCurrentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform); } else { mat4 identity; mDrawColorProgram->set(mOrthoMatrix, mModelView, identity); mCurrentProgram->set(mOrthoMatrix, mModelView, identity); } glUniform4f(mDrawColorProgram->color, r, g, b, a); glUniform4f(mCurrentProgram->color, r, g, b, a); glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); } void OpenGLRenderer::drawLinearGradientShader(float left, float top, float right, float bottom, float alpha, SkXfermode::Mode mode) { glActiveTexture(GL_TEXTURE1); Texture* texture = mGradientCache.get(mShaderKey); if (!texture) { SkShader::TileMode tileMode = SkShader::kClamp_TileMode; Loading @@ -690,14 +704,18 @@ void OpenGLRenderer::drawLinearGradientShader(float left, float top, float right mShaderPositions, mShaderCount, tileMode); } ProgramDescription description; description.hasGradient = true; mModelView.loadTranslate(left, top, 0.0f); mModelView.scale(right - left, bottom - top, 1.0f); useProgram(mDrawLinearGradientProgram); mDrawLinearGradientProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform); useProgram(mProgramCache.get(description)); mCurrentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform); chooseBlending(mShaderBlend || alpha < 1.0f, mode); bindTexture(texture->id, mShaderTileX, mShaderTileY); bindTexture(texture->id, mShaderTileX, mShaderTileY, 1); glUniform1i(mCurrentProgram->getUniform("gradientSampler"), 1); Rect start(mShaderBounds[0], mShaderBounds[1], mShaderBounds[2], mShaderBounds[3]); if (mShaderMatrix) { Loading @@ -713,15 +731,15 @@ void OpenGLRenderer::drawLinearGradientShader(float left, float top, float right screenSpace.multiply(mModelView); // Always premultiplied glUniform4f(mDrawLinearGradientProgram->color, alpha, alpha, alpha, alpha); glUniform2f(mDrawLinearGradientProgram->start, start.left, start.top); glUniform2f(mDrawLinearGradientProgram->gradient, gradientX, gradientY); glUniform1f(mDrawLinearGradientProgram->gradientLength, glUniform4f(mCurrentProgram->color, alpha, alpha, alpha, alpha); glUniform2f(mCurrentProgram->getUniform("gradientStart"), start.left, start.top); glUniform2f(mCurrentProgram->getUniform("gradient"), gradientX, gradientY); glUniform1f(mCurrentProgram->getUniform("gradientLength"), 1.0f / (gradientX * gradientX + gradientY * gradientY)); glUniformMatrix4fv(mDrawLinearGradientProgram->screenSpace, 1, GL_FALSE, glUniformMatrix4fv(mCurrentProgram->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]); glVertexAttribPointer(mDrawLinearGradientProgram->position, 2, GL_FLOAT, GL_FALSE, glVertexAttribPointer(mCurrentProgram->position, 2, GL_FLOAT, GL_FALSE, gMeshStride, &mMeshVertices[0].position[0]); glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); Loading @@ -729,42 +747,55 @@ void OpenGLRenderer::drawLinearGradientShader(float left, float top, float right void OpenGLRenderer::drawBitmapShader(float left, float top, float right, float bottom, float alpha, SkXfermode::Mode mode) { glActiveTexture(GL_TEXTURE2); const Texture* texture = mTextureCache.get(mShaderBitmap); const float width = texture->width; const float height = texture->height; // This could be done in the vertex shader but we have only 4 vertices float u1 = 0.0f; float v1 = 0.0f; float u2 = right - left; float v2 = bottom - top; mModelView.loadTranslate(left, top, 0.0f); mModelView.scale(right - left, bottom - top, 1.0f); // TODO: If the texture is not pow, use a shader to support repeat/mirror mat4 textureTransform; if (mShaderMatrix) { SkMatrix inverse; mShaderMatrix->invert(&inverse); mat4 m(inverse); Rect r(u1, v1, u2, v2); m.mapRect(r); textureTransform.load(inverse); textureTransform.multiply(mModelView); } else { textureTransform.load(mModelView); } u1 = r.left; u2 = r.right; v1 = r.top; v2 = r.bottom; ProgramDescription description; description.hasBitmap = true; // The driver does not support non-power of two mirrored/repeated // textures, so do it ourselves if (!mExtensions.hasNPot()) { description.isBitmapNpot = true; description.bitmapWrapS = mShaderTileX; description.bitmapWrapT = mShaderTileY; } u1 /= width; u2 /= width; v1 /= height; v2 /= height; useProgram(mProgramCache.get(description)); mCurrentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform); resetDrawTextureTexCoords(u1, v1, u2, v2); chooseBlending(texture->blend || alpha < 1.0f, mode); drawTextureMesh(left, top, right, bottom, texture->id, alpha, mode, texture->blend, &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0], NULL); // Texture bindTexture(texture->id, mShaderTileX, mShaderTileY, 2); glUniform1i(mCurrentProgram->getUniform("bitmapSampler"), 2); glUniformMatrix4fv(mCurrentProgram->getUniform("textureTransform"), 1, GL_FALSE, &textureTransform.data[0]); glUniform2f(mCurrentProgram->getUniform("textureDimension"), 1.0f / width, 1.0f / height); resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f); // Always premultiplied glUniform4f(mCurrentProgram->color, alpha, alpha, alpha, alpha); // Mesh glVertexAttribPointer(mCurrentProgram->position, 2, GL_FLOAT, GL_FALSE, gMeshStride, &mMeshVertices[0].position[0]); glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); } void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom, Loading @@ -786,28 +817,37 @@ void OpenGLRenderer::drawTextureRect(float left, float top, float right, float b void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float bottom, GLuint texture, float alpha, SkXfermode::Mode mode, bool blend, GLvoid* vertices, GLvoid* texCoords, GLvoid* indices, GLsizei elementsCount) { ProgramDescription description; description.hasTexture = true; mModelView.loadTranslate(left, top, 0.0f); mModelView.scale(right - left, bottom - top, 1.0f); useProgram(mDrawTextureProgram); mDrawTextureProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform); useProgram(mProgramCache.get(description)); mCurrentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform); chooseBlending(blend || alpha < 1.0f, mode); bindTexture(texture, mShaderTileX, mShaderTileY); // Texture bindTexture(texture, mShaderTileX, mShaderTileY, 0); glUniform1i(mCurrentProgram->getUniform("sampler"), 0); // Always premultiplied glUniform4f(mDrawTextureProgram->color, alpha, alpha, alpha, alpha); glUniform4f(mCurrentProgram->color, alpha, alpha, alpha, alpha); glVertexAttribPointer(mDrawTextureProgram->position, 2, GL_FLOAT, GL_FALSE, // Mesh int texCoordsSlot = mCurrentProgram->getAttrib("texCoords"); glEnableVertexAttribArray(texCoordsSlot); glVertexAttribPointer(mCurrentProgram->position, 2, GL_FLOAT, GL_FALSE, gMeshStride, vertices); glVertexAttribPointer(mDrawTextureProgram->texCoords, 2, GL_FLOAT, GL_FALSE, gMeshStride, texCoords); glVertexAttribPointer(texCoordsSlot, 2, GL_FLOAT, GL_FALSE, gMeshStride, texCoords); if (!indices) { glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); } else { glDrawElements(GL_TRIANGLES, elementsCount, GL_UNSIGNED_SHORT, indices); } glDisableVertexAttribArray(texCoordsSlot); } void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode, bool isPremultiplied) { Loading Loading @@ -836,9 +876,9 @@ void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode, bool isPr mBlend = blend; } bool OpenGLRenderer::useProgram(const sp<Program>& program) { bool OpenGLRenderer::useProgram(Program* program) { if (!program->isInUse()) { mCurrentProgram->remove(); if (mCurrentProgram != NULL) mCurrentProgram->remove(); program->use(); mCurrentProgram = program; return false; Loading Loading @@ -875,12 +915,12 @@ void OpenGLRenderer::getAlphaAndMode(const SkPaint* paint, int* alpha, SkXfermod } } void OpenGLRenderer::bindTexture(GLuint texture, GLenum wrapS, GLenum wrapT) { if (texture != mLastTexture) { void OpenGLRenderer::bindTexture(GLuint texture, GLenum wrapS, GLenum wrapT, GLuint textureUnit) { glActiveTexture(gTextureUnits[textureUnit]); if (texture != mLastTexture[textureUnit]) { glBindTexture(GL_TEXTURE_2D, texture); mLastTexture = texture; mLastTexture[textureUnit] = texture; } // TODO: Don't set the texture parameters every time glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT); } Loading
libs/hwui/OpenGLRenderer.h +7 −21 Original line number Diff line number Diff line Loading @@ -46,23 +46,12 @@ namespace android { namespace uirenderer { /////////////////////////////////////////////////////////////////////////////// // Support /////////////////////////////////////////////////////////////////////////////// /** * Structure mapping Skia xfermodes to OpenGL blending factors. */ struct Blender { SkXfermode::Mode mode; GLenum src; GLenum dst; }; // struct Blender /////////////////////////////////////////////////////////////////////////////// // Renderer /////////////////////////////////////////////////////////////////////////////// #define REQUIRED_TEXTURE_UNITS_COUNT 3 /** * OpenGL renderer used to draw accelerated 2D graphics. The API is a * simplified version of Skia's Canvas API. Loading Loading @@ -294,7 +283,7 @@ private: /** * Binds the specified texture with the specified wrap modes. */ inline void bindTexture(GLuint texture, GLenum wrapS, GLenum wrapT); inline void bindTexture(GLuint texture, GLenum wrapS, GLenum wrapT, GLuint textureUnit = 0); /** * Enable or disable blending as necessary. This function sets the appropriate Loading @@ -312,7 +301,7 @@ private: * * @return true If the specified program was already in use, false otherwise. */ inline bool useProgram(const sp<Program>& program); inline bool useProgram(Program* program); // Dimensions of the drawing surface int mWidth, mHeight; Loading @@ -331,17 +320,14 @@ private: sp<Snapshot> mSnapshot; // Shaders sp<Program> mCurrentProgram; sp<DrawColorProgram> mDrawColorProgram; sp<DrawTextureProgram> mDrawTextureProgram; sp<DrawTextProgram> mDrawTextProgram; sp<DrawLinearGradientProgram> mDrawLinearGradientProgram; Program* mCurrentProgram; // Used to draw textured quads TextureVertex mMeshVertices[4]; // Current texture state GLuint mLastTexture; GLuint mLastTexture[REQUIRED_TEXTURE_UNITS_COUNT]; GLint mMaxTextureUnits; // Last known blend state bool mBlend; Loading
libs/hwui/Program.cpp +22 −103 Original line number Diff line number Diff line Loading @@ -27,16 +27,6 @@ namespace uirenderer { #define SHADER_SOURCE(name, source) const char* name = #source #include "shaders/drawColor.frag" #include "shaders/drawTexture.vert" #include "shaders/drawTexture.frag" #include "shaders/drawText.frag" #include "shaders/drawLinearGradient.vert" #include "shaders/drawLinearGradient.frag" /////////////////////////////////////////////////////////////////////////////// // Base program /////////////////////////////////////////////////////////////////////////////// Loading Loading @@ -65,6 +55,10 @@ Program::Program(const char* vertex, const char* fragment) { } mUse = false; position = addAttrib("position"); color = addUniform("color"); transform = addUniform("transform"); } Program::~Program() { Loading @@ -73,15 +67,6 @@ Program::~Program() { glDeleteProgram(id); } void Program::use() { glUseProgram(id); mUse = true; } void Program::remove() { mUse = false; } int Program::addAttrib(const char* name) { int slot = glGetAttribLocation(id, name); attributes.add(name, slot); Loading @@ -89,7 +74,11 @@ int Program::addAttrib(const char* name) { } int Program::getAttrib(const char* name) { return attributes.valueFor(name); ssize_t index = attributes.indexOfKey(name); if (index >= 0) { return attributes.valueAt(index); } return addAttrib(name); } int Program::addUniform(const char* name) { Loading @@ -99,7 +88,11 @@ int Program::addUniform(const char* name) { } int Program::getUniform(const char* name) { return uniforms.valueFor(name); ssize_t index = uniforms.indexOfKey(name); if (index >= 0) { return uniforms.valueAt(index); } return addUniform(name); } GLuint Program::buildShader(const char* source, GLenum type) { Loading @@ -121,28 +114,7 @@ GLuint Program::buildShader(const char* source, GLenum type) { return shader; } /////////////////////////////////////////////////////////////////////////////// // Draw color /////////////////////////////////////////////////////////////////////////////// DrawColorProgram::DrawColorProgram(): Program(gDrawTextureVertexShader, gDrawColorFragmentShader) { getAttribsAndUniforms(); } DrawColorProgram::DrawColorProgram(const char* vertex, const char* fragment): Program(vertex, fragment) { getAttribsAndUniforms(); } void DrawColorProgram::getAttribsAndUniforms() { position = addAttrib("position"); texCoords = addAttrib("texCoords"); color = addUniform("color"); transform = addUniform("transform"); } void DrawColorProgram::set(const mat4& projectionMatrix, const mat4& modelViewMatrix, void Program::set(const mat4& projectionMatrix, const mat4& modelViewMatrix, const mat4& transformMatrix) { mat4 t(projectionMatrix); t.multiply(transformMatrix); Loading @@ -151,70 +123,17 @@ void DrawColorProgram::set(const mat4& projectionMatrix, const mat4& modelViewMa glUniformMatrix4fv(transform, 1, GL_FALSE, &t.data[0]); } void DrawColorProgram::use() { Program::use(); glEnableVertexAttribArray(position); glEnableVertexAttribArray(texCoords); } void DrawColorProgram::remove() { Program::remove(); glDisableVertexAttribArray(position); glDisableVertexAttribArray(texCoords); } /////////////////////////////////////////////////////////////////////////////// // Draw texture /////////////////////////////////////////////////////////////////////////////// DrawTextureProgram::DrawTextureProgram(): DrawColorProgram(gDrawTextureVertexShader, gDrawTextureFragmentShader) { sampler = addUniform("sampler"); } DrawTextureProgram::DrawTextureProgram(const char* vertex, const char* fragment): DrawColorProgram(vertex, fragment) { sampler = addUniform("sampler"); } void DrawTextureProgram::use() { DrawColorProgram::use(); glUniform1i(sampler, 0); } void DrawTextureProgram::remove() { DrawColorProgram::remove(); } /////////////////////////////////////////////////////////////////////////////// // Draw text /////////////////////////////////////////////////////////////////////////////// DrawTextProgram::DrawTextProgram(): DrawTextureProgram(gDrawTextureVertexShader, gDrawTextFragmentShader) { } /////////////////////////////////////////////////////////////////////////////// // Draw linear gradient /////////////////////////////////////////////////////////////////////////////// void Program::use() { glUseProgram(id); mUse = true; DrawLinearGradientProgram::DrawLinearGradientProgram(): DrawColorProgram(gDrawLinearGradientVertexShader, gDrawLinearGradientFragmentShader) { gradient = addUniform("gradient"); gradientLength = addUniform("gradientLength"); sampler = addUniform("sampler"); start = addUniform("start"); screenSpace = addUniform("screenSpace"); glEnableVertexAttribArray(position); } void DrawLinearGradientProgram::use() { DrawColorProgram::use(); glActiveTexture(GL_TEXTURE0); glUniform1i(sampler, 0); } void Program::remove() { mUse = false; void DrawLinearGradientProgram::remove() { DrawColorProgram::remove(); glDisableVertexAttribArray(position); } }; // namespace uirenderer Loading