Loading include/input/Input.h +13 −1 Original line number Original line Diff line number Diff line Loading @@ -70,6 +70,14 @@ enum { */ */ AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE = 0x8, AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE = 0x8, /** * This flag indicates that the event will not cause a focus change if it is directed to an * unfocused window, even if it an ACTION_DOWN. This is typically used with pointer * gestures to allow the user to direct gestures to an unfocused window without bringing it * into focus. */ AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE = 0x40, /* Motion event is inconsistent with previously sent motion events. */ /* Motion event is inconsistent with previously sent motion events. */ AMOTION_EVENT_FLAG_TAINTED = 0x80000000, AMOTION_EVENT_FLAG_TAINTED = 0x80000000, }; }; Loading Loading @@ -746,10 +754,14 @@ public: void scale(float globalScaleFactor); void scale(float globalScaleFactor); // Apply 3x3 perspective matrix transformation. // Set 3x3 perspective matrix transformation. // Matrix is in row-major form and compatible with SkMatrix. // Matrix is in row-major form and compatible with SkMatrix. void transform(const std::array<float, 9>& matrix); void transform(const std::array<float, 9>& matrix); // Apply 3x3 perspective matrix transformation only to content (do not modify mTransform). // Matrix is in row-major form and compatible with SkMatrix. void applyTransform(const std::array<float, 9>& matrix); #ifdef __linux__ #ifdef __linux__ status_t readFromParcel(Parcel* parcel); status_t readFromParcel(Parcel* parcel); status_t writeToParcel(Parcel* parcel) const; status_t writeToParcel(Parcel* parcel) const; Loading include/input/InputTransport.h +1 −1 Original line number Original line Diff line number Diff line Loading @@ -229,7 +229,7 @@ public: InputChannel(const InputChannel& other) InputChannel(const InputChannel& other) : mName(other.mName), mFd(::dup(other.mFd)), mToken(other.mToken){}; : mName(other.mName), mFd(::dup(other.mFd)), mToken(other.mToken){}; InputChannel(const std::string name, android::base::unique_fd fd, sp<IBinder> token); InputChannel(const std::string name, android::base::unique_fd fd, sp<IBinder> token); virtual ~InputChannel(); ~InputChannel() override; /** /** * Create a pair of input channels. * Create a pair of input channels. * The two returned input channels are equivalent, and are labeled as "server" and "client" * The two returned input channels are equivalent, and are labeled as "server" and "client" Loading libs/input/Input.cpp +18 −0 Original line number Original line Diff line number Diff line Loading @@ -569,6 +569,24 @@ void MotionEvent::transform(const std::array<float, 9>& matrix) { } } } } void MotionEvent::applyTransform(const std::array<float, 9>& matrix) { // Determine how the origin is transformed by the matrix so that we // can transform orientation vectors. vec2 origin = transformPoint(matrix, 0, 0); // Apply the transformation to all samples. size_t numSamples = mSamplePointerCoords.size(); for (size_t i = 0; i < numSamples; i++) { PointerCoords& c = mSamplePointerCoords.editItemAt(i); float orientation = c.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION); c.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, transformAngle(matrix, orientation, origin.x, origin.y)); vec2 xy = transformPoint(matrix, c.getX(), c.getY()); c.setAxisValue(AMOTION_EVENT_AXIS_X, xy.x); c.setAxisValue(AMOTION_EVENT_AXIS_Y, xy.y); } } #ifdef __linux__ #ifdef __linux__ static status_t readFromParcel(ui::Transform& transform, const Parcel& parcel) { static status_t readFromParcel(ui::Transform& transform, const Parcel& parcel) { float dsdx, dtdx, tx, dtdy, dsdy, ty; float dsdx, dtdx, tx, dtdy, dsdy, ty; Loading libs/input/tests/InputEvent_test.cpp +47 −21 Original line number Original line Diff line number Diff line Loading @@ -636,8 +636,7 @@ TEST_F(MotionEventTest, Transform) { ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001); ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001); } } TEST_F(MotionEventTest, RawCompatTransform) { MotionEvent createTouchDownEvent(int x, int y, ui::Transform transform) { auto createTouchDownEvent = [](int x, int y, ui::Transform transform) { std::vector<PointerProperties> pointerProperties; std::vector<PointerProperties> pointerProperties; pointerProperties.push_back(PointerProperties{/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER}); pointerProperties.push_back(PointerProperties{/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER}); std::vector<PointerCoords> pointerCoords; std::vector<PointerCoords> pointerCoords; Loading @@ -650,14 +649,41 @@ TEST_F(MotionEventTest, RawCompatTransform) { /* displayId */ 0, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, /* displayId */ 0, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, /* actionButton */ 0, /* flags */ 0, /* edgeFlags */ 0, AMETA_NONE, /* actionButton */ 0, /* flags */ 0, /* edgeFlags */ 0, AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE, transform, /* buttonState */ 0, MotionClassification::NONE, transform, /* xPrecision */ 0, /* yPrecision */ 0, /* xPrecision */ 0, /* yPrecision */ 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, /* displayWidth */ 400, AMOTION_EVENT_INVALID_CURSOR_POSITION, /* displayWidth */ 400, /* displayHeight */ 800, eventTime, eventTime, pointerCoords.size(), /* displayHeight */ 800, eventTime, eventTime, pointerCoords.size(), pointerProperties.data(), pointerCoords.data()); pointerProperties.data(), pointerCoords.data()); return event; return event; }; } TEST_F(MotionEventTest, ApplyTransform) { // Create a rotate-90 transform with an offset (like a window which isn't fullscreen). ui::Transform identity; ui::Transform xform(ui::Transform::ROT_90, 800, 400); xform.set(xform.tx() + 20, xform.ty() + 40); MotionEvent event = createTouchDownEvent(60, 100, xform); ASSERT_EQ(700, event.getRawX(0)); ASSERT_EQ(60, event.getRawY(0)); ASSERT_NE(event.getRawX(0), event.getX(0)); ASSERT_NE(event.getRawY(0), event.getY(0)); MotionEvent changedEvent = createTouchDownEvent(60, 100, identity); const std::array<float, 9> rowMajor{xform[0][0], xform[1][0], xform[2][0], xform[0][1], xform[1][1], xform[2][1], xform[0][2], xform[1][2], xform[2][2]}; changedEvent.applyTransform(rowMajor); // transformContent effectively rotates the raw coordinates, so those should now include // both rotation AND offset ASSERT_EQ(720, changedEvent.getRawX(0)); ASSERT_EQ(100, changedEvent.getRawY(0)); // The transformed output should be the same then ASSERT_NEAR(event.getX(0), changedEvent.getX(0), 0.001); ASSERT_NEAR(event.getY(0), changedEvent.getY(0), 0.001); } TEST_F(MotionEventTest, RawCompatTransform) { { { // Make sure raw is raw regardless of transform translation. // Make sure raw is raw regardless of transform translation. ui::Transform xform; ui::Transform xform; Loading libs/renderengine/skia/Cache.cpp +55 −48 Original line number Original line Diff line number Diff line Loading @@ -238,9 +238,14 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { if (previousCount) { if (previousCount) { ALOGD("%d Shaders already compiled before Cache::primeShaderCache ran\n", previousCount); ALOGD("%d Shaders already compiled before Cache::primeShaderCache ran\n", previousCount); } } // The loop is beneficial for debugging and should otherwise be optimized out by the compiler. // Adding additional bounds to the loop is useful for verifying that the size of the dst buffer // does not impact the shader compilation counts by triggering different behaviors in RE/Skia. for (SkSize bounds : {SkSize::Make(128, 128), /*SkSize::Make(1080, 2340)*/}) { const nsecs_t timeBefore = systemTime(); const nsecs_t timeBefore = systemTime(); // The dimensions should not matter, so long as we draw inside them. // The dimensions should not matter, so long as we draw inside them. const Rect displayRect(0, 0, 1080, 2340); const Rect displayRect(0, 0, bounds.fWidth, bounds.fHeight); DisplaySettings display{ DisplaySettings display{ .physicalDisplay = displayRect, .physicalDisplay = displayRect, .clip = displayRect, .clip = displayRect, Loading @@ -251,18 +256,19 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { const int64_t usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; const int64_t usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; sp<GraphicBuffer> dstBuffer = sp<GraphicBuffer> dstBuffer = new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888, 1, new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888, usage, "primeShaderCache_dst"); 1, usage, "primeShaderCache_dst"); const auto dstTexture = std::make_shared<ExternalTexture>(dstBuffer, *renderengine, const auto dstTexture = std::make_shared<ExternalTexture>(dstBuffer, *renderengine, ExternalTexture::Usage::WRITEABLE); ExternalTexture::Usage::WRITEABLE); // This buffer will be the source for the call to drawImageLayers. Draw // This buffer will be the source for the call to drawImageLayers. Draw // something to it as a placeholder for what an app draws. We should draw // something to it as a placeholder for what an app draws. We should draw // something, but the details are not important. Make use of the shadow layer drawing step // something, but the details are not important. Make use of the shadow layer drawing step // to populate it. // to populate it. sp<GraphicBuffer> srcBuffer = sp<GraphicBuffer> srcBuffer = new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888, 1, new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888, usage, "drawImageLayer_src"); 1, usage, "drawImageLayer_src"); const auto srcTexture = const auto srcTexture = std::make_shared<ExternalTexture>(srcBuffer, *renderengine, std::make_shared<ExternalTexture>(srcBuffer, *renderengine, Loading @@ -279,8 +285,8 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { const int64_t usageExternal = GRALLOC_USAGE_HW_TEXTURE; const int64_t usageExternal = GRALLOC_USAGE_HW_TEXTURE; sp<GraphicBuffer> externalBuffer = sp<GraphicBuffer> externalBuffer = new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888, 1, new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888, usageExternal, "primeShaderCache_external"); 1, usageExternal, "primeShaderCache_external"); const auto externalTexture = const auto externalTexture = std::make_shared<ExternalTexture>(externalBuffer, *renderengine, std::make_shared<ExternalTexture>(externalBuffer, *renderengine, ExternalTexture::Usage::READABLE); ExternalTexture::Usage::READABLE); Loading @@ -296,5 +302,6 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { const int shadersCompiled = renderengine->reportShadersCompiled(); const int shadersCompiled = renderengine->reportShadersCompiled(); ALOGD("Shader cache generated %d shaders in %f ms\n", shadersCompiled, compileTimeMs); ALOGD("Shader cache generated %d shaders in %f ms\n", shadersCompiled, compileTimeMs); } } } } // namespace android::renderengine::skia } // namespace android::renderengine::skia Loading
include/input/Input.h +13 −1 Original line number Original line Diff line number Diff line Loading @@ -70,6 +70,14 @@ enum { */ */ AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE = 0x8, AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE = 0x8, /** * This flag indicates that the event will not cause a focus change if it is directed to an * unfocused window, even if it an ACTION_DOWN. This is typically used with pointer * gestures to allow the user to direct gestures to an unfocused window without bringing it * into focus. */ AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE = 0x40, /* Motion event is inconsistent with previously sent motion events. */ /* Motion event is inconsistent with previously sent motion events. */ AMOTION_EVENT_FLAG_TAINTED = 0x80000000, AMOTION_EVENT_FLAG_TAINTED = 0x80000000, }; }; Loading Loading @@ -746,10 +754,14 @@ public: void scale(float globalScaleFactor); void scale(float globalScaleFactor); // Apply 3x3 perspective matrix transformation. // Set 3x3 perspective matrix transformation. // Matrix is in row-major form and compatible with SkMatrix. // Matrix is in row-major form and compatible with SkMatrix. void transform(const std::array<float, 9>& matrix); void transform(const std::array<float, 9>& matrix); // Apply 3x3 perspective matrix transformation only to content (do not modify mTransform). // Matrix is in row-major form and compatible with SkMatrix. void applyTransform(const std::array<float, 9>& matrix); #ifdef __linux__ #ifdef __linux__ status_t readFromParcel(Parcel* parcel); status_t readFromParcel(Parcel* parcel); status_t writeToParcel(Parcel* parcel) const; status_t writeToParcel(Parcel* parcel) const; Loading
include/input/InputTransport.h +1 −1 Original line number Original line Diff line number Diff line Loading @@ -229,7 +229,7 @@ public: InputChannel(const InputChannel& other) InputChannel(const InputChannel& other) : mName(other.mName), mFd(::dup(other.mFd)), mToken(other.mToken){}; : mName(other.mName), mFd(::dup(other.mFd)), mToken(other.mToken){}; InputChannel(const std::string name, android::base::unique_fd fd, sp<IBinder> token); InputChannel(const std::string name, android::base::unique_fd fd, sp<IBinder> token); virtual ~InputChannel(); ~InputChannel() override; /** /** * Create a pair of input channels. * Create a pair of input channels. * The two returned input channels are equivalent, and are labeled as "server" and "client" * The two returned input channels are equivalent, and are labeled as "server" and "client" Loading
libs/input/Input.cpp +18 −0 Original line number Original line Diff line number Diff line Loading @@ -569,6 +569,24 @@ void MotionEvent::transform(const std::array<float, 9>& matrix) { } } } } void MotionEvent::applyTransform(const std::array<float, 9>& matrix) { // Determine how the origin is transformed by the matrix so that we // can transform orientation vectors. vec2 origin = transformPoint(matrix, 0, 0); // Apply the transformation to all samples. size_t numSamples = mSamplePointerCoords.size(); for (size_t i = 0; i < numSamples; i++) { PointerCoords& c = mSamplePointerCoords.editItemAt(i); float orientation = c.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION); c.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, transformAngle(matrix, orientation, origin.x, origin.y)); vec2 xy = transformPoint(matrix, c.getX(), c.getY()); c.setAxisValue(AMOTION_EVENT_AXIS_X, xy.x); c.setAxisValue(AMOTION_EVENT_AXIS_Y, xy.y); } } #ifdef __linux__ #ifdef __linux__ static status_t readFromParcel(ui::Transform& transform, const Parcel& parcel) { static status_t readFromParcel(ui::Transform& transform, const Parcel& parcel) { float dsdx, dtdx, tx, dtdy, dsdy, ty; float dsdx, dtdx, tx, dtdy, dsdy, ty; Loading
libs/input/tests/InputEvent_test.cpp +47 −21 Original line number Original line Diff line number Diff line Loading @@ -636,8 +636,7 @@ TEST_F(MotionEventTest, Transform) { ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001); ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001); } } TEST_F(MotionEventTest, RawCompatTransform) { MotionEvent createTouchDownEvent(int x, int y, ui::Transform transform) { auto createTouchDownEvent = [](int x, int y, ui::Transform transform) { std::vector<PointerProperties> pointerProperties; std::vector<PointerProperties> pointerProperties; pointerProperties.push_back(PointerProperties{/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER}); pointerProperties.push_back(PointerProperties{/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER}); std::vector<PointerCoords> pointerCoords; std::vector<PointerCoords> pointerCoords; Loading @@ -650,14 +649,41 @@ TEST_F(MotionEventTest, RawCompatTransform) { /* displayId */ 0, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, /* displayId */ 0, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, /* actionButton */ 0, /* flags */ 0, /* edgeFlags */ 0, AMETA_NONE, /* actionButton */ 0, /* flags */ 0, /* edgeFlags */ 0, AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE, transform, /* buttonState */ 0, MotionClassification::NONE, transform, /* xPrecision */ 0, /* yPrecision */ 0, /* xPrecision */ 0, /* yPrecision */ 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, /* displayWidth */ 400, AMOTION_EVENT_INVALID_CURSOR_POSITION, /* displayWidth */ 400, /* displayHeight */ 800, eventTime, eventTime, pointerCoords.size(), /* displayHeight */ 800, eventTime, eventTime, pointerCoords.size(), pointerProperties.data(), pointerCoords.data()); pointerProperties.data(), pointerCoords.data()); return event; return event; }; } TEST_F(MotionEventTest, ApplyTransform) { // Create a rotate-90 transform with an offset (like a window which isn't fullscreen). ui::Transform identity; ui::Transform xform(ui::Transform::ROT_90, 800, 400); xform.set(xform.tx() + 20, xform.ty() + 40); MotionEvent event = createTouchDownEvent(60, 100, xform); ASSERT_EQ(700, event.getRawX(0)); ASSERT_EQ(60, event.getRawY(0)); ASSERT_NE(event.getRawX(0), event.getX(0)); ASSERT_NE(event.getRawY(0), event.getY(0)); MotionEvent changedEvent = createTouchDownEvent(60, 100, identity); const std::array<float, 9> rowMajor{xform[0][0], xform[1][0], xform[2][0], xform[0][1], xform[1][1], xform[2][1], xform[0][2], xform[1][2], xform[2][2]}; changedEvent.applyTransform(rowMajor); // transformContent effectively rotates the raw coordinates, so those should now include // both rotation AND offset ASSERT_EQ(720, changedEvent.getRawX(0)); ASSERT_EQ(100, changedEvent.getRawY(0)); // The transformed output should be the same then ASSERT_NEAR(event.getX(0), changedEvent.getX(0), 0.001); ASSERT_NEAR(event.getY(0), changedEvent.getY(0), 0.001); } TEST_F(MotionEventTest, RawCompatTransform) { { { // Make sure raw is raw regardless of transform translation. // Make sure raw is raw regardless of transform translation. ui::Transform xform; ui::Transform xform; Loading
libs/renderengine/skia/Cache.cpp +55 −48 Original line number Original line Diff line number Diff line Loading @@ -238,9 +238,14 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { if (previousCount) { if (previousCount) { ALOGD("%d Shaders already compiled before Cache::primeShaderCache ran\n", previousCount); ALOGD("%d Shaders already compiled before Cache::primeShaderCache ran\n", previousCount); } } // The loop is beneficial for debugging and should otherwise be optimized out by the compiler. // Adding additional bounds to the loop is useful for verifying that the size of the dst buffer // does not impact the shader compilation counts by triggering different behaviors in RE/Skia. for (SkSize bounds : {SkSize::Make(128, 128), /*SkSize::Make(1080, 2340)*/}) { const nsecs_t timeBefore = systemTime(); const nsecs_t timeBefore = systemTime(); // The dimensions should not matter, so long as we draw inside them. // The dimensions should not matter, so long as we draw inside them. const Rect displayRect(0, 0, 1080, 2340); const Rect displayRect(0, 0, bounds.fWidth, bounds.fHeight); DisplaySettings display{ DisplaySettings display{ .physicalDisplay = displayRect, .physicalDisplay = displayRect, .clip = displayRect, .clip = displayRect, Loading @@ -251,18 +256,19 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { const int64_t usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; const int64_t usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; sp<GraphicBuffer> dstBuffer = sp<GraphicBuffer> dstBuffer = new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888, 1, new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888, usage, "primeShaderCache_dst"); 1, usage, "primeShaderCache_dst"); const auto dstTexture = std::make_shared<ExternalTexture>(dstBuffer, *renderengine, const auto dstTexture = std::make_shared<ExternalTexture>(dstBuffer, *renderengine, ExternalTexture::Usage::WRITEABLE); ExternalTexture::Usage::WRITEABLE); // This buffer will be the source for the call to drawImageLayers. Draw // This buffer will be the source for the call to drawImageLayers. Draw // something to it as a placeholder for what an app draws. We should draw // something to it as a placeholder for what an app draws. We should draw // something, but the details are not important. Make use of the shadow layer drawing step // something, but the details are not important. Make use of the shadow layer drawing step // to populate it. // to populate it. sp<GraphicBuffer> srcBuffer = sp<GraphicBuffer> srcBuffer = new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888, 1, new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888, usage, "drawImageLayer_src"); 1, usage, "drawImageLayer_src"); const auto srcTexture = const auto srcTexture = std::make_shared<ExternalTexture>(srcBuffer, *renderengine, std::make_shared<ExternalTexture>(srcBuffer, *renderengine, Loading @@ -279,8 +285,8 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { const int64_t usageExternal = GRALLOC_USAGE_HW_TEXTURE; const int64_t usageExternal = GRALLOC_USAGE_HW_TEXTURE; sp<GraphicBuffer> externalBuffer = sp<GraphicBuffer> externalBuffer = new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888, 1, new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888, usageExternal, "primeShaderCache_external"); 1, usageExternal, "primeShaderCache_external"); const auto externalTexture = const auto externalTexture = std::make_shared<ExternalTexture>(externalBuffer, *renderengine, std::make_shared<ExternalTexture>(externalBuffer, *renderengine, ExternalTexture::Usage::READABLE); ExternalTexture::Usage::READABLE); Loading @@ -296,5 +302,6 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { const int shadersCompiled = renderengine->reportShadersCompiled(); const int shadersCompiled = renderengine->reportShadersCompiled(); ALOGD("Shader cache generated %d shaders in %f ms\n", shadersCompiled, compileTimeMs); ALOGD("Shader cache generated %d shaders in %f ms\n", shadersCompiled, compileTimeMs); } } } } // namespace android::renderengine::skia } // namespace android::renderengine::skia