blob: 7f571b875fc94ecf6beec524fd9f62391dd2c9f7 [file] [log] [blame]
robertphillips@google.com7d501ab2012-06-21 21:09:06 +00001/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "GrSurface.h"
bsalomonf276ac52015-10-09 13:36:42 -07009#include "GrContext.h"
Robert Phillipsf2361d22016-10-25 14:20:06 -040010#include "GrOpList.h"
bsalomonafbf2d62014-09-30 12:18:44 -070011#include "GrSurfacePriv.h"
robertphillips@google.com7d501ab2012-06-21 21:09:06 +000012
commit-bot@chromium.org6c5d9a12013-09-30 18:05:43 +000013#include "SkBitmap.h"
bsalomonf276ac52015-10-09 13:36:42 -070014#include "SkGrPriv.h"
commit-bot@chromium.org6c5d9a12013-09-30 18:05:43 +000015#include "SkImageEncoder.h"
bungeman@google.comfab44db2013-10-11 18:50:45 +000016#include <stdio.h>
commit-bot@chromium.org6c5d9a12013-09-30 18:05:43 +000017
Robert Phillipsf2361d22016-10-25 14:20:06 -040018GrSurface::~GrSurface() {
19 if (fLastOpList) {
20 fLastOpList->clearTarget();
21 }
22 SkSafeUnref(fLastOpList);
23
24 // check that invokeReleaseProc has been called (if needed)
25 SkASSERT(NULL == fReleaseProc);
26}
27
robertphillipsf1c6cd72016-08-18 07:11:13 -070028size_t GrSurface::WorstCaseSize(const GrSurfaceDesc& desc) {
robertphillips6e83ac72015-08-13 05:19:14 -070029 size_t size;
30
31 bool isRenderTarget = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag);
32 if (isRenderTarget) {
33 // We own one color value for each MSAA sample.
34 int colorValuesPerPixel = SkTMax(1, desc.fSampleCnt);
35 if (desc.fSampleCnt) {
36 // Worse case, we own the resolve buffer so that is one more sample per pixel.
37 colorValuesPerPixel += 1;
38 }
39 SkASSERT(kUnknown_GrPixelConfig != desc.fConfig);
40 SkASSERT(!GrPixelConfigIsCompressed(desc.fConfig));
Robert Phillips68b7a522016-11-09 08:03:21 -050041 size_t colorBytes = (size_t) desc.fWidth * desc.fHeight * GrBytesPerPixel(desc.fConfig);
robertphillips4c56b9f2016-08-17 08:02:51 -070042
Robert Phillipsd6214d42016-11-07 08:23:48 -050043 // This would be a nice assert to have (i.e., we aren't creating 0 width/height surfaces).
44 // Unfortunately Chromium seems to want to do this.
45 //SkASSERT(colorBytes > 0);
46
47 size = colorValuesPerPixel * colorBytes;
48 size += colorBytes/3; // in case we have to mipmap
robertphillips6e83ac72015-08-13 05:19:14 -070049 } else {
50 if (GrPixelConfigIsCompressed(desc.fConfig)) {
51 size = GrCompressedFormatDataSize(desc.fConfig, desc.fWidth, desc.fHeight);
52 } else {
Robert Phillips68b7a522016-11-09 08:03:21 -050053 size = (size_t) desc.fWidth * desc.fHeight * GrBytesPerPixel(desc.fConfig);
robertphillips6e83ac72015-08-13 05:19:14 -070054 }
55
56 size += size/3; // in case we have to mipmap
57 }
58
59 return size;
60}
61
Robert Phillipsd6214d42016-11-07 08:23:48 -050062size_t GrSurface::ComputeSize(const GrSurfaceDesc& desc,
63 int colorSamplesPerPixel,
64 bool hasMIPMaps) {
65 size_t colorSize;
66
67 SkASSERT(kUnknown_GrPixelConfig != desc.fConfig);
68 if (GrPixelConfigIsCompressed(desc.fConfig)) {
69 colorSize = GrCompressedFormatDataSize(desc.fConfig, desc.fWidth, desc.fHeight);
70 } else {
Robert Phillips68b7a522016-11-09 08:03:21 -050071 colorSize = (size_t) desc.fWidth * desc.fHeight * GrBytesPerPixel(desc.fConfig);
Robert Phillipsd6214d42016-11-07 08:23:48 -050072 }
73 SkASSERT(colorSize > 0);
74
75 size_t finalSize = colorSamplesPerPixel * colorSize;
76
77 if (hasMIPMaps) {
78 // We don't have to worry about the mipmaps being a different size than
79 // we'd expect because we never change fDesc.fWidth/fHeight.
80 finalSize += colorSize/3;
81 }
82
83 SkASSERT(finalSize <= WorstCaseSize(desc));
84 return finalSize;
85}
86
bsalomone8d21e82015-07-16 08:23:13 -070087template<typename T> static bool adjust_params(int surfaceWidth,
88 int surfaceHeight,
89 size_t bpp,
90 int* left, int* top, int* width, int* height,
91 T** data,
92 size_t* rowBytes) {
93 if (!*rowBytes) {
94 *rowBytes = *width * bpp;
95 }
96
97 SkIRect subRect = SkIRect::MakeXYWH(*left, *top, *width, *height);
98 SkIRect bounds = SkIRect::MakeWH(surfaceWidth, surfaceHeight);
99
100 if (!subRect.intersect(bounds)) {
101 return false;
102 }
103 *data = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(*data) +
104 (subRect.fTop - *top) * *rowBytes + (subRect.fLeft - *left) * bpp);
105
106 *left = subRect.fLeft;
107 *top = subRect.fTop;
108 *width = subRect.width();
109 *height = subRect.height();
110 return true;
111}
112
113bool GrSurfacePriv::AdjustReadPixelParams(int surfaceWidth,
114 int surfaceHeight,
115 size_t bpp,
116 int* left, int* top, int* width, int* height,
117 void** data,
118 size_t* rowBytes) {
119 return adjust_params<void>(surfaceWidth, surfaceHeight, bpp, left, top, width, height, data,
120 rowBytes);
121}
122
123bool GrSurfacePriv::AdjustWritePixelParams(int surfaceWidth,
124 int surfaceHeight,
125 size_t bpp,
126 int* left, int* top, int* width, int* height,
127 const void** data,
128 size_t* rowBytes) {
129 return adjust_params<const void>(surfaceWidth, surfaceHeight, bpp, left, top, width, height,
130 data, rowBytes);
131}
132
133
134//////////////////////////////////////////////////////////////////////////////
135
bsalomon81beccc2014-10-13 12:32:55 -0700136bool GrSurface::writePixels(int left, int top, int width, int height,
137 GrPixelConfig config, const void* buffer, size_t rowBytes,
138 uint32_t pixelOpsFlags) {
139 // go through context so that all necessary flushing occurs
140 GrContext* context = this->getContext();
halcanary96fcdcc2015-08-27 07:41:13 -0700141 if (nullptr == context) {
bsalomon81beccc2014-10-13 12:32:55 -0700142 return false;
143 }
cblume55f2d2d2016-02-26 13:20:48 -0800144 return context->writeSurfacePixels(this, left, top, width, height, config, buffer,
145 rowBytes, pixelOpsFlags);
bsalomon81beccc2014-10-13 12:32:55 -0700146}
147
148bool GrSurface::readPixels(int left, int top, int width, int height,
149 GrPixelConfig config, void* buffer, size_t rowBytes,
150 uint32_t pixelOpsFlags) {
151 // go through context so that all necessary flushing occurs
152 GrContext* context = this->getContext();
halcanary96fcdcc2015-08-27 07:41:13 -0700153 if (nullptr == context) {
bsalomon81beccc2014-10-13 12:32:55 -0700154 return false;
155 }
bsalomone8d21e82015-07-16 08:23:13 -0700156 return context->readSurfacePixels(this, left, top, width, height, config, buffer,
157 rowBytes, pixelOpsFlags);
bsalomon81beccc2014-10-13 12:32:55 -0700158}
159
bsalomonafbf2d62014-09-30 12:18:44 -0700160// TODO: This should probably be a non-member helper function. It might only be needed in
161// debug or developer builds.
commit-bot@chromium.org6c5d9a12013-09-30 18:05:43 +0000162bool GrSurface::savePixels(const char* filename) {
163 SkBitmap bm;
reed84825042014-09-02 12:50:45 -0700164 if (!bm.tryAllocPixels(SkImageInfo::MakeN32Premul(this->width(), this->height()))) {
reed@google.com9ebcac52014-01-24 18:53:42 +0000165 return false;
166 }
commit-bot@chromium.org6c5d9a12013-09-30 18:05:43 +0000167
bsalomonafbf2d62014-09-30 12:18:44 -0700168 bool result = this->readPixels(0, 0, this->width(), this->height(), kSkia8888_GrPixelConfig,
169 bm.getPixels());
commit-bot@chromium.org6c5d9a12013-09-30 18:05:43 +0000170 if (!result) {
171 SkDebugf("------ failed to read pixels for %s\n", filename);
172 return false;
173 }
skia.committer@gmail.com1d3bfdc2013-10-01 07:01:46 +0000174
commit-bot@chromium.org6c5d9a12013-09-30 18:05:43 +0000175 // remove any previous version of this file
176 remove(filename);
177
178 if (!SkImageEncoder::EncodeFile(filename, bm, SkImageEncoder::kPNG_Type, 100)) {
179 SkDebugf("------ failed to encode %s\n", filename);
180 remove(filename); // remove any partial file
181 return false;
182 }
183
184 return true;
185}
bsalomon8d034a12014-09-22 12:21:08 -0700186
bsalomonf80bfed2014-10-07 05:56:02 -0700187void GrSurface::flushWrites() {
188 if (!this->wasDestroyed()) {
189 this->getContext()->flushSurfaceWrites(this);
190 }
191}
192
bsalomon8d034a12014-09-22 12:21:08 -0700193bool GrSurface::hasPendingRead() const {
194 const GrTexture* thisTex = this->asTexture();
195 if (thisTex && thisTex->internalHasPendingRead()) {
196 return true;
197 }
198 const GrRenderTarget* thisRT = this->asRenderTarget();
199 if (thisRT && thisRT->internalHasPendingRead()) {
200 return true;
201 }
202 return false;
203}
204
205bool GrSurface::hasPendingWrite() const {
206 const GrTexture* thisTex = this->asTexture();
207 if (thisTex && thisTex->internalHasPendingWrite()) {
208 return true;
209 }
210 const GrRenderTarget* thisRT = this->asRenderTarget();
211 if (thisRT && thisRT->internalHasPendingWrite()) {
212 return true;
213 }
214 return false;
215}
216
217bool GrSurface::hasPendingIO() const {
218 const GrTexture* thisTex = this->asTexture();
219 if (thisTex && thisTex->internalHasPendingIO()) {
220 return true;
221 }
222 const GrRenderTarget* thisRT = this->asRenderTarget();
223 if (thisRT && thisRT->internalHasPendingIO()) {
224 return true;
225 }
226 return false;
227}
reedde499882015-06-18 13:41:40 -0700228
229void GrSurface::onRelease() {
230 this->invokeReleaseProc();
231 this->INHERITED::onRelease();
232}
233
234void GrSurface::onAbandon() {
235 this->invokeReleaseProc();
236 this->INHERITED::onAbandon();
237}
Robert Phillipsf2361d22016-10-25 14:20:06 -0400238
239void GrSurface::setLastOpList(GrOpList* opList) {
240 if (fLastOpList) {
241 // The non-MDB world never closes so we can't check this condition
242#ifdef ENABLE_MDB
243 SkASSERT(fLastOpList->isClosed());
244#endif
245 fLastOpList->clearTarget();
246 }
247
248 SkRefCnt_SafeAssign(fLastOpList, opList);
249}