blob: f67bfd4eb5239e104b871244e647fdcaef8f1000 [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"
Robert Phillipsb4460882016-11-17 14:43:51 -050016#include "SkMathPriv.h"
bungeman@google.comfab44db2013-10-11 18:50:45 +000017#include <stdio.h>
commit-bot@chromium.org6c5d9a12013-09-30 18:05:43 +000018
Robert Phillipsf2361d22016-10-25 14:20:06 -040019GrSurface::~GrSurface() {
20 if (fLastOpList) {
21 fLastOpList->clearTarget();
22 }
23 SkSafeUnref(fLastOpList);
24
25 // check that invokeReleaseProc has been called (if needed)
26 SkASSERT(NULL == fReleaseProc);
27}
28
Robert Phillipsb4460882016-11-17 14:43:51 -050029size_t GrSurface::WorstCaseSize(const GrSurfaceDesc& desc, bool useNextPow2) {
robertphillips6e83ac72015-08-13 05:19:14 -070030 size_t size;
31
Robert Phillipsb4460882016-11-17 14:43:51 -050032 int width = useNextPow2 ? GrNextPow2(desc.fWidth) : desc.fWidth;
33 int height = useNextPow2 ? GrNextPow2(desc.fHeight) : desc.fHeight;
34
robertphillips6e83ac72015-08-13 05:19:14 -070035 bool isRenderTarget = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag);
36 if (isRenderTarget) {
37 // We own one color value for each MSAA sample.
38 int colorValuesPerPixel = SkTMax(1, desc.fSampleCnt);
39 if (desc.fSampleCnt) {
40 // Worse case, we own the resolve buffer so that is one more sample per pixel.
41 colorValuesPerPixel += 1;
42 }
43 SkASSERT(kUnknown_GrPixelConfig != desc.fConfig);
44 SkASSERT(!GrPixelConfigIsCompressed(desc.fConfig));
Robert Phillipsb4460882016-11-17 14:43:51 -050045 size_t colorBytes = (size_t) width * height * GrBytesPerPixel(desc.fConfig);
robertphillips4c56b9f2016-08-17 08:02:51 -070046
Robert Phillipsd6214d42016-11-07 08:23:48 -050047 // This would be a nice assert to have (i.e., we aren't creating 0 width/height surfaces).
48 // Unfortunately Chromium seems to want to do this.
49 //SkASSERT(colorBytes > 0);
50
51 size = colorValuesPerPixel * colorBytes;
52 size += colorBytes/3; // in case we have to mipmap
robertphillips6e83ac72015-08-13 05:19:14 -070053 } else {
54 if (GrPixelConfigIsCompressed(desc.fConfig)) {
Robert Phillipsb4460882016-11-17 14:43:51 -050055 size = GrCompressedFormatDataSize(desc.fConfig, width, height);
robertphillips6e83ac72015-08-13 05:19:14 -070056 } else {
Robert Phillipsb4460882016-11-17 14:43:51 -050057 size = (size_t) width * height * GrBytesPerPixel(desc.fConfig);
robertphillips6e83ac72015-08-13 05:19:14 -070058 }
59
60 size += size/3; // in case we have to mipmap
61 }
62
63 return size;
64}
65
Robert Phillipsd6214d42016-11-07 08:23:48 -050066size_t GrSurface::ComputeSize(const GrSurfaceDesc& desc,
67 int colorSamplesPerPixel,
Robert Phillipsb4460882016-11-17 14:43:51 -050068 bool hasMIPMaps,
69 bool useNextPow2) {
Robert Phillipsd6214d42016-11-07 08:23:48 -050070 size_t colorSize;
71
Robert Phillipsb4460882016-11-17 14:43:51 -050072 int width = useNextPow2 ? GrNextPow2(desc.fWidth) : desc.fWidth;
73 int height = useNextPow2 ? GrNextPow2(desc.fHeight) : desc.fHeight;
74
Robert Phillipsd6214d42016-11-07 08:23:48 -050075 SkASSERT(kUnknown_GrPixelConfig != desc.fConfig);
76 if (GrPixelConfigIsCompressed(desc.fConfig)) {
Robert Phillipsb4460882016-11-17 14:43:51 -050077 colorSize = GrCompressedFormatDataSize(desc.fConfig, width, height);
Robert Phillipsd6214d42016-11-07 08:23:48 -050078 } else {
Robert Phillipsb4460882016-11-17 14:43:51 -050079 colorSize = (size_t) width * height * GrBytesPerPixel(desc.fConfig);
Robert Phillipsd6214d42016-11-07 08:23:48 -050080 }
81 SkASSERT(colorSize > 0);
82
83 size_t finalSize = colorSamplesPerPixel * colorSize;
84
85 if (hasMIPMaps) {
86 // We don't have to worry about the mipmaps being a different size than
87 // we'd expect because we never change fDesc.fWidth/fHeight.
88 finalSize += colorSize/3;
89 }
90
Robert Phillipsb4460882016-11-17 14:43:51 -050091 SkASSERT(finalSize <= WorstCaseSize(desc, useNextPow2));
Robert Phillipsd6214d42016-11-07 08:23:48 -050092 return finalSize;
93}
94
bsalomone8d21e82015-07-16 08:23:13 -070095template<typename T> static bool adjust_params(int surfaceWidth,
96 int surfaceHeight,
97 size_t bpp,
98 int* left, int* top, int* width, int* height,
99 T** data,
100 size_t* rowBytes) {
101 if (!*rowBytes) {
102 *rowBytes = *width * bpp;
103 }
104
105 SkIRect subRect = SkIRect::MakeXYWH(*left, *top, *width, *height);
106 SkIRect bounds = SkIRect::MakeWH(surfaceWidth, surfaceHeight);
107
108 if (!subRect.intersect(bounds)) {
109 return false;
110 }
111 *data = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(*data) +
112 (subRect.fTop - *top) * *rowBytes + (subRect.fLeft - *left) * bpp);
113
114 *left = subRect.fLeft;
115 *top = subRect.fTop;
116 *width = subRect.width();
117 *height = subRect.height();
118 return true;
119}
120
121bool GrSurfacePriv::AdjustReadPixelParams(int surfaceWidth,
122 int surfaceHeight,
123 size_t bpp,
124 int* left, int* top, int* width, int* height,
125 void** data,
126 size_t* rowBytes) {
127 return adjust_params<void>(surfaceWidth, surfaceHeight, bpp, left, top, width, height, data,
128 rowBytes);
129}
130
131bool GrSurfacePriv::AdjustWritePixelParams(int surfaceWidth,
132 int surfaceHeight,
133 size_t bpp,
134 int* left, int* top, int* width, int* height,
135 const void** data,
136 size_t* rowBytes) {
137 return adjust_params<const void>(surfaceWidth, surfaceHeight, bpp, left, top, width, height,
138 data, rowBytes);
139}
140
141
142//////////////////////////////////////////////////////////////////////////////
143
bsalomon81beccc2014-10-13 12:32:55 -0700144bool GrSurface::writePixels(int left, int top, int width, int height,
145 GrPixelConfig config, const void* buffer, size_t rowBytes,
146 uint32_t pixelOpsFlags) {
147 // go through context so that all necessary flushing occurs
148 GrContext* context = this->getContext();
halcanary96fcdcc2015-08-27 07:41:13 -0700149 if (nullptr == context) {
bsalomon81beccc2014-10-13 12:32:55 -0700150 return false;
151 }
cblume55f2d2d2016-02-26 13:20:48 -0800152 return context->writeSurfacePixels(this, left, top, width, height, config, buffer,
153 rowBytes, pixelOpsFlags);
bsalomon81beccc2014-10-13 12:32:55 -0700154}
155
156bool GrSurface::readPixels(int left, int top, int width, int height,
157 GrPixelConfig config, void* buffer, size_t rowBytes,
158 uint32_t pixelOpsFlags) {
159 // go through context so that all necessary flushing occurs
160 GrContext* context = this->getContext();
halcanary96fcdcc2015-08-27 07:41:13 -0700161 if (nullptr == context) {
bsalomon81beccc2014-10-13 12:32:55 -0700162 return false;
163 }
bsalomone8d21e82015-07-16 08:23:13 -0700164 return context->readSurfacePixels(this, left, top, width, height, config, buffer,
165 rowBytes, pixelOpsFlags);
bsalomon81beccc2014-10-13 12:32:55 -0700166}
167
bsalomonafbf2d62014-09-30 12:18:44 -0700168// TODO: This should probably be a non-member helper function. It might only be needed in
169// debug or developer builds.
commit-bot@chromium.org6c5d9a12013-09-30 18:05:43 +0000170bool GrSurface::savePixels(const char* filename) {
171 SkBitmap bm;
reed84825042014-09-02 12:50:45 -0700172 if (!bm.tryAllocPixels(SkImageInfo::MakeN32Premul(this->width(), this->height()))) {
reed@google.com9ebcac52014-01-24 18:53:42 +0000173 return false;
174 }
commit-bot@chromium.org6c5d9a12013-09-30 18:05:43 +0000175
bsalomonafbf2d62014-09-30 12:18:44 -0700176 bool result = this->readPixels(0, 0, this->width(), this->height(), kSkia8888_GrPixelConfig,
177 bm.getPixels());
commit-bot@chromium.org6c5d9a12013-09-30 18:05:43 +0000178 if (!result) {
179 SkDebugf("------ failed to read pixels for %s\n", filename);
180 return false;
181 }
skia.committer@gmail.com1d3bfdc2013-10-01 07:01:46 +0000182
commit-bot@chromium.org6c5d9a12013-09-30 18:05:43 +0000183 // remove any previous version of this file
184 remove(filename);
185
Hal Canarya2b4bdc2016-11-22 14:21:38 -0700186 if (!SkImageEncoder::EncodeFile(filename, bm, SkImageEncoder::kPNG_Type, 100)) {
commit-bot@chromium.org6c5d9a12013-09-30 18:05:43 +0000187 SkDebugf("------ failed to encode %s\n", filename);
188 remove(filename); // remove any partial file
189 return false;
190 }
191
192 return true;
193}
bsalomon8d034a12014-09-22 12:21:08 -0700194
bsalomonf80bfed2014-10-07 05:56:02 -0700195void GrSurface::flushWrites() {
196 if (!this->wasDestroyed()) {
197 this->getContext()->flushSurfaceWrites(this);
198 }
199}
200
bsalomon8d034a12014-09-22 12:21:08 -0700201bool GrSurface::hasPendingRead() const {
202 const GrTexture* thisTex = this->asTexture();
203 if (thisTex && thisTex->internalHasPendingRead()) {
204 return true;
205 }
206 const GrRenderTarget* thisRT = this->asRenderTarget();
207 if (thisRT && thisRT->internalHasPendingRead()) {
208 return true;
209 }
210 return false;
211}
212
213bool GrSurface::hasPendingWrite() const {
214 const GrTexture* thisTex = this->asTexture();
215 if (thisTex && thisTex->internalHasPendingWrite()) {
216 return true;
217 }
218 const GrRenderTarget* thisRT = this->asRenderTarget();
219 if (thisRT && thisRT->internalHasPendingWrite()) {
220 return true;
221 }
222 return false;
223}
224
225bool GrSurface::hasPendingIO() const {
226 const GrTexture* thisTex = this->asTexture();
227 if (thisTex && thisTex->internalHasPendingIO()) {
228 return true;
229 }
230 const GrRenderTarget* thisRT = this->asRenderTarget();
231 if (thisRT && thisRT->internalHasPendingIO()) {
232 return true;
233 }
234 return false;
235}
reedde499882015-06-18 13:41:40 -0700236
237void GrSurface::onRelease() {
238 this->invokeReleaseProc();
239 this->INHERITED::onRelease();
240}
241
242void GrSurface::onAbandon() {
243 this->invokeReleaseProc();
244 this->INHERITED::onAbandon();
245}
Robert Phillipsf2361d22016-10-25 14:20:06 -0400246
247void GrSurface::setLastOpList(GrOpList* opList) {
248 if (fLastOpList) {
249 // The non-MDB world never closes so we can't check this condition
250#ifdef ENABLE_MDB
251 SkASSERT(fLastOpList->isClosed());
252#endif
253 fLastOpList->clearTarget();
254 }
255
256 SkRefCnt_SafeAssign(fLastOpList, opList);
257}