blob: 3876f17411d8067a41f362ced42f245fc98760f0 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
reed@google.comac10a2d2010-12-22 21:39:39 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2010 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
reed@google.comac10a2d2010-12-22 21:39:39 +00007 */
8
9
epoger@google.comec3ed6a2011-07-28 14:26:00 +000010
robertphillips@google.com5088eb42012-06-28 20:59:13 +000011#include "SkGrPixelRef.h"
piotaixr0e977052014-09-17 16:24:04 -070012
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +000013#include "GrContext.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000014#include "GrTexture.h"
junovda5469d2015-06-15 09:48:15 -070015#include "GrTexturePriv.h"
piotaixr0e977052014-09-17 16:24:04 -070016#include "SkBitmapCache.h"
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +000017#include "SkGr.h"
bsalomon@google.com669fdc42011-04-05 17:08:27 +000018#include "SkRect.h"
reed@google.com9c49bc32011-07-07 13:42:37 +000019
reed@google.combf790232013-12-13 19:45:58 +000020SkROLockPixelsPixelRef::SkROLockPixelsPixelRef(const SkImageInfo& info)
mtklein7e6d9c02015-08-13 14:02:06 -070021 : INHERITED(info) {}
reed@google.com9c49bc32011-07-07 13:42:37 +000022
reed@google.combf790232013-12-13 19:45:58 +000023SkROLockPixelsPixelRef::~SkROLockPixelsPixelRef() {}
reed@google.com9c49bc32011-07-07 13:42:37 +000024
reed@google.comd0419b12014-01-06 17:08:27 +000025bool SkROLockPixelsPixelRef::onNewLockPixels(LockRec* rec) {
reed@google.com9c49bc32011-07-07 13:42:37 +000026 fBitmap.reset();
27// SkDebugf("---------- calling readpixels in support of lockpixels\n");
bsalomon9d22fd62016-01-11 11:14:17 -080028 if (!this->onReadPixels(&fBitmap, this->info().colorType(), nullptr)) {
reed@google.com9c49bc32011-07-07 13:42:37 +000029 SkDebugf("SkROLockPixelsPixelRef::onLockPixels failed!\n");
reed@google.comd0419b12014-01-06 17:08:27 +000030 return false;
reed@google.com9c49bc32011-07-07 13:42:37 +000031 }
32 fBitmap.lockPixels();
halcanary96fcdcc2015-08-27 07:41:13 -070033 if (nullptr == fBitmap.getPixels()) {
reed@google.comd0419b12014-01-06 17:08:27 +000034 return false;
35 }
36
37 rec->fPixels = fBitmap.getPixels();
halcanary96fcdcc2015-08-27 07:41:13 -070038 rec->fColorTable = nullptr;
reed@google.comd0419b12014-01-06 17:08:27 +000039 rec->fRowBytes = fBitmap.rowBytes();
40 return true;
reed@google.com9c49bc32011-07-07 13:42:37 +000041}
42
43void SkROLockPixelsPixelRef::onUnlockPixels() {
44 fBitmap.unlockPixels();
45}
46
47bool SkROLockPixelsPixelRef::onLockPixelsAreWritable() const {
48 return false;
49}
50
51///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com669fdc42011-04-05 17:08:27 +000052
junov96c118e2014-09-26 13:09:47 -070053static SkGrPixelRef* copy_to_new_texture_pixelref(GrTexture* texture, SkColorType dstCT,
jvanverthfa1e8a72014-12-22 08:31:49 -080054 SkColorProfileType dstPT, const SkIRect* subset) {
halcanary96fcdcc2015-08-27 07:41:13 -070055 if (nullptr == texture || kUnknown_SkColorType == dstCT) {
56 return nullptr;
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +000057 }
58 GrContext* context = texture->getContext();
halcanary96fcdcc2015-08-27 07:41:13 -070059 if (nullptr == context) {
60 return nullptr;
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +000061 }
bsalomonf2703d82014-10-28 14:33:06 -070062 GrSurfaceDesc desc;
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +000063
bsalomonf80bfed2014-10-07 05:56:02 -070064 SkIRect srcRect;
65
66 if (!subset) {
67 desc.fWidth = texture->width();
68 desc.fHeight = texture->height();
69 srcRect = SkIRect::MakeWH(texture->width(), texture->height());
70 } else {
scroggo@google.coma2a31922012-12-07 19:14:45 +000071 SkASSERT(SkIRect::MakeWH(texture->width(), texture->height()).contains(*subset));
72 // Create a new texture that is the size of subset.
73 desc.fWidth = subset->width();
74 desc.fHeight = subset->height();
bsalomonf80bfed2014-10-07 05:56:02 -070075 srcRect = *subset;
scroggo@google.coma2a31922012-12-07 19:14:45 +000076 }
bsalomon6bc1b5f2015-02-23 09:06:38 -080077 desc.fFlags = kRenderTarget_GrSurfaceFlag;
jvanverthfa1e8a72014-12-22 08:31:49 -080078 desc.fConfig = SkImageInfo2GrPixelConfig(dstCT, kPremul_SkAlphaType, dstPT);
erikchen7fec91c2016-02-05 12:10:55 -080079 desc.fTextureStorageAllocator = texture->desc().fTextureStorageAllocator;
skia.committer@gmail.com96f5fa02013-12-16 07:01:40 +000080
halcanary96fcdcc2015-08-27 07:41:13 -070081 GrTexture* dst = context->textureProvider()->createTexture(desc, false, nullptr, 0);
82 if (nullptr == dst) {
83 return nullptr;
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +000084 }
85
junov96c118e2014-09-26 13:09:47 -070086 // Blink is relying on the above copy being sent to GL immediately in the case when the source
bsalomonf80bfed2014-10-07 05:56:02 -070087 // is a WebGL canvas backing store. We could have a TODO to remove this flush flag, but we have
88 // a larger TODO to remove SkGrPixelRef entirely.
89 context->copySurface(dst->asRenderTarget(), texture, srcRect, SkIPoint::Make(0,0),
90 GrContext::kFlushWrites_PixelOp);
mtklein7e6d9c02015-08-13 14:02:06 -070091
jvanverthfa1e8a72014-12-22 08:31:49 -080092 SkImageInfo info = SkImageInfo::Make(desc.fWidth, desc.fHeight, dstCT, kPremul_SkAlphaType,
93 dstPT);
halcanary385fe4d2015-08-26 13:07:48 -070094 SkGrPixelRef* pixelRef = new SkGrPixelRef(info, dst);
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +000095 SkSafeUnref(dst);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +000096 return pixelRef;
97}
98
99///////////////////////////////////////////////////////////////////////////////
100
bsalomonbcf0a522014-10-08 08:40:09 -0700101SkGrPixelRef::SkGrPixelRef(const SkImageInfo& info, GrSurface* surface) : INHERITED(info) {
bsalomon71875932014-08-29 08:08:35 -0700102 // For surfaces that are both textures and render targets, the texture owns the
103 // render target but not vice versa. So we ref the texture to keep both alive for
104 // the lifetime of this pixel ref.
105 fSurface = SkSafeRef(surface->asTexture());
halcanary96fcdcc2015-08-27 07:41:13 -0700106 if (nullptr == fSurface) {
bsalomon71875932014-08-29 08:08:35 -0700107 fSurface = SkSafeRef(surface);
reed@google.com61867872013-12-09 13:41:06 +0000108 }
commit-bot@chromium.org8e0993d2014-01-28 15:16:45 +0000109
110 if (fSurface) {
reede5ea5002014-09-03 11:54:58 -0700111 SkASSERT(info.width() <= fSurface->width());
112 SkASSERT(info.height() <= fSurface->height());
commit-bot@chromium.org8e0993d2014-01-28 15:16:45 +0000113 }
reed@google.com61867872013-12-09 13:41:06 +0000114}
115
robertphillips@google.comd881bc12012-06-28 20:02:39 +0000116SkGrPixelRef::~SkGrPixelRef() {
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +0000117 SkSafeUnref(fSurface);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000118}
119
commit-bot@chromium.orgb8d00db2013-06-26 19:18:23 +0000120GrTexture* SkGrPixelRef::getTexture() {
bsalomon49f085d2014-09-05 13:34:00 -0700121 if (fSurface) {
commit-bot@chromium.orgb8d00db2013-06-26 19:18:23 +0000122 return fSurface->asTexture();
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000123 }
halcanary96fcdcc2015-08-27 07:41:13 -0700124 return nullptr;
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000125}
126
junovda5469d2015-06-15 09:48:15 -0700127void SkGrPixelRef::onNotifyPixelsChanged() {
128 GrTexture* texture = this->getTexture();
129 if (texture) {
130 texture->texturePriv().dirtyMipMaps(true);
131 }
132}
133
jvanverthfa1e8a72014-12-22 08:31:49 -0800134SkPixelRef* SkGrPixelRef::deepCopy(SkColorType dstCT, SkColorProfileType dstPT,
135 const SkIRect* subset) {
halcanary96fcdcc2015-08-27 07:41:13 -0700136 if (nullptr == fSurface) {
137 return nullptr;
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +0000138 }
piotaixr0e977052014-09-17 16:24:04 -0700139
robertphillips@google.comd881bc12012-06-28 20:02:39 +0000140 // Note that when copying a render-target-backed pixel ref, we
141 // return a texture-backed pixel ref instead. This is because
142 // render-target pixel refs are usually created in conjunction with
143 // a GrTexture owned elsewhere (e.g., SkGpuDevice), and cannot live
144 // independently of that texture. Texture-backed pixel refs, on the other
145 // hand, own their GrTextures, and are thus self-contained.
jvanverthfa1e8a72014-12-22 08:31:49 -0800146 return copy_to_new_texture_pixelref(fSurface->asTexture(), dstCT, dstPT, subset);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +0000147}
148
piotaixr0e977052014-09-17 16:24:04 -0700149static bool tryAllocBitmapPixels(SkBitmap* bitmap) {
150 SkBitmap::Allocator* allocator = SkBitmapCache::GetAllocator();
halcanary96fcdcc2015-08-27 07:41:13 -0700151 if (nullptr != allocator) {
piotaixr0e977052014-09-17 16:24:04 -0700152 return allocator->allocPixelRef(bitmap, 0);
153 } else {
154 // DiscardableMemory is not available, fallback to default allocator
155 return bitmap->tryAllocPixels();
156 }
157}
158
bsalomon9d22fd62016-01-11 11:14:17 -0800159bool SkGrPixelRef::onReadPixels(SkBitmap* dst, SkColorType colorType, const SkIRect* subset) {
halcanary96fcdcc2015-08-27 07:41:13 -0700160 if (nullptr == fSurface || fSurface->wasDestroyed()) {
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000161 return false;
162 }
robertphillips@google.comd881bc12012-06-28 20:02:39 +0000163
bsalomon9d22fd62016-01-11 11:14:17 -0800164 GrPixelConfig config;
165 if (kRGBA_8888_SkColorType == colorType) {
166 config = kRGBA_8888_GrPixelConfig;
167 } else if (kBGRA_8888_SkColorType == colorType) {
168 config = kBGRA_8888_GrPixelConfig;
169 } else {
170 return false;
171 }
172
piotaixr0e977052014-09-17 16:24:04 -0700173 SkIRect bounds;
bsalomon49f085d2014-09-05 13:34:00 -0700174 if (subset) {
piotaixr0e977052014-09-17 16:24:04 -0700175 bounds = *subset;
robertphillips@google.comd881bc12012-06-28 20:02:39 +0000176 } else {
piotaixr0e977052014-09-17 16:24:04 -0700177 bounds = SkIRect::MakeWH(this->info().width(), this->info().height());
robertphillips@google.comd881bc12012-06-28 20:02:39 +0000178 }
piotaixr0e977052014-09-17 16:24:04 -0700179
180 //Check the cache
181 if(!SkBitmapCache::Find(this->getGenerationID(), bounds, dst)) {
182 //Cache miss
183
184 SkBitmap cachedBitmap;
bsalomon9d22fd62016-01-11 11:14:17 -0800185 cachedBitmap.setInfo(SkImageInfo::Make(bounds.width(), bounds.height(), colorType,
186 this->info().alphaType(),
187 this->info().profileType()));
piotaixr0e977052014-09-17 16:24:04 -0700188
189 // If we can't alloc the pixels, then fail
190 if (!tryAllocBitmapPixels(&cachedBitmap)) {
191 return false;
192 }
193
194 // Try to read the pixels from the surface
195 void* buffer = cachedBitmap.getPixels();
196 bool readPixelsOk = fSurface->readPixels(bounds.fLeft, bounds.fTop,
197 bounds.width(), bounds.height(),
bsalomon9d22fd62016-01-11 11:14:17 -0800198 config, buffer, cachedBitmap.rowBytes());
piotaixr0e977052014-09-17 16:24:04 -0700199
200 if (!readPixelsOk) {
201 return false;
202 }
203
204 // If we are here, pixels were read correctly from the surface.
205 cachedBitmap.setImmutable();
206 //Add to the cache
reed83787d02015-02-25 07:17:11 -0800207 SkBitmapCache::Add(this, bounds, cachedBitmap);
piotaixr0e977052014-09-17 16:24:04 -0700208
209 dst->swap(cachedBitmap);
210 }
211
212 return true;
213
reed@google.com4281d652011-04-08 18:54:20 +0000214}