static void Bitmap_prepareToDraw(JNIEnv* env, jobject, jlong bitmapPtr) {
LocalScopedBitmap bitmapHandle(bitmapPtr);
if (!bitmapHandle.valid()) return;
- SkBitmap bitmap;
- bitmapHandle->getSkBitmap(&bitmap);
- android::uirenderer::renderthread::RenderProxy::prepareToDraw(bitmap);
+ android::uirenderer::renderthread::RenderProxy::prepareToDraw(bitmapHandle->bitmap());
}
static jint Bitmap_getAllocationByteCount(JNIEnv* env, jobject, jlong bitmapPtr) {
const MergedBakedOpList& opList) {
const BakedOpState& firstState = *(opList.states[0]);
- const SkBitmap* bitmap = (static_cast<const BitmapOp*>(opList.states[0]->op))->bitmap;
+ Bitmap* bitmap = (static_cast<const BitmapOp*>(opList.states[0]->op))->bitmap;
Texture* texture = renderer.caches().textureCache.get(bitmap);
if (!texture) return;
if (!mRenderTarget.frameBufferId) mHasDrawn = true;
}
-Texture* BakedOpRenderer::getTexture(const SkBitmap* bitmap) {
+Texture* BakedOpRenderer::getTexture(Bitmap* bitmap) {
return mCaches.textureCache.get(bitmap);
}
void endLayer();
WARN_UNUSED_RESULT OffscreenBuffer* copyToLayer(const Rect& area);
- Texture* getTexture(const SkBitmap* bitmap);
+ Texture* getTexture(Bitmap* bitmap);
const LightInfo& getLightInfo() const { return mLightInfo; }
void renderGlop(const BakedOpState& state, const Glop& glop) {
bool DisplayList::prepareListAndChildren(TreeInfo& info, bool functorsNeedLayer,
std::function<void(RenderNode*, TreeInfo&, bool)> childFn) {
TextureCache& cache = Caches::getInstance().textureCache;
- for (auto&& bitmapResource : bitmapResources) {
+ for (auto& bitmapResource : bitmapResources) {
void* ownerToken = &info.canvasContext;
- info.prepareTextures = cache.prefetchAndMarkInUse(ownerToken, bitmapResource);
+ info.prepareTextures = cache.prefetchAndMarkInUse(ownerToken, bitmapResource.get());
}
for (auto&& op : children) {
RenderNode* childNode = op->renderNode;
#include "Matrix.h"
#include "RenderProperties.h"
#include "TreeInfo.h"
+#include "hwui/Bitmap.h"
#include <vector>
const LsaVector<NodeOpType*>& getChildren() const { return children; }
- const LsaVector<const SkBitmap*>& getBitmapResources() const { return bitmapResources; }
+ const LsaVector<sk_sp<Bitmap>>& getBitmapResources() const { return bitmapResources; }
size_t addChild(NodeOpType* childOp);
LsaVector<NodeOpType*> children;
// Resources - Skia objects + 9 patches referred to by this DisplayList
- LsaVector<const SkBitmap*> bitmapResources;
+ LsaVector<sk_sp<Bitmap>> bitmapResources;
LsaVector<const SkPath*> pathResources;
LsaVector<const Res_png_9patch*> patchResources;
LsaVector<std::unique_ptr<const SkPaint>> paints;
}
void FrameBuilder::deferVectorDrawableOp(const VectorDrawableOp& op) {
- SkBitmap bitmap;
- op.vectorDrawable->getBitmapUpdateIfDirty().getSkBitmap(&bitmap);
- SkBitmap* localBitmap = mAllocator.create<SkBitmap>(bitmap);
+ Bitmap& bitmap = op.vectorDrawable->getBitmapUpdateIfDirty();
SkPaint* paint = op.vectorDrawable->getPaint();
const BitmapRectOp* resolvedOp = mAllocator.create_trivial<BitmapRectOp>(op.unmappedBounds,
op.localMatrix,
op.localClip,
paint,
- localBitmap,
+ &bitmap,
Rect(bitmap.width(), bitmap.height()));
deferBitmapRectOp(*resolvedOp);
}
};
struct BitmapOp : RecordedOp {
- BitmapOp(BASE_PARAMS, const SkBitmap* bitmap)
+ BitmapOp(BASE_PARAMS, Bitmap* bitmap)
: SUPER(BitmapOp)
, bitmap(bitmap) {}
- const SkBitmap* bitmap;
+ Bitmap* bitmap;
};
struct BitmapMeshOp : RecordedOp {
- BitmapMeshOp(BASE_PARAMS, const SkBitmap* bitmap, int meshWidth, int meshHeight,
+ BitmapMeshOp(BASE_PARAMS, Bitmap* bitmap, int meshWidth, int meshHeight,
const float* vertices, const int* colors)
: SUPER(BitmapMeshOp)
, bitmap(bitmap)
, meshHeight(meshHeight)
, vertices(vertices)
, colors(colors) {}
- const SkBitmap* bitmap;
+ Bitmap* bitmap;
const int meshWidth;
const int meshHeight;
const float* vertices;
};
struct BitmapRectOp : RecordedOp {
- BitmapRectOp(BASE_PARAMS, const SkBitmap* bitmap, const Rect& src)
+ BitmapRectOp(BASE_PARAMS, Bitmap* bitmap, const Rect& src)
: SUPER(BitmapRectOp)
, bitmap(bitmap)
, src(src) {}
- const SkBitmap* bitmap;
+ Bitmap* bitmap;
const Rect src;
};
};
struct PatchOp : RecordedOp {
- PatchOp(BASE_PARAMS, const SkBitmap* bitmap, const Res_png_9patch* patch)
+ PatchOp(BASE_PARAMS, Bitmap* bitmap, const Res_png_9patch* patch)
: SUPER(PatchOp)
, bitmap(bitmap)
, patch(patch) {}
- const SkBitmap* bitmap;
+ Bitmap* bitmap;
const Res_png_9patch* patch;
};
#include "RenderNode.h"
#include "VectorDrawable.h"
#include "hwui/MinikinUtils.h"
-#include "hwui/Bitmap.h"
namespace android {
namespace uirenderer {
// Bitmap-based
void RecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) {
- SkBitmap skBitmap;
- bitmap.getSkBitmap(&skBitmap);
save(SaveFlags::Matrix);
translate(left, top);
- drawBitmap(&skBitmap, paint);
+ drawBitmap(bitmap, paint);
restore();
}
-void RecordingCanvas::drawBitmap(Bitmap& hwuiBitmap, const SkMatrix& matrix,
+void RecordingCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix,
const SkPaint* paint) {
- SkBitmap bitmap;
- hwuiBitmap.getSkBitmap(&bitmap);
if (matrix.isIdentity()) {
- drawBitmap(&bitmap, paint);
+ drawBitmap(bitmap, paint);
} else if (!(matrix.getType() & ~(SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask))
&& MathUtils::isPositive(matrix.getScaleX())
&& MathUtils::isPositive(matrix.getScaleY())) {
SkRect dst;
bitmap.getBounds(&src);
matrix.mapRect(&dst, src);
- drawBitmap(hwuiBitmap, src.fLeft, src.fTop, src.fRight, src.fBottom,
+ drawBitmap(bitmap, src.fLeft, src.fTop, src.fRight, src.fBottom,
dst.fLeft, dst.fTop, dst.fRight, dst.fBottom, paint);
} else {
save(SaveFlags::Matrix);
concat(matrix);
- drawBitmap(&bitmap, paint);
+ drawBitmap(bitmap, paint);
restore();
}
}
-void RecordingCanvas::drawBitmap(Bitmap& hwuiBitmap, float srcLeft, float srcTop,
+void RecordingCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop,
float srcRight, float srcBottom, float dstLeft, float dstTop,
float dstRight, float dstBottom, const SkPaint* paint) {
- SkBitmap bitmap;
- hwuiBitmap.getSkBitmap(&bitmap);
if (srcLeft == 0 && srcTop == 0
&& srcRight == bitmap.width()
&& srcBottom == bitmap.height()
// transform simple rect to rect drawing case into position bitmap ops, since they merge
save(SaveFlags::Matrix);
translate(dstLeft, dstTop);
- drawBitmap(&bitmap, paint);
+ drawBitmap(bitmap, paint);
restore();
} else {
addOp(alloc().create_trivial<BitmapRectOp>(
}
}
-void RecordingCanvas::drawBitmapMesh(Bitmap& hwuiBitmap, int meshWidth, int meshHeight,
+void RecordingCanvas::drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight,
const float* vertices, const int* colors, const SkPaint* paint) {
- SkBitmap bitmap;
- hwuiBitmap.getSkBitmap(&bitmap);
int vertexCount = (meshWidth + 1) * (meshHeight + 1);
addOp(alloc().create_trivial<BitmapMeshOp>(
calcBoundsOfPoints(vertices, vertexCount * 2),
refBuffer<int>(colors, vertexCount))); // 1 color per vertex
}
-void RecordingCanvas::drawNinePatch(Bitmap& hwuiBitmap, const android::Res_png_9patch& patch,
+void RecordingCanvas::drawNinePatch(Bitmap& bitmap, const android::Res_png_9patch& patch,
float dstLeft, float dstTop, float dstRight, float dstBottom,
const SkPaint* paint) {
- SkBitmap bitmap;
- hwuiBitmap.getSkBitmap(&bitmap);
addOp(alloc().create_trivial<PatchOp>(
Rect(dstLeft, dstTop, dstRight, dstBottom),
*(mState.currentSnapshot()->transform),
}
}
-void RecordingCanvas::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
+void RecordingCanvas::drawBitmap(Bitmap& bitmap, const SkPaint* paint) {
addOp(alloc().create_trivial<BitmapOp>(
- Rect(bitmap->width(), bitmap->height()),
+ Rect(bitmap.width(), bitmap.height()),
*(mState.currentSnapshot()->transform),
getRecordedClip(),
- refPaint(paint), refBitmap(*bitmap)));
+ refPaint(paint), refBitmap(bitmap)));
}
void RecordingCanvas::drawRenderNode(RenderNode* renderNode) {
SkBitmap bitmap;
SkShader::TileMode xy[2];
if (shader->isABitmap(&bitmap, nullptr, xy)) {
- refBitmap(bitmap);
+ // TODO: create hwui-owned BitmapShader.
+ Bitmap* hwuiBitmap = static_cast<Bitmap*>(bitmap.pixelRef());
+ refBitmap(*hwuiBitmap);
return;
}
SkShader::ComposeRec rec;
#include "ResourceCache.h"
#include "SkiaCanvasProxy.h"
#include "Snapshot.h"
+#include "hwui/Bitmap.h"
#include "hwui/Canvas.h"
#include "utils/LinearAllocator.h"
#include "utils/Macros.h"
return mState.writableSnapshot()->mutateClipArea().serializeClip(alloc());
}
- void drawBitmap(const SkBitmap* bitmap, const SkPaint* paint);
+ void drawBitmap(Bitmap& bitmap, const SkPaint* paint);
void drawSimpleRects(const float* rects, int vertexCount, const SkPaint* paint);
return cachedRegion;
}
- inline const SkBitmap* refBitmap(const SkBitmap& bitmap) {
+ inline Bitmap* refBitmap(Bitmap& bitmap) {
// Note that this assumes the bitmap is immutable. There are cases this won't handle
// correctly, such as creating the bitmap from scratch, drawing with it, changing its
// contents, and drawing again. The only fix would be to always copy it the first time,
// which doesn't seem worth the extra cycles for this unlikely case.
- SkBitmap* localBitmap = alloc().create<SkBitmap>(bitmap);
- mDisplayList->bitmapResources.push_back(localBitmap);
- return localBitmap;
+
+ // this is required because sk_sp's ctor adopts the pointer,
+ // but does not increment the refcount,
+ bitmap.ref();
+ mDisplayList->bitmapResources.emplace_back(&bitmap);
+ return &bitmap;
}
inline const Res_png_9patch* refPatch(const Res_png_9patch* patch) {
#include "Layer.h"
#include "Matrix.h"
#include "Texture.h"
+#include "hwui/Bitmap.h"
#include <SkMatrix.h>
#include <utils/Log.h>
return false;
}
- outData->bitmapTexture = caches.textureCache.get(&bitmap);
+ // TODO: create hwui-owned BitmapShader.
+ Bitmap* hwuiBitmap = static_cast<Bitmap*>(bitmap.pixelRef());
+ outData->bitmapTexture = caches.textureCache.get(hwuiBitmap);
if (!outData->bitmapTexture) return false;
outData->bitmapSampler = (*textureUnit)++;
#include "TextureCache.h"
#include "Properties.h"
#include "utils/TraceUtils.h"
+#include "hwui/Bitmap.h"
namespace android {
namespace uirenderer {
}
}
-bool TextureCache::canMakeTextureFromBitmap(const SkBitmap* bitmap) {
+bool TextureCache::canMakeTextureFromBitmap(Bitmap* bitmap) {
if (bitmap->width() > mMaxTextureSize || bitmap->height() > mMaxTextureSize) {
ALOGW("Bitmap too large to be uploaded into a texture (%dx%d, max=%dx%d)",
bitmap->width(), bitmap->height(), mMaxTextureSize, mMaxTextureSize);
// Returns a prepared Texture* that either is already in the cache or can fit
// in the cache (and is thus added to the cache)
-Texture* TextureCache::getCachedTexture(const SkBitmap* bitmap) {
- Texture* texture = mCache.get(bitmap->pixelRef()->getStableID());
+Texture* TextureCache::getCachedTexture(Bitmap* bitmap) {
+ Texture* texture = mCache.get(bitmap->getStableID());
if (!texture) {
if (!canMakeTextureFromBitmap(bitmap)) {
texture = new Texture(Caches::getInstance());
texture->bitmapSize = size;
texture->generation = bitmap->getGenerationID();
- texture->upload(*bitmap);
+ SkBitmap skBitmap;
+ bitmap->getSkBitmap(&skBitmap);
+ texture->upload(skBitmap);
mSize += size;
TEXTURE_LOGD("TextureCache::get: create texture(%p): name, size, mSize = %d, %d, %d",
if (mDebugEnabled) {
ALOGD("Texture created, size = %d", size);
}
- mCache.put(bitmap->pixelRef()->getStableID(), texture);
+ mCache.put(bitmap->getStableID(), texture);
}
} else if (!texture->isInUse && bitmap->getGenerationID() != texture->generation) {
// Texture was in the cache but is dirty, re-upload
// TODO: Re-adjust the cache size if the bitmap's dimensions have changed
- texture->upload(*bitmap);
+ SkBitmap skBitmap;
+ bitmap->getSkBitmap(&skBitmap);
+ texture->upload(skBitmap);
texture->generation = bitmap->getGenerationID();
}
return texture;
}
-bool TextureCache::prefetchAndMarkInUse(void* ownerToken, const SkBitmap* bitmap) {
+bool TextureCache::prefetchAndMarkInUse(void* ownerToken, Bitmap* bitmap) {
Texture* texture = getCachedTexture(bitmap);
if (texture) {
texture->isInUse = ownerToken;
return texture;
}
-bool TextureCache::prefetch(const SkBitmap* bitmap) {
+bool TextureCache::prefetch(Bitmap* bitmap) {
return getCachedTexture(bitmap);
}
-Texture* TextureCache::get(const SkBitmap* bitmap) {
+Texture* TextureCache::get(Bitmap* bitmap) {
Texture* texture = getCachedTexture(bitmap);
if (!texture) {
const uint32_t size = bitmap->rowBytes() * bitmap->height();
texture = new Texture(Caches::getInstance());
texture->bitmapSize = size;
- texture->upload(*bitmap);
+ SkBitmap skBitmap;
+ bitmap->getSkBitmap(&skBitmap);
+ texture->upload(skBitmap);
texture->generation = bitmap->getGenerationID();
texture->cleanup = true;
}
#include <unordered_map>
namespace android {
+
+class Bitmap;
+
namespace uirenderer {
class Texture;
* acquired for the bitmap, false otherwise. If a Texture was acquired it is
* marked as in use.
*/
- bool prefetchAndMarkInUse(void* ownerToken, const SkBitmap* bitmap);
+ bool prefetchAndMarkInUse(void* ownerToken, Bitmap* bitmap);
/**
* Attempts to precache the SkBitmap. Returns true if a Texture was successfully
* acquired for the bitmap, false otherwise. Does not mark the Texture
* as in use and won't update currently in-use Textures.
*/
- bool prefetch(const SkBitmap* bitmap);
+ bool prefetch(Bitmap* bitmap);
/**
* Returns the texture associated with the specified bitmap from within the cache.
* If the texture cannot be found in the cache, a new texture is generated.
*/
- Texture* get(const SkBitmap* bitmap);
+ Texture* get(Bitmap* bitmap);
/**
* Removes the texture associated with the specified pixelRef. This is meant
void flush();
private:
- bool canMakeTextureFromBitmap(const SkBitmap* bitmap);
+ bool canMakeTextureFromBitmap(Bitmap* bitmap);
- Texture* getCachedTexture(const SkBitmap* bitmap);
+ Texture* getCachedTexture(Bitmap* bitmap);
LruCache<uint32_t, Texture*> mCache;
outBitmap->setHasHardwareMipMap(mHasHardwareMipMap);
}
+void Bitmap::getBounds(SkRect* bounds) const {
+ SkASSERT(bounds);
+ bounds->set(0, 0, SkIntToScalar(info().width()), SkIntToScalar(info().height()));
+}
+
} // namespace android
\ No newline at end of file
void setHasHardwareMipMap(bool hasMipMap);
bool hasHardwareMipMap() const;
+ bool isOpaque() const {return info().isOpaque(); }
+ SkColorType colorType() const { return info().colorType(); }
+ void getBounds(SkRect* bounds) const;
+
protected:
virtual bool onNewLockPixels(LockRec* rec) override;
virtual void onUnlockPixels() override { };
reinterpret_cast<intptr_t>( staticPostAndWait(task) ));
}
-CREATE_BRIDGE2(prepareToDraw, RenderThread* thread, SkBitmap* bitmap) {
+CREATE_BRIDGE2(prepareToDraw, RenderThread* thread, Bitmap* bitmap) {
if (Caches::hasInstance() && args->thread->eglManager().hasEglContext()) {
ATRACE_NAME("Bitmap#prepareToDraw task");
Caches::getInstance().textureCache.prefetch(args->bitmap);
}
- delete args->bitmap;
+ args->bitmap->unref();
args->bitmap = nullptr;
return nullptr;
}
-void RenderProxy::prepareToDraw(const SkBitmap& bitmap) {
+void RenderProxy::prepareToDraw(Bitmap& bitmap) {
// If we haven't spun up a hardware accelerated window yet, there's no
// point in precaching these bitmaps as it can't impact jank.
// We also don't know if we even will spin up a hardware-accelerated
RenderThread* renderThread = &RenderThread::getInstance();
SETUP_TASK(prepareToDraw);
args->thread = renderThread;
- args->bitmap = new SkBitmap(bitmap);
+ bitmap.ref();
+ args->bitmap = &bitmap;
nsecs_t lastVsync = renderThread->timeLord().latestVsync();
nsecs_t estimatedNextVsync = lastVsync + renderThread->timeLord().frameIntervalNanos();
nsecs_t timeToNextVsync = estimatedNextVsync - systemTime(CLOCK_MONOTONIC);
ANDROID_API static int copySurfaceInto(sp<Surface>& surface,
int left, int top, int right, int bottom, SkBitmap* bitmap);
- ANDROID_API static void prepareToDraw(const SkBitmap& bitmap);
+ ANDROID_API static void prepareToDraw(Bitmap& bitmap);
private:
RenderThread& mRenderThread;
return Bitmap::allocateHeapBitmap(outBitmap, nullptr);
}
- static SkBitmap createSkBitmap(int width, int height,
- SkColorType colorType = kN32_SkColorType) {
- SkBitmap bitmap;
- sk_sp<SkColorSpace> colorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
- SkImageInfo info = SkImageInfo::Make(width, height,
- colorType, kPremul_SkAlphaType, colorSpace);
- bitmap.setInfo(info);
- Bitmap::allocateHeapBitmap(&bitmap, nullptr);
- return bitmap;
- }
-
static sp<DeferredLayerUpdater> createTextureLayerUpdater(
renderthread::RenderThread& renderThread, uint32_t width, uint32_t height,
const SkMatrix& transform);
void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
switch(mIndex++) {
case 0:
- EXPECT_EQ(opaqueBitmap.get(), op.bitmap->pixelRef());
+ EXPECT_EQ(opaqueBitmap.get(), op.bitmap);
break;
case 1:
- EXPECT_EQ(transpBitmap.get(), op.bitmap->pixelRef());
+ EXPECT_EQ(transpBitmap.get(), op.bitmap);
break;
default:
ADD_FAILURE() << "Only two ops expected.";
}
TEST(RecordingCanvas, refBitmapInShader_bitmapShader) {
- SkBitmap bitmap = TestUtils::createSkBitmap(100, 100);
+ sk_sp<Bitmap> bitmap = TestUtils::createBitmap(100, 100);
auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [&bitmap](RecordingCanvas& canvas) {
SkPaint paint;
- sk_sp<SkShader> shader = SkMakeBitmapShader(bitmap,
+ SkBitmap skBitmap;
+ bitmap->getSkBitmap(&skBitmap);
+ sk_sp<SkShader> shader = SkMakeBitmapShader(skBitmap,
SkShader::TileMode::kClamp_TileMode,
SkShader::TileMode::kClamp_TileMode,
nullptr,
}
TEST(RecordingCanvas, refBitmapInShader_composeShader) {
- SkBitmap bitmap = TestUtils::createSkBitmap(100, 100);
+ sk_sp<Bitmap> bitmap = TestUtils::createBitmap(100, 100);
auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [&bitmap](RecordingCanvas& canvas) {
SkPaint paint;
- sk_sp<SkShader> shader1 = SkMakeBitmapShader(bitmap,
+ SkBitmap skBitmap;
+ bitmap->getSkBitmap(&skBitmap);
+ sk_sp<SkShader> shader1 = SkMakeBitmapShader(skBitmap,
SkShader::TileMode::kClamp_TileMode,
SkShader::TileMode::kClamp_TileMode,
nullptr,