diff options
-rw-r--r-- | libs/hwui/FontRenderer.cpp | 1 | ||||
-rw-r--r-- | libs/hwui/Matrix.cpp | 5 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 194 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.h | 28 | ||||
-rw-r--r-- | libs/hwui/Program.cpp | 125 | ||||
-rw-r--r-- | libs/hwui/Program.h | 165 | ||||
-rw-r--r-- | libs/hwui/ProgramCache.cpp | 67 | ||||
-rw-r--r-- | libs/hwui/ProgramCache.h | 40 | ||||
-rw-r--r-- | libs/hwui/shaders/drawColor.frag | 11 | ||||
-rw-r--r-- | libs/hwui/shaders/drawLinearGradient.frag | 14 | ||||
-rw-r--r-- | libs/hwui/shaders/drawLinearGradient.vert | 20 | ||||
-rw-r--r-- | libs/hwui/shaders/drawText.frag | 14 | ||||
-rw-r--r-- | libs/hwui/shaders/drawTexture.frag | 14 | ||||
-rw-r--r-- | libs/hwui/shaders/drawTexture.vert | 15 | ||||
-rw-r--r-- | tests/HwAccelerationTest/src/com/google/android/test/hwui/ShadersActivity.java | 1 |
15 files changed, 278 insertions, 436 deletions
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp index 5595ab0..6074ec8 100644 --- a/libs/hwui/FontRenderer.cpp +++ b/libs/hwui/FontRenderer.cpp @@ -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); diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp index b459202..0c31ba9 100644 --- a/libs/hwui/Matrix.cpp +++ b/libs/hwui/Matrix.cpp @@ -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; diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 0ed6276..3d9aa26 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -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[] = { @@ -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 }; /////////////////////////////////////////////////////////////////////////////// @@ -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; @@ -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() { @@ -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); @@ -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: @@ -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); } /////////////////////////////////////////////////////////////////////////////// @@ -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; @@ -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; @@ -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) { @@ -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); @@ -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, @@ -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) { @@ -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; @@ -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); } diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 975be05..5e5c021 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -47,22 +47,11 @@ 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. @@ -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 @@ -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; @@ -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; diff --git a/libs/hwui/Program.cpp b/libs/hwui/Program.cpp index 86fc154..dbae38e 100644 --- a/libs/hwui/Program.cpp +++ b/libs/hwui/Program.cpp @@ -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 /////////////////////////////////////////////////////////////////////////////// @@ -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() { @@ -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); @@ -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) { @@ -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) { @@ -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); @@ -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 diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h index 2cdd905..6531c74 100644 --- a/libs/hwui/Program.h +++ b/libs/hwui/Program.h @@ -21,7 +21,6 @@ #include <GLES2/gl2ext.h> #include <utils/KeyedVector.h> -#include <utils/RefBase.h> #include "Matrix.h" @@ -32,7 +31,7 @@ namespace uirenderer { * A program holds a vertex and a fragment shader. It offers several utility * methods to query attributes and uniforms. */ -class Program: public LightRefBase<Program> { +class Program { public: /** * Creates a new program with the specified vertex and fragment @@ -70,6 +69,28 @@ public: return mUse; } + /** + * Binds the program with the specified projection, modelView and + * transform matrices. + */ + void set(const mat4& projectionMatrix, const mat4& modelViewMatrix, + const mat4& transformMatrix); + + /** + * Name of the position attribute. + */ + int position; + + /** + * Name of the color uniform. + */ + int color; + + /** + * Name of the transform uniform. + */ + int transform; + protected: /** * Adds an attribute with the specified name. @@ -107,146 +128,6 @@ private: bool mUse; }; // class Program -/** - * Program used to draw vertices with a simple color. The shaders must - * specify the following attributes: - * vec4 position, position of the vertex - * vec4 color, RGBA color of the vertex - * - * And the following uniforms: - * mat4 projection, the projection matrix - * mat4 modelView, the modelView matrix - * mat4 transform, an extra transformation matrix - */ -class DrawColorProgram: public Program { -public: - DrawColorProgram(); - DrawColorProgram(const char* vertex, const char* fragment); - - /** - * Binds the program with the specified projection, modelView and - * transform matrices. - */ - void set(const mat4& projectionMatrix, const mat4& modelViewMatrix, - const mat4& transformMatrix); - - /** - * Binds this program to the GL context. - */ - virtual void use(); - - /** - * Marks this program as unused. This will not unbind - * the program from the GL context. - */ - virtual void remove(); - - /** - * Name of the position attribute. - */ - int position; - - /** - * Name of the texture coordinates attribute. - */ - int texCoords; - - /** - * Name of the color uniform. - */ - int color; - - /** - * Name of the transform uniform. - */ - int transform; - -protected: - void getAttribsAndUniforms(); -}; - -/** - * Program used to draw textured vertices. In addition to everything that the - * DrawColorProgram supports, the following two attributes must be specified: - * sampler2D sampler, the texture sampler - * vec2 texCoords, the texture coordinates of the vertex - */ -class DrawTextureProgram: public DrawColorProgram { -public: - DrawTextureProgram(); - DrawTextureProgram(const char* vertex, const char* fragment); - - /** - * Binds this program to the GL context. - */ - virtual void use(); - - /** - * Marks this program as unused. This will not unbind - * the program from the GL context. - */ - virtual void remove(); - - /** - * Name of the texture sampler uniform. - */ - int sampler; -}; - -class DrawTextProgram: public DrawTextureProgram { -public: - DrawTextProgram(); -}; - -/** - * Program used to draw linear gradients. In addition to everything that the - * DrawColorProgram supports, the following two attributes must be specified: - * vec2 gradient, the vector describing the linear gradient - * float gradientLength, the invert of the magnitude of the gradient vector - * sampler2D sampler, the texture sampler - */ -class DrawLinearGradientProgram: public DrawColorProgram { -public: - DrawLinearGradientProgram(); - - /** - * Binds this program to the GL context. - */ - virtual void use(); - - /** - * Marks this program as unused. This will not unbind - * the program from the GL context. - */ - virtual void remove(); - - /** - * Name of the matrix used to compute the screen space coordinates - * of the vertices. - */ - int screenSpace; - - /** - * Name of the linear gradient start point. - */ - int start; - - /** - * Name of the linear gradient vector. - */ - int gradient; - - /** - * Name of the inverse of linear gradient vector's magnitude. - */ - int gradientLength; - - /** - * Name of the texture sampler uniform. - */ - int sampler; -}; - }; // namespace uirenderer }; // namespace android diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp index 5a89eb6..c9e2d2e 100644 --- a/libs/hwui/ProgramCache.cpp +++ b/libs/hwui/ProgramCache.cpp @@ -40,6 +40,9 @@ const char* gVS_Header_Uniforms_HasGradient = "uniform vec2 gradient;\n" "uniform vec2 gradientStart;\n" "uniform mat4 screenSpace;\n"; +const char* gVS_Header_Uniforms_HasBitmap = + "uniform mat4 textureTransform;\n" + "uniform vec2 textureDimension;\n"; const char* gVS_Header_Varyings_HasTexture = "varying vec2 outTexCoords;\n"; const char* gVS_Header_Varyings_HasBitmap = @@ -53,6 +56,9 @@ const char* gVS_Main_OutTexCoords = const char* gVS_Main_OutGradientIndex = " vec4 location = screenSpace * position;\n" " index = dot(location.xy - gradientStart, gradient) * gradientLength;\n"; +const char* gVS_Main_OutBitmapTexCoords = + " vec4 bitmapCoords = textureTransform * position;\n" + " outBitmapTexCoords = bitmapCoords.xy * textureDimension;\n"; const char* gVS_Main_Position = " gl_Position = transform * position;\n"; const char* gVS_Footer = @@ -97,12 +103,18 @@ const char* gFS_Main_FetchGradient = " vec4 gradientColor = texture2D(gradientSampler, vec2(index, 0.5));\n"; const char* gFS_Main_FetchBitmap = " vec4 bitmapColor = texture2D(bitmapSampler, outBitmapTexCoords);\n"; +const char* gFS_Main_FetchBitmapNpot = + " vec4 bitmapColor = texture2D(bitmapSampler, wrap(outBitmapTexCoords));\n"; const char* gFS_Main_BlendShadersBG = " fragColor = blendShaders(bitmapColor, gradientColor)"; const char* gFS_Main_BlendShadersGB = " fragColor = blendShaders(gradientColor, bitmapColor)"; const char* gFS_Main_BlendShaders_Modulate = " * fragColor.a;\n"; +const char* gFS_Main_GradientShader_Modulate = + " fragColor = gradientColor * fragColor.a;\n"; +const char* gFS_Main_BitmapShader_Modulate = + " fragColor = bitmapColor * fragColor.a;\n"; const char* gFS_Main_FragColor = " gl_FragColor = fragColor;\n"; const char* gFS_Main_ApplyColorOp[4] = { @@ -204,7 +216,7 @@ Program* ProgramCache::generateProgram(const ProgramDescription& description, pr String8 ProgramCache::generateVertexShader(const ProgramDescription& description) { // Add attributes String8 shader(gVS_Header_Attributes); - if (description.hasTexture || description.hasBitmap) { + if (description.hasTexture) { shader.append(gVS_Header_Attributes_TexCoords); } // Uniforms @@ -212,6 +224,9 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description if (description.hasGradient) { shader.append(gVS_Header_Uniforms_HasGradient); } + if (description.hasBitmap) { + shader.append(gVS_Header_Uniforms_HasBitmap); + } // Varyings if (description.hasTexture) { shader.append(gVS_Header_Varyings_HasTexture); @@ -231,6 +246,9 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description if (description.hasGradient) { shader.append(gVS_Main_OutGradientIndex); } + if (description.hasBitmap) { + shader.append(gVS_Main_OutBitmapTexCoords); + } // Output transformed position shader.append(gVS_Main_Position); } @@ -278,6 +296,9 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti if (description.colorOp == ProgramDescription::kColorBlend) { generatePorterDuffBlend(shader, "blendColors", description.colorMode); } + if (description.isBitmapNpot) { + generateTextureWrap(shader, description.bitmapWrapS, description.bitmapWrapT); + } // Begin the shader shader.append(gFS_Main); { @@ -295,7 +316,11 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti shader.append(gFS_Main_FetchGradient); } if (description.hasBitmap) { - shader.append(gFS_Main_FetchBitmap); + if (!description.isBitmapNpot) { + shader.append(gFS_Main_FetchBitmap); + } else { + shader.append(gFS_Main_FetchBitmapNpot); + } } // Case when we have two shaders set if (description.hasGradient && description.hasBitmap) { @@ -305,6 +330,12 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti shader.append(gFS_Main_BlendShadersGB); } shader.append(gFS_Main_BlendShaders_Modulate); + } else { + if (description.hasGradient) { + shader.append(gFS_Main_GradientShader_Modulate); + } else if (description.hasBitmap) { + shader.append(gFS_Main_BitmapShader_Modulate); + } } // Apply the color op if needed shader.append(gFS_Main_ApplyColorOp[description.colorOp]); @@ -328,5 +359,37 @@ void ProgramCache::generatePorterDuffBlend(String8& shader, const char* name, shader.append("}\n"); } +void ProgramCache::generateTextureWrap(String8& shader, GLenum wrapS, GLenum wrapT) { + shader.append("\nvec2 wrap(vec2 texCoords) {\n"); + if (wrapS == GL_MIRRORED_REPEAT) { + shader.append(" float xMod2 = mod(texCoords.x, 2.0);\n"); + shader.append(" if (xMod2 > 1.0) xMod2 = 2.0 - xMod2;\n"); + } + if (wrapT == GL_MIRRORED_REPEAT) { + shader.append(" float yMod2 = mod(texCoords.y, 2.0);\n"); + shader.append(" if (yMod2 > 1.0) yMod2 = 2.0 - yMod2;\n"); + } + shader.append(" return vec2("); + switch (wrapS) { + case GL_REPEAT: + shader.append("mod(texCoords.x, 1.0)"); + break; + case GL_MIRRORED_REPEAT: + shader.append("xMod2"); + break; + } + shader.append(", "); + switch (wrapT) { + case GL_REPEAT: + shader.append("mod(texCoords.y, 1.0)"); + break; + case GL_MIRRORED_REPEAT: + shader.append("yMod2"); + break; + } + shader.append(");\n"); + shader.append("}\n"); +} + }; // namespace uirenderer }; // namespace android diff --git a/libs/hwui/ProgramCache.h b/libs/hwui/ProgramCache.h index 7f2f5fa..5a6ec33 100644 --- a/libs/hwui/ProgramCache.h +++ b/libs/hwui/ProgramCache.h @@ -20,6 +20,8 @@ #include <utils/KeyedVector.h> #include <utils/Log.h> +#include <GLES2/gl2.h> + #include <SkXfermode.h> #include "Program.h" @@ -32,7 +34,7 @@ namespace uirenderer { /////////////////////////////////////////////////////////////////////////////// // Debug -#define DEBUG_PROGRAM_CACHE 0 +#define DEBUG_PROGRAM_CACHE 1 // Debug #if DEBUG_PROGRAM_CACHE @@ -49,12 +51,19 @@ namespace uirenderer { #define PROGRAM_KEY_COLOR_MATRIX 0x20 #define PROGRAM_KEY_COLOR_LIGHTING 0x40 #define PROGRAM_KEY_COLOR_BLEND 0x80 +#define PROGRAM_KEY_BITMAP_NPOT 0x100 + +#define PROGRAM_KEY_BITMAP_WRAPS_MASK 0x600 +#define PROGRAM_KEY_BITMAP_WRAPT_MASK 0x1800 // Support only the 12 Porter-Duff modes for now #define PROGRAM_MAX_XFERMODE 0xC #define PROGRAM_XFERMODE_SHADER_SHIFT 24 #define PROGRAM_XFERMODE_COLOR_OP_SHIFT 20 +#define PROGRAM_BITMAP_WRAPS_SHIFT 9 +#define PROGRAM_BITMAP_WRAPT_SHIFT 11 + /////////////////////////////////////////////////////////////////////////////// // Types /////////////////////////////////////////////////////////////////////////////// @@ -80,7 +89,9 @@ struct ProgramDescription { ProgramDescription(): hasTexture(false), hasAlpha8Texture(false), - hasBitmap(false), hasGradient(false), shadersMode(SkXfermode::kClear_Mode), + hasBitmap(false), isBitmapNpot(false), hasGradient(false), + shadersMode(SkXfermode::kClear_Mode), isBitmapFirst(false), + bitmapWrapS(GL_CLAMP_TO_EDGE), bitmapWrapT(GL_CLAMP_TO_EDGE), colorOp(kColorNone), colorMode(SkXfermode::kClear_Mode) { } @@ -90,19 +101,41 @@ struct ProgramDescription { // Shaders bool hasBitmap; + bool isBitmapNpot; bool hasGradient; SkXfermode::Mode shadersMode; bool isBitmapFirst; + GLenum bitmapWrapS; + GLenum bitmapWrapT; // Color operations int colorOp; SkXfermode::Mode colorMode; + inline uint32_t getEnumForWrap(GLenum wrap) const { + switch (wrap) { + case GL_CLAMP_TO_EDGE: + return 0; + case GL_REPEAT: + return 1; + case GL_MIRRORED_REPEAT: + return 2; + } + return 0; + } + programid key() const { programid key = 0; if (hasTexture) key |= PROGRAM_KEY_TEXTURE; if (hasAlpha8Texture) key |= PROGRAM_KEY_A8_TEXTURE; - if (hasBitmap) key |= PROGRAM_KEY_BITMAP; + if (hasBitmap) { + key |= PROGRAM_KEY_BITMAP; + if (isBitmapNpot) { + key |= PROGRAM_KEY_BITMAP_NPOT; + key |= getEnumForWrap(bitmapWrapS) << PROGRAM_BITMAP_WRAPS_SHIFT; + key |= getEnumForWrap(bitmapWrapT) << PROGRAM_BITMAP_WRAPT_SHIFT; + } + } if (hasGradient) key |= PROGRAM_KEY_GRADIENT; if (isBitmapFirst) key |= PROGRAM_KEY_BITMAP_FIRST; if (hasBitmap && hasGradient) { @@ -144,6 +177,7 @@ private: String8 generateVertexShader(const ProgramDescription& description); String8 generateFragmentShader(const ProgramDescription& description); void generatePorterDuffBlend(String8& shader, const char* name, SkXfermode::Mode mode); + void generateTextureWrap(String8& shader, GLenum wrapS, GLenum wrapT); KeyedVector<programid, Program*> mCache; diff --git a/libs/hwui/shaders/drawColor.frag b/libs/hwui/shaders/drawColor.frag deleted file mode 100644 index 1d6cb8b..0000000 --- a/libs/hwui/shaders/drawColor.frag +++ /dev/null @@ -1,11 +0,0 @@ -SHADER_SOURCE(gDrawColorFragmentShader, - -precision mediump float; - -uniform vec4 color; - -void main(void) { - gl_FragColor = color; -} - -); diff --git a/libs/hwui/shaders/drawLinearGradient.frag b/libs/hwui/shaders/drawLinearGradient.frag deleted file mode 100644 index 469c662..0000000 --- a/libs/hwui/shaders/drawLinearGradient.frag +++ /dev/null @@ -1,14 +0,0 @@ -SHADER_SOURCE(gDrawLinearGradientFragmentShader, - -precision mediump float; - -varying float index; - -uniform vec4 color; -uniform sampler2D sampler; - -void main(void) { - gl_FragColor = texture2D(sampler, vec2(index, 0.5)) * color; -} - -); diff --git a/libs/hwui/shaders/drawLinearGradient.vert b/libs/hwui/shaders/drawLinearGradient.vert deleted file mode 100644 index d2f857d..0000000 --- a/libs/hwui/shaders/drawLinearGradient.vert +++ /dev/null @@ -1,20 +0,0 @@ -SHADER_SOURCE(gDrawLinearGradientVertexShader, - -attribute vec4 position; - -uniform mat4 transform; -uniform float gradientLength; -uniform vec2 gradient; -uniform vec2 start; -uniform mat4 screenSpace; - -varying float index; - -void main(void) { - vec4 location = screenSpace * position; - index = dot(location.xy - start, gradient) * gradientLength; - - gl_Position = transform * position; -} - -); diff --git a/libs/hwui/shaders/drawText.frag b/libs/hwui/shaders/drawText.frag deleted file mode 100644 index 49532c7..0000000 --- a/libs/hwui/shaders/drawText.frag +++ /dev/null @@ -1,14 +0,0 @@ -SHADER_SOURCE(gDrawTextFragmentShader, - -precision mediump float; - -varying vec2 outTexCoords; - -uniform vec4 color; -uniform sampler2D sampler; - -void main(void) { - gl_FragColor = color * texture2D(sampler, outTexCoords).a; -} - -); diff --git a/libs/hwui/shaders/drawTexture.frag b/libs/hwui/shaders/drawTexture.frag deleted file mode 100644 index 8390d8e..0000000 --- a/libs/hwui/shaders/drawTexture.frag +++ /dev/null @@ -1,14 +0,0 @@ -SHADER_SOURCE(gDrawTextureFragmentShader, - -precision mediump float; - -varying vec2 outTexCoords; - -uniform vec4 color; -uniform sampler2D sampler; - -void main(void) { - gl_FragColor = texture2D(sampler, outTexCoords) * color; -} - -); diff --git a/libs/hwui/shaders/drawTexture.vert b/libs/hwui/shaders/drawTexture.vert deleted file mode 100644 index 240aebf..0000000 --- a/libs/hwui/shaders/drawTexture.vert +++ /dev/null @@ -1,15 +0,0 @@ -SHADER_SOURCE(gDrawTextureVertexShader, - -attribute vec4 position; -attribute vec2 texCoords; - -uniform mat4 transform; - -varying vec2 outTexCoords; - -void main(void) { - outTexCoords = texCoords; - gl_Position = transform * position; -} - -); diff --git a/tests/HwAccelerationTest/src/com/google/android/test/hwui/ShadersActivity.java b/tests/HwAccelerationTest/src/com/google/android/test/hwui/ShadersActivity.java index 1912245..abd741c 100644 --- a/tests/HwAccelerationTest/src/com/google/android/test/hwui/ShadersActivity.java +++ b/tests/HwAccelerationTest/src/com/google/android/test/hwui/ShadersActivity.java @@ -68,6 +68,7 @@ public class ShadersActivity extends Activity { Shader.TileMode.REPEAT); Matrix m1 = new Matrix(); m1.setTranslate(mTexWidth / 2.0f, mTexHeight / 2.0f); + m1.postRotate(45, 0, 0); mTranslatedShader.setLocalMatrix(m1); mScaledShader = new BitmapShader(texture, Shader.TileMode.MIRROR, |