Loading core/java/android/view/GLES20Canvas.java +38 −1 Original line number Diff line number Diff line Loading @@ -17,16 +17,21 @@ package android.view; import android.graphics.Bitmap; import android.graphics.BitmapShader; import android.graphics.Canvas; import android.graphics.DrawFilter; import android.graphics.LinearGradient; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Picture; import android.graphics.PorterDuff; import android.graphics.RadialGradient; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Region; import android.graphics.Shader; import android.graphics.SweepGradient; import javax.microedition.khronos.opengles.GL; Loading Loading @@ -369,6 +374,7 @@ class GLES20Canvas extends Canvas { @Override public void drawPatch(Bitmap bitmap, byte[] chunks, RectF dst, Paint paint) { // Shaders are ignored when drawing patches final int nativePaint = paint == null ? 0 : paint.mNativePaint; nDrawPatch(mRenderer, bitmap.mNativeBitmap, chunks, dst.left, dst.top, dst.right, dst.bottom, nativePaint); Loading @@ -379,6 +385,7 @@ class GLES20Canvas extends Canvas { @Override public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) { // Shaders are ignored when drawing bitmaps final int nativePaint = paint == null ? 0 : paint.mNativePaint; nDrawBitmap(mRenderer, bitmap.mNativeBitmap, left, top, nativePaint); } Loading @@ -387,6 +394,7 @@ class GLES20Canvas extends Canvas { @Override public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) { // Shaders are ignored when drawing bitmaps final int nativePaint = paint == null ? 0 : paint.mNativePaint; nDrawBitmap(mRenderer, bitmap.mNativeBitmap, matrix.native_instance, nativePaint); } Loading @@ -395,6 +403,7 @@ class GLES20Canvas extends Canvas { @Override public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) { // Shaders are ignored when drawing bitmaps final int nativePaint = paint == null ? 0 : paint.mNativePaint; nDrawBitmap(mRenderer, bitmap.mNativeBitmap, src.left, src.top, src.right, src.bottom, dst.left, dst.top, dst.right, dst.bottom, nativePaint Loading @@ -403,6 +412,7 @@ class GLES20Canvas extends Canvas { @Override public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) { // Shaders are ignored when drawing bitmaps final int nativePaint = paint == null ? 0 : paint.mNativePaint; nDrawBitmap(mRenderer, bitmap.mNativeBitmap, src.left, src.top, src.right, src.bottom, dst.left, dst.top, dst.right, dst.bottom, nativePaint Loading @@ -416,6 +426,7 @@ class GLES20Canvas extends Canvas { @Override public void drawBitmap(int[] colors, int offset, int stride, float x, float y, int width, int height, boolean hasAlpha, Paint paint) { // Shaders are ignored when drawing bitmaps final Bitmap.Config config = hasAlpha ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; final Bitmap b = Bitmap.createBitmap(colors, offset, stride, width, height, config); final int nativePaint = paint == null ? 0 : paint.mNativePaint; Loading @@ -426,6 +437,7 @@ class GLES20Canvas extends Canvas { @Override public void drawBitmap(int[] colors, int offset, int stride, int x, int y, int width, int height, boolean hasAlpha, Paint paint) { // Shaders are ignored when drawing bitmaps drawBitmap(colors, offset, stride, (float) x, (float) y, width, height, hasAlpha, paint); } Loading Loading @@ -532,7 +544,9 @@ class GLES20Canvas extends Canvas { @Override public void drawRect(float left, float top, float right, float bottom, Paint paint) { boolean hasShader = setupShader(paint); nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint); if (hasShader) nResetShader(mRenderer); } private native void nDrawRect(int renderer, float left, float top, float right, float bottom, Loading @@ -555,7 +569,7 @@ class GLES20Canvas extends Canvas { @Override public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) { throw new UnsupportedOperationException(); // TODO: Implement } @Override Loading Loading @@ -607,4 +621,27 @@ class GLES20Canvas extends Canvas { int indexOffset, int indexCount, Paint paint) { // TODO: Implement } private boolean setupShader(Paint paint) { final Shader shader = paint.getShader(); if (shader != null) { if (shader instanceof BitmapShader) { final BitmapShader bs = (BitmapShader) shader; nSetupBitmapShader(mRenderer, bs.native_instance, bs.mBitmap.mNativeBitmap, bs.mTileX, bs.mTileY, bs.mLocalMatrix); return true; } else if (shader instanceof LinearGradient) { // TODO: Implement } else if (shader instanceof RadialGradient) { // TODO: Implement } else if (shader instanceof SweepGradient) { // TODO: Implement } } return false; } private native void nSetupBitmapShader(int renderer, int shader, int bitmap, int tileX, int tileY, int matrix); private native void nResetShader(int renderer); } core/jni/android_view_GLES20Canvas.cpp +19 −0 Original line number Diff line number Diff line Loading @@ -220,6 +220,22 @@ static void android_view_GLES20Canvas_drawRect(JNIEnv* env, jobject canvas, renderer->drawRect(left, top, right, bottom, paint); } // ---------------------------------------------------------------------------- // Shaders // ---------------------------------------------------------------------------- static void android_view_GLES20Canvas_resetShader(JNIEnv* env, jobject canvas, OpenGLRenderer* renderer) { renderer->resetShader(); } static void android_view_GLES20Canvas_setupBitmapShader(JNIEnv* env, jobject canvas, OpenGLRenderer* renderer, SkShader* shader, SkBitmap* bitmap, SkShader::TileMode tileX, SkShader::TileMode tileY, SkMatrix* matrix) { renderer->setupBitmapShader(bitmap, tileX, tileY, matrix, (shader->getFlags() & SkShader::kOpaqueAlpha_Flag) == 0); } // ---------------------------------------------------------------------------- // JNI Glue // ---------------------------------------------------------------------------- Loading Loading @@ -259,6 +275,9 @@ static JNINativeMethod gMethods[] = { { "nDrawColor", "(III)V", (void*) android_view_GLES20Canvas_drawColor }, { "nDrawRect", "(IFFFFI)V", (void*) android_view_GLES20Canvas_drawRect }, { "nResetShader", "(I)V", (void*) android_view_GLES20Canvas_resetShader }, { "nSetupBitmapShader", "(IIIIII)V", (void*) android_view_GLES20Canvas_setupBitmapShader }, { "nGetClipBounds", "(ILandroid/graphics/Rect;)Z", (void*) android_view_GLES20Canvas_getClipBounds }, }; Loading graphics/java/android/graphics/Shader.java +15 −4 Original line number Diff line number Diff line Loading @@ -23,9 +23,19 @@ package android.graphics; * drawn with that paint will get its color(s) from the shader. */ public class Shader { /** * Local matrix native instance. * * @hide */ public int mLocalMatrix; // this is set by subclasses, but don't make it public /* package */ int native_instance; /** * This is set by subclasses, but don't make it public. * * @hide */ public int native_instance; public enum TileMode { /** Loading Loading @@ -64,11 +74,12 @@ public class Shader { * @param localM The shader's new local matrix, or null to specify identity */ public void setLocalMatrix(Matrix localM) { nativeSetLocalMatrix(native_instance, localM != null ? localM.native_instance : 0); mLocalMatrix = localM != null ? localM.native_instance : 0; nativeSetLocalMatrix(native_instance, mLocalMatrix); } protected void finalize() throws Throwable { super.finalize(); nativeDestructor(native_instance); } Loading libs/hwui/OpenGLRenderer.cpp +121 −33 Original line number Diff line number Diff line Loading @@ -90,6 +90,12 @@ static const Blender gBlends[] = { { SkXfermode::kXor_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA } }; static const GLint gTileModes[] = { GL_CLAMP_TO_EDGE, // == SkShader::kClamp_TileMode GL_REPEAT, // == SkShader::kRepeat_Mode GL_MIRRORED_REPEAT // == SkShader::kMirror_TileMode }; /////////////////////////////////////////////////////////////////////////////// // Constructors/destructor /////////////////////////////////////////////////////////////////////////////// Loading @@ -116,9 +122,15 @@ OpenGLRenderer::OpenGLRenderer(): LOGD(" Using default layer cache size of %dMB", DEFAULT_LAYER_CACHE_SIZE); } mDrawColorShader = new DrawColorProgram; mDrawTextureShader = new DrawTextureProgram; mCurrentShader = mDrawTextureShader; mDrawColorProgram = new DrawColorProgram; mDrawTextureProgram = new DrawTextureProgram; mCurrentProgram = mDrawTextureProgram; mShader = kShaderNone; mShaderTileX = SkShader::kClamp_TileMode; mShaderTileY = SkShader::kClamp_TileMode; mShaderMatrix = NULL; mShaderBitmap = NULL; memcpy(mDrawTextureVertices, gDrawTextureVertices, sizeof(gDrawTextureVertices)); } Loading Loading @@ -295,7 +307,7 @@ int OpenGLRenderer::saveLayerAlpha(float left, float top, float right, float bot bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top, float right, float bottom, int alpha, SkXfermode::Mode mode,int flags) { LAYER_LOGD("Requesting layer %dx%d", size.width, size.height); LAYER_LOGD("Requesting layer %fx%f", right - left, bottom - top); LAYER_LOGD("Layer cache size = %d", mLayerCache.getSize()); GLuint previousFbo = snapshot->previous.get() ? snapshot->previous->fbo : 0; Loading Loading @@ -327,7 +339,7 @@ bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top, saveSnapshot(); // TODO: This doesn't preserve other transformations (check Skia first) mSnapshot->transform.loadTranslate(-left, -top, 0.0f); mSnapshot->clipRect.set(left, top, right, bottom); mSnapshot->setClip(left, top, right, bottom); mSnapshot->height = bottom - top; setScissorFromClip(); Loading Loading @@ -512,50 +524,125 @@ void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, // Skia draws using the color's alpha channel if < 255 // Otherwise, it uses the paint's alpha int color = p->getColor(); if (((color >> 24) & 0xFF) == 255) { if (((color >> 24) & 0xff) == 255) { color |= p->getAlpha() << 24; } drawColorRect(left, top, right, bottom, color, mode); } /////////////////////////////////////////////////////////////////////////////// // Shaders /////////////////////////////////////////////////////////////////////////////// void OpenGLRenderer::resetShader() { mShader = OpenGLRenderer::kShaderNone; mShaderBlend = false; mShaderTileX = SkShader::kClamp_TileMode; mShaderTileY = SkShader::kClamp_TileMode; } void OpenGLRenderer::setupBitmapShader(SkBitmap* bitmap, SkShader::TileMode tileX, SkShader::TileMode tileY, SkMatrix* matrix, bool hasAlpha) { mShader = kShaderBitmap; mShaderBlend = hasAlpha; mShaderBitmap = bitmap; mShaderTileX = tileX; mShaderTileY = tileY; mShaderMatrix = matrix; } /////////////////////////////////////////////////////////////////////////////// // Drawing implementation /////////////////////////////////////////////////////////////////////////////// void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom, int color, SkXfermode::Mode mode, bool ignoreTransform) { // If a shader is set, preserve only the alpha if (mShader != kShaderNone) { color |= 0x00ffffff; } // Render using pre-multiplied alpha const int alpha = (color >> 24) & 0xFF; const GLfloat a = alpha / 255.0f; const GLfloat r = ((color >> 16) & 0xFF) / 255.0f; const GLfloat g = ((color >> 8) & 0xFF) / 255.0f; const GLfloat b = ((color ) & 0xFF) / 255.0f; const GLfloat r = a * ((color >> 16) & 0xFF) / 255.0f; const GLfloat g = a * ((color >> 8) & 0xFF) / 255.0f; const GLfloat b = a * ((color ) & 0xFF) / 255.0f; switch (mShader) { case kShaderBitmap: drawBitmapShader(left, top, right, bottom, a, mode); return; default: break; } // Pre-multiplication happens when setting the shader color chooseBlending(alpha < 255, mode); chooseBlending(alpha < 255 || mShaderBlend, mode); mModelView.loadTranslate(left, top, 0.0f); mModelView.scale(right - left, bottom - top, 1.0f); const bool inUse = useShader(mDrawColorShader); // TODO: Pick the program matching the current shader sp<DrawColorProgram> program = mDrawColorProgram; if (!useProgram(program)) { const GLvoid* p = &gDrawColorVertices[0].position[0]; glVertexAttribPointer(program->position, 2, GL_FLOAT, GL_FALSE, gDrawColorVertexStride, p); } if (!ignoreTransform) { mDrawColorShader->set(mOrthoMatrix, mModelView, mSnapshot->transform); program->set(mOrthoMatrix, mModelView, mSnapshot->transform); } else { mat4 identity; mDrawColorShader->set(mOrthoMatrix, mModelView, identity); program->set(mOrthoMatrix, mModelView, identity); } if (!inUse) { const GLvoid* p = &gDrawColorVertices[0].position[0]; glVertexAttribPointer(mDrawColorShader->position, 2, GL_FLOAT, GL_FALSE, gDrawColorVertexStride, p); } // Render using pre-multiplied alpha glUniform4f(mDrawColorShader->color, r * a, g * a, b * a, a); glUniform4f(program->color, r, g, b, a); glDrawArrays(GL_TRIANGLE_STRIP, 0, gDrawColorVertexCount); } void OpenGLRenderer::drawBitmapShader(float left, float top, float right, float bottom, float alpha, SkXfermode::Mode mode) { 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; if (mShaderMatrix) { SkMatrix inverse; mShaderMatrix->invert(&inverse); mat4 m(inverse); Rect r(u1, v1, u2, v2); m.mapRect(r); u1 = r.left; u2 = r.right; v1 = r.top; v2 = r.bottom; } u1 /= width; u2 /= width; v1 /= height; v2 /= height; resetDrawTextureTexCoords(u1, v1, u2, v2); drawTextureMesh(left, top, right, bottom, texture->id, alpha, mode, texture->blend, &mDrawTextureVertices[0].position[0], &mDrawTextureVertices[0].texture[0], NULL); resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f); } void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom, const Texture* texture, const SkPaint* paint) { int alpha; Loading @@ -578,21 +665,22 @@ void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float b mModelView.loadTranslate(left, top, 0.0f); mModelView.scale(right - left, bottom - top, 1.0f); useShader(mDrawTextureShader); mDrawTextureShader->set(mOrthoMatrix, mModelView, mSnapshot->transform); useProgram(mDrawTextureProgram); mDrawTextureProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform); chooseBlending(blend || alpha < 1.0f, mode); // TODO: Only bind/set parameters when needed glBindTexture(GL_TEXTURE_2D, texture); // TODO handle tiling and filtering here glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gTileModes[mShaderTileX]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gTileModes[mShaderTileY]); // Always premultiplied glUniform4f(mDrawTextureShader->color, alpha, alpha, alpha, alpha); glUniform4f(mDrawTextureProgram->color, alpha, alpha, alpha, alpha); glVertexAttribPointer(mDrawTextureShader->position, 2, GL_FLOAT, GL_FALSE, glVertexAttribPointer(mDrawTextureProgram->position, 2, GL_FLOAT, GL_FALSE, gDrawTextureVertexStride, vertices); glVertexAttribPointer(mDrawTextureShader->texCoords, 2, GL_FLOAT, GL_FALSE, glVertexAttribPointer(mDrawTextureProgram->texCoords, 2, GL_FLOAT, GL_FALSE, gDrawTextureVertexStride, texCoords); if (!indices) { Loading Loading @@ -630,11 +718,11 @@ void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode, bool isPr mBlend = blend; } bool OpenGLRenderer::useShader(const sp<Program>& shader) { if (!shader->isInUse()) { mCurrentShader->remove(); shader->use(); mCurrentShader = shader; bool OpenGLRenderer::useProgram(const sp<Program>& program) { if (!program->isInUse()) { mCurrentProgram->remove(); program->use(); mCurrentProgram = program; return false; } return true; Loading libs/hwui/OpenGLRenderer.h +48 −9 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ #include <SkBitmap.h> #include <SkMatrix.h> #include <SkPaint.h> #include <SkShader.h> #include <SkXfermode.h> #include <utils/RefBase.h> Loading Loading @@ -98,7 +99,22 @@ public: void drawColor(int color, SkXfermode::Mode mode); void drawRect(float left, float top, float right, float bottom, const SkPaint* paint); void resetShader(); void setupBitmapShader(SkBitmap* bitmap, SkShader::TileMode tileX, SkShader::TileMode tileY, SkMatrix* matrix, bool hasAlpha); private: /** * Type of Skia shader in use. */ enum ShaderType { kShaderNone, kShaderBitmap, kShaderLinearGradient, kShaderCircularGradient, kShaderSweepGradient }; /** * Saves the current state of the renderer as a new snapshot. * The new snapshot is saved in mSnapshot and the previous snapshot Loading Loading @@ -216,6 +232,19 @@ private: float alpha, SkXfermode::Mode mode, bool blend, GLvoid* vertices, GLvoid* texCoords, GLvoid* indices, GLsizei elementsCount = 0); /** * Fills the specified rectangle with the currently set bitmap shader. * * @param left The left coordinate of the rectangle * @param top The top coordinate of the rectangle * @param right The right coordinate of the rectangle * @param bottom The bottom coordinate of the rectangle * @param alpha An additional translucency parameter, between 0.0f and 1.0f * @param mode The blending mode */ void drawBitmapShader(float left, float top, float right, float bottom, float alpha, SkXfermode::Mode mode); /** * Resets the texture coordinates stored in mDrawTextureVertices. Setting the values * back to default is achieved by calling: Loading Loading @@ -246,14 +275,16 @@ private: inline void chooseBlending(bool blend, SkXfermode::Mode mode, bool isPremultiplied = true); /** * Use the specified shader with the current GL context. If the shader is already * in use, it will not be bound again. If it is not in use, the current shader is * marked unused and the specified shader becomes used and becomes the new * current shader. * Use the specified program with the current GL context. If the program is already * in use, it will not be bound again. If it is not in use, the current program is * marked unused and the specified program becomes used and becomes the new * current program. * * @return true If the specified shader was already in use, false otherwise. * @param program The program to use * * @return true If the specified program was already in use, false otherwise. */ inline bool useShader(const sp<Program>& shader); inline bool useProgram(const sp<Program>& program); // Dimensions of the drawing surface int mWidth, mHeight; Loading @@ -272,9 +303,9 @@ private: sp<Snapshot> mSnapshot; // Shaders sp<Program> mCurrentShader; sp<DrawColorProgram> mDrawColorShader; sp<DrawTextureProgram> mDrawTextureShader; sp<Program> mCurrentProgram; sp<DrawColorProgram> mDrawColorProgram; sp<DrawTextureProgram> mDrawTextureProgram; // Used to draw textured quads TextureVertex mDrawTextureVertices[4]; Loading @@ -284,6 +315,14 @@ private: GLenum mLastSrcMode; GLenum mLastDstMode; // Skia shader ShaderType mShader; bool mShaderBlend; SkBitmap* mShaderBitmap; SkShader::TileMode mShaderTileX; SkShader::TileMode mShaderTileY; SkMatrix* mShaderMatrix; // Various caches TextureCache mTextureCache; LayerCache mLayerCache; Loading Loading
core/java/android/view/GLES20Canvas.java +38 −1 Original line number Diff line number Diff line Loading @@ -17,16 +17,21 @@ package android.view; import android.graphics.Bitmap; import android.graphics.BitmapShader; import android.graphics.Canvas; import android.graphics.DrawFilter; import android.graphics.LinearGradient; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Picture; import android.graphics.PorterDuff; import android.graphics.RadialGradient; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Region; import android.graphics.Shader; import android.graphics.SweepGradient; import javax.microedition.khronos.opengles.GL; Loading Loading @@ -369,6 +374,7 @@ class GLES20Canvas extends Canvas { @Override public void drawPatch(Bitmap bitmap, byte[] chunks, RectF dst, Paint paint) { // Shaders are ignored when drawing patches final int nativePaint = paint == null ? 0 : paint.mNativePaint; nDrawPatch(mRenderer, bitmap.mNativeBitmap, chunks, dst.left, dst.top, dst.right, dst.bottom, nativePaint); Loading @@ -379,6 +385,7 @@ class GLES20Canvas extends Canvas { @Override public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) { // Shaders are ignored when drawing bitmaps final int nativePaint = paint == null ? 0 : paint.mNativePaint; nDrawBitmap(mRenderer, bitmap.mNativeBitmap, left, top, nativePaint); } Loading @@ -387,6 +394,7 @@ class GLES20Canvas extends Canvas { @Override public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) { // Shaders are ignored when drawing bitmaps final int nativePaint = paint == null ? 0 : paint.mNativePaint; nDrawBitmap(mRenderer, bitmap.mNativeBitmap, matrix.native_instance, nativePaint); } Loading @@ -395,6 +403,7 @@ class GLES20Canvas extends Canvas { @Override public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) { // Shaders are ignored when drawing bitmaps final int nativePaint = paint == null ? 0 : paint.mNativePaint; nDrawBitmap(mRenderer, bitmap.mNativeBitmap, src.left, src.top, src.right, src.bottom, dst.left, dst.top, dst.right, dst.bottom, nativePaint Loading @@ -403,6 +412,7 @@ class GLES20Canvas extends Canvas { @Override public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) { // Shaders are ignored when drawing bitmaps final int nativePaint = paint == null ? 0 : paint.mNativePaint; nDrawBitmap(mRenderer, bitmap.mNativeBitmap, src.left, src.top, src.right, src.bottom, dst.left, dst.top, dst.right, dst.bottom, nativePaint Loading @@ -416,6 +426,7 @@ class GLES20Canvas extends Canvas { @Override public void drawBitmap(int[] colors, int offset, int stride, float x, float y, int width, int height, boolean hasAlpha, Paint paint) { // Shaders are ignored when drawing bitmaps final Bitmap.Config config = hasAlpha ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; final Bitmap b = Bitmap.createBitmap(colors, offset, stride, width, height, config); final int nativePaint = paint == null ? 0 : paint.mNativePaint; Loading @@ -426,6 +437,7 @@ class GLES20Canvas extends Canvas { @Override public void drawBitmap(int[] colors, int offset, int stride, int x, int y, int width, int height, boolean hasAlpha, Paint paint) { // Shaders are ignored when drawing bitmaps drawBitmap(colors, offset, stride, (float) x, (float) y, width, height, hasAlpha, paint); } Loading Loading @@ -532,7 +544,9 @@ class GLES20Canvas extends Canvas { @Override public void drawRect(float left, float top, float right, float bottom, Paint paint) { boolean hasShader = setupShader(paint); nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint); if (hasShader) nResetShader(mRenderer); } private native void nDrawRect(int renderer, float left, float top, float right, float bottom, Loading @@ -555,7 +569,7 @@ class GLES20Canvas extends Canvas { @Override public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) { throw new UnsupportedOperationException(); // TODO: Implement } @Override Loading Loading @@ -607,4 +621,27 @@ class GLES20Canvas extends Canvas { int indexOffset, int indexCount, Paint paint) { // TODO: Implement } private boolean setupShader(Paint paint) { final Shader shader = paint.getShader(); if (shader != null) { if (shader instanceof BitmapShader) { final BitmapShader bs = (BitmapShader) shader; nSetupBitmapShader(mRenderer, bs.native_instance, bs.mBitmap.mNativeBitmap, bs.mTileX, bs.mTileY, bs.mLocalMatrix); return true; } else if (shader instanceof LinearGradient) { // TODO: Implement } else if (shader instanceof RadialGradient) { // TODO: Implement } else if (shader instanceof SweepGradient) { // TODO: Implement } } return false; } private native void nSetupBitmapShader(int renderer, int shader, int bitmap, int tileX, int tileY, int matrix); private native void nResetShader(int renderer); }
core/jni/android_view_GLES20Canvas.cpp +19 −0 Original line number Diff line number Diff line Loading @@ -220,6 +220,22 @@ static void android_view_GLES20Canvas_drawRect(JNIEnv* env, jobject canvas, renderer->drawRect(left, top, right, bottom, paint); } // ---------------------------------------------------------------------------- // Shaders // ---------------------------------------------------------------------------- static void android_view_GLES20Canvas_resetShader(JNIEnv* env, jobject canvas, OpenGLRenderer* renderer) { renderer->resetShader(); } static void android_view_GLES20Canvas_setupBitmapShader(JNIEnv* env, jobject canvas, OpenGLRenderer* renderer, SkShader* shader, SkBitmap* bitmap, SkShader::TileMode tileX, SkShader::TileMode tileY, SkMatrix* matrix) { renderer->setupBitmapShader(bitmap, tileX, tileY, matrix, (shader->getFlags() & SkShader::kOpaqueAlpha_Flag) == 0); } // ---------------------------------------------------------------------------- // JNI Glue // ---------------------------------------------------------------------------- Loading Loading @@ -259,6 +275,9 @@ static JNINativeMethod gMethods[] = { { "nDrawColor", "(III)V", (void*) android_view_GLES20Canvas_drawColor }, { "nDrawRect", "(IFFFFI)V", (void*) android_view_GLES20Canvas_drawRect }, { "nResetShader", "(I)V", (void*) android_view_GLES20Canvas_resetShader }, { "nSetupBitmapShader", "(IIIIII)V", (void*) android_view_GLES20Canvas_setupBitmapShader }, { "nGetClipBounds", "(ILandroid/graphics/Rect;)Z", (void*) android_view_GLES20Canvas_getClipBounds }, }; Loading
graphics/java/android/graphics/Shader.java +15 −4 Original line number Diff line number Diff line Loading @@ -23,9 +23,19 @@ package android.graphics; * drawn with that paint will get its color(s) from the shader. */ public class Shader { /** * Local matrix native instance. * * @hide */ public int mLocalMatrix; // this is set by subclasses, but don't make it public /* package */ int native_instance; /** * This is set by subclasses, but don't make it public. * * @hide */ public int native_instance; public enum TileMode { /** Loading Loading @@ -64,11 +74,12 @@ public class Shader { * @param localM The shader's new local matrix, or null to specify identity */ public void setLocalMatrix(Matrix localM) { nativeSetLocalMatrix(native_instance, localM != null ? localM.native_instance : 0); mLocalMatrix = localM != null ? localM.native_instance : 0; nativeSetLocalMatrix(native_instance, mLocalMatrix); } protected void finalize() throws Throwable { super.finalize(); nativeDestructor(native_instance); } Loading
libs/hwui/OpenGLRenderer.cpp +121 −33 Original line number Diff line number Diff line Loading @@ -90,6 +90,12 @@ static const Blender gBlends[] = { { SkXfermode::kXor_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA } }; static const GLint gTileModes[] = { GL_CLAMP_TO_EDGE, // == SkShader::kClamp_TileMode GL_REPEAT, // == SkShader::kRepeat_Mode GL_MIRRORED_REPEAT // == SkShader::kMirror_TileMode }; /////////////////////////////////////////////////////////////////////////////// // Constructors/destructor /////////////////////////////////////////////////////////////////////////////// Loading @@ -116,9 +122,15 @@ OpenGLRenderer::OpenGLRenderer(): LOGD(" Using default layer cache size of %dMB", DEFAULT_LAYER_CACHE_SIZE); } mDrawColorShader = new DrawColorProgram; mDrawTextureShader = new DrawTextureProgram; mCurrentShader = mDrawTextureShader; mDrawColorProgram = new DrawColorProgram; mDrawTextureProgram = new DrawTextureProgram; mCurrentProgram = mDrawTextureProgram; mShader = kShaderNone; mShaderTileX = SkShader::kClamp_TileMode; mShaderTileY = SkShader::kClamp_TileMode; mShaderMatrix = NULL; mShaderBitmap = NULL; memcpy(mDrawTextureVertices, gDrawTextureVertices, sizeof(gDrawTextureVertices)); } Loading Loading @@ -295,7 +307,7 @@ int OpenGLRenderer::saveLayerAlpha(float left, float top, float right, float bot bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top, float right, float bottom, int alpha, SkXfermode::Mode mode,int flags) { LAYER_LOGD("Requesting layer %dx%d", size.width, size.height); LAYER_LOGD("Requesting layer %fx%f", right - left, bottom - top); LAYER_LOGD("Layer cache size = %d", mLayerCache.getSize()); GLuint previousFbo = snapshot->previous.get() ? snapshot->previous->fbo : 0; Loading Loading @@ -327,7 +339,7 @@ bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top, saveSnapshot(); // TODO: This doesn't preserve other transformations (check Skia first) mSnapshot->transform.loadTranslate(-left, -top, 0.0f); mSnapshot->clipRect.set(left, top, right, bottom); mSnapshot->setClip(left, top, right, bottom); mSnapshot->height = bottom - top; setScissorFromClip(); Loading Loading @@ -512,50 +524,125 @@ void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, // Skia draws using the color's alpha channel if < 255 // Otherwise, it uses the paint's alpha int color = p->getColor(); if (((color >> 24) & 0xFF) == 255) { if (((color >> 24) & 0xff) == 255) { color |= p->getAlpha() << 24; } drawColorRect(left, top, right, bottom, color, mode); } /////////////////////////////////////////////////////////////////////////////// // Shaders /////////////////////////////////////////////////////////////////////////////// void OpenGLRenderer::resetShader() { mShader = OpenGLRenderer::kShaderNone; mShaderBlend = false; mShaderTileX = SkShader::kClamp_TileMode; mShaderTileY = SkShader::kClamp_TileMode; } void OpenGLRenderer::setupBitmapShader(SkBitmap* bitmap, SkShader::TileMode tileX, SkShader::TileMode tileY, SkMatrix* matrix, bool hasAlpha) { mShader = kShaderBitmap; mShaderBlend = hasAlpha; mShaderBitmap = bitmap; mShaderTileX = tileX; mShaderTileY = tileY; mShaderMatrix = matrix; } /////////////////////////////////////////////////////////////////////////////// // Drawing implementation /////////////////////////////////////////////////////////////////////////////// void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom, int color, SkXfermode::Mode mode, bool ignoreTransform) { // If a shader is set, preserve only the alpha if (mShader != kShaderNone) { color |= 0x00ffffff; } // Render using pre-multiplied alpha const int alpha = (color >> 24) & 0xFF; const GLfloat a = alpha / 255.0f; const GLfloat r = ((color >> 16) & 0xFF) / 255.0f; const GLfloat g = ((color >> 8) & 0xFF) / 255.0f; const GLfloat b = ((color ) & 0xFF) / 255.0f; const GLfloat r = a * ((color >> 16) & 0xFF) / 255.0f; const GLfloat g = a * ((color >> 8) & 0xFF) / 255.0f; const GLfloat b = a * ((color ) & 0xFF) / 255.0f; switch (mShader) { case kShaderBitmap: drawBitmapShader(left, top, right, bottom, a, mode); return; default: break; } // Pre-multiplication happens when setting the shader color chooseBlending(alpha < 255, mode); chooseBlending(alpha < 255 || mShaderBlend, mode); mModelView.loadTranslate(left, top, 0.0f); mModelView.scale(right - left, bottom - top, 1.0f); const bool inUse = useShader(mDrawColorShader); // TODO: Pick the program matching the current shader sp<DrawColorProgram> program = mDrawColorProgram; if (!useProgram(program)) { const GLvoid* p = &gDrawColorVertices[0].position[0]; glVertexAttribPointer(program->position, 2, GL_FLOAT, GL_FALSE, gDrawColorVertexStride, p); } if (!ignoreTransform) { mDrawColorShader->set(mOrthoMatrix, mModelView, mSnapshot->transform); program->set(mOrthoMatrix, mModelView, mSnapshot->transform); } else { mat4 identity; mDrawColorShader->set(mOrthoMatrix, mModelView, identity); program->set(mOrthoMatrix, mModelView, identity); } if (!inUse) { const GLvoid* p = &gDrawColorVertices[0].position[0]; glVertexAttribPointer(mDrawColorShader->position, 2, GL_FLOAT, GL_FALSE, gDrawColorVertexStride, p); } // Render using pre-multiplied alpha glUniform4f(mDrawColorShader->color, r * a, g * a, b * a, a); glUniform4f(program->color, r, g, b, a); glDrawArrays(GL_TRIANGLE_STRIP, 0, gDrawColorVertexCount); } void OpenGLRenderer::drawBitmapShader(float left, float top, float right, float bottom, float alpha, SkXfermode::Mode mode) { 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; if (mShaderMatrix) { SkMatrix inverse; mShaderMatrix->invert(&inverse); mat4 m(inverse); Rect r(u1, v1, u2, v2); m.mapRect(r); u1 = r.left; u2 = r.right; v1 = r.top; v2 = r.bottom; } u1 /= width; u2 /= width; v1 /= height; v2 /= height; resetDrawTextureTexCoords(u1, v1, u2, v2); drawTextureMesh(left, top, right, bottom, texture->id, alpha, mode, texture->blend, &mDrawTextureVertices[0].position[0], &mDrawTextureVertices[0].texture[0], NULL); resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f); } void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom, const Texture* texture, const SkPaint* paint) { int alpha; Loading @@ -578,21 +665,22 @@ void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float b mModelView.loadTranslate(left, top, 0.0f); mModelView.scale(right - left, bottom - top, 1.0f); useShader(mDrawTextureShader); mDrawTextureShader->set(mOrthoMatrix, mModelView, mSnapshot->transform); useProgram(mDrawTextureProgram); mDrawTextureProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform); chooseBlending(blend || alpha < 1.0f, mode); // TODO: Only bind/set parameters when needed glBindTexture(GL_TEXTURE_2D, texture); // TODO handle tiling and filtering here glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gTileModes[mShaderTileX]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gTileModes[mShaderTileY]); // Always premultiplied glUniform4f(mDrawTextureShader->color, alpha, alpha, alpha, alpha); glUniform4f(mDrawTextureProgram->color, alpha, alpha, alpha, alpha); glVertexAttribPointer(mDrawTextureShader->position, 2, GL_FLOAT, GL_FALSE, glVertexAttribPointer(mDrawTextureProgram->position, 2, GL_FLOAT, GL_FALSE, gDrawTextureVertexStride, vertices); glVertexAttribPointer(mDrawTextureShader->texCoords, 2, GL_FLOAT, GL_FALSE, glVertexAttribPointer(mDrawTextureProgram->texCoords, 2, GL_FLOAT, GL_FALSE, gDrawTextureVertexStride, texCoords); if (!indices) { Loading Loading @@ -630,11 +718,11 @@ void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode, bool isPr mBlend = blend; } bool OpenGLRenderer::useShader(const sp<Program>& shader) { if (!shader->isInUse()) { mCurrentShader->remove(); shader->use(); mCurrentShader = shader; bool OpenGLRenderer::useProgram(const sp<Program>& program) { if (!program->isInUse()) { mCurrentProgram->remove(); program->use(); mCurrentProgram = program; return false; } return true; Loading
libs/hwui/OpenGLRenderer.h +48 −9 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ #include <SkBitmap.h> #include <SkMatrix.h> #include <SkPaint.h> #include <SkShader.h> #include <SkXfermode.h> #include <utils/RefBase.h> Loading Loading @@ -98,7 +99,22 @@ public: void drawColor(int color, SkXfermode::Mode mode); void drawRect(float left, float top, float right, float bottom, const SkPaint* paint); void resetShader(); void setupBitmapShader(SkBitmap* bitmap, SkShader::TileMode tileX, SkShader::TileMode tileY, SkMatrix* matrix, bool hasAlpha); private: /** * Type of Skia shader in use. */ enum ShaderType { kShaderNone, kShaderBitmap, kShaderLinearGradient, kShaderCircularGradient, kShaderSweepGradient }; /** * Saves the current state of the renderer as a new snapshot. * The new snapshot is saved in mSnapshot and the previous snapshot Loading Loading @@ -216,6 +232,19 @@ private: float alpha, SkXfermode::Mode mode, bool blend, GLvoid* vertices, GLvoid* texCoords, GLvoid* indices, GLsizei elementsCount = 0); /** * Fills the specified rectangle with the currently set bitmap shader. * * @param left The left coordinate of the rectangle * @param top The top coordinate of the rectangle * @param right The right coordinate of the rectangle * @param bottom The bottom coordinate of the rectangle * @param alpha An additional translucency parameter, between 0.0f and 1.0f * @param mode The blending mode */ void drawBitmapShader(float left, float top, float right, float bottom, float alpha, SkXfermode::Mode mode); /** * Resets the texture coordinates stored in mDrawTextureVertices. Setting the values * back to default is achieved by calling: Loading Loading @@ -246,14 +275,16 @@ private: inline void chooseBlending(bool blend, SkXfermode::Mode mode, bool isPremultiplied = true); /** * Use the specified shader with the current GL context. If the shader is already * in use, it will not be bound again. If it is not in use, the current shader is * marked unused and the specified shader becomes used and becomes the new * current shader. * Use the specified program with the current GL context. If the program is already * in use, it will not be bound again. If it is not in use, the current program is * marked unused and the specified program becomes used and becomes the new * current program. * * @return true If the specified shader was already in use, false otherwise. * @param program The program to use * * @return true If the specified program was already in use, false otherwise. */ inline bool useShader(const sp<Program>& shader); inline bool useProgram(const sp<Program>& program); // Dimensions of the drawing surface int mWidth, mHeight; Loading @@ -272,9 +303,9 @@ private: sp<Snapshot> mSnapshot; // Shaders sp<Program> mCurrentShader; sp<DrawColorProgram> mDrawColorShader; sp<DrawTextureProgram> mDrawTextureShader; sp<Program> mCurrentProgram; sp<DrawColorProgram> mDrawColorProgram; sp<DrawTextureProgram> mDrawTextureProgram; // Used to draw textured quads TextureVertex mDrawTextureVertices[4]; Loading @@ -284,6 +315,14 @@ private: GLenum mLastSrcMode; GLenum mLastDstMode; // Skia shader ShaderType mShader; bool mShaderBlend; SkBitmap* mShaderBitmap; SkShader::TileMode mShaderTileX; SkShader::TileMode mShaderTileY; SkMatrix* mShaderMatrix; // Various caches TextureCache mTextureCache; LayerCache mLayerCache; Loading