1 /*
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"
9 #include "GrContext.h"
10 #include "GrSurfacePriv.h"
11
12 #include "SkBitmap.h"
13 #include "SkGrPriv.h"
14 #include "SkImageEncoder.h"
15 #include <stdio.h>
16
WorseCaseSize(const GrSurfaceDesc & desc)17 size_t GrSurface::WorseCaseSize(const GrSurfaceDesc& desc) {
18 size_t size;
19
20 bool isRenderTarget = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag);
21 if (isRenderTarget) {
22 // We own one color value for each MSAA sample.
23 int colorValuesPerPixel = SkTMax(1, desc.fSampleCnt);
24 if (desc.fSampleCnt) {
25 // Worse case, we own the resolve buffer so that is one more sample per pixel.
26 colorValuesPerPixel += 1;
27 }
28 SkASSERT(kUnknown_GrPixelConfig != desc.fConfig);
29 SkASSERT(!GrPixelConfigIsCompressed(desc.fConfig));
30 size_t colorBytes = GrBytesPerPixel(desc.fConfig);
31 SkASSERT(colorBytes > 0);
32 size = colorValuesPerPixel * desc.fWidth * desc.fHeight * colorBytes;
33 } else {
34 if (GrPixelConfigIsCompressed(desc.fConfig)) {
35 size = GrCompressedFormatDataSize(desc.fConfig, desc.fWidth, desc.fHeight);
36 } else {
37 size = (size_t) desc.fWidth * desc.fHeight * GrBytesPerPixel(desc.fConfig);
38 }
39
40 size += size/3; // in case we have to mipmap
41 }
42
43 return size;
44 }
45
adjust_params(int surfaceWidth,int surfaceHeight,size_t bpp,int * left,int * top,int * width,int * height,T ** data,size_t * rowBytes)46 template<typename T> static bool adjust_params(int surfaceWidth,
47 int surfaceHeight,
48 size_t bpp,
49 int* left, int* top, int* width, int* height,
50 T** data,
51 size_t* rowBytes) {
52 if (!*rowBytes) {
53 *rowBytes = *width * bpp;
54 }
55
56 SkIRect subRect = SkIRect::MakeXYWH(*left, *top, *width, *height);
57 SkIRect bounds = SkIRect::MakeWH(surfaceWidth, surfaceHeight);
58
59 if (!subRect.intersect(bounds)) {
60 return false;
61 }
62 *data = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(*data) +
63 (subRect.fTop - *top) * *rowBytes + (subRect.fLeft - *left) * bpp);
64
65 *left = subRect.fLeft;
66 *top = subRect.fTop;
67 *width = subRect.width();
68 *height = subRect.height();
69 return true;
70 }
71
AdjustReadPixelParams(int surfaceWidth,int surfaceHeight,size_t bpp,int * left,int * top,int * width,int * height,void ** data,size_t * rowBytes)72 bool GrSurfacePriv::AdjustReadPixelParams(int surfaceWidth,
73 int surfaceHeight,
74 size_t bpp,
75 int* left, int* top, int* width, int* height,
76 void** data,
77 size_t* rowBytes) {
78 return adjust_params<void>(surfaceWidth, surfaceHeight, bpp, left, top, width, height, data,
79 rowBytes);
80 }
81
AdjustWritePixelParams(int surfaceWidth,int surfaceHeight,size_t bpp,int * left,int * top,int * width,int * height,const void ** data,size_t * rowBytes)82 bool GrSurfacePriv::AdjustWritePixelParams(int surfaceWidth,
83 int surfaceHeight,
84 size_t bpp,
85 int* left, int* top, int* width, int* height,
86 const void** data,
87 size_t* rowBytes) {
88 return adjust_params<const void>(surfaceWidth, surfaceHeight, bpp, left, top, width, height,
89 data, rowBytes);
90 }
91
92
93 //////////////////////////////////////////////////////////////////////////////
94
writePixels(int left,int top,int width,int height,GrPixelConfig config,const void * buffer,size_t rowBytes,uint32_t pixelOpsFlags)95 bool GrSurface::writePixels(int left, int top, int width, int height,
96 GrPixelConfig config, const void* buffer, size_t rowBytes,
97 uint32_t pixelOpsFlags) {
98 // go through context so that all necessary flushing occurs
99 GrContext* context = this->getContext();
100 if (nullptr == context) {
101 return false;
102 }
103 return context->writeSurfacePixels(this, left, top, width, height, config, buffer, rowBytes,
104 pixelOpsFlags);
105 }
106
readPixels(int left,int top,int width,int height,GrPixelConfig config,void * buffer,size_t rowBytes,uint32_t pixelOpsFlags)107 bool GrSurface::readPixels(int left, int top, int width, int height,
108 GrPixelConfig config, void* buffer, size_t rowBytes,
109 uint32_t pixelOpsFlags) {
110 // go through context so that all necessary flushing occurs
111 GrContext* context = this->getContext();
112 if (nullptr == context) {
113 return false;
114 }
115 return context->readSurfacePixels(this, left, top, width, height, config, buffer,
116 rowBytes, pixelOpsFlags);
117 }
118
info(SkAlphaType alphaType) const119 SkImageInfo GrSurface::info(SkAlphaType alphaType) const {
120 SkColorType colorType;
121 SkColorProfileType profileType;
122 if (!GrPixelConfig2ColorAndProfileType(this->config(), &colorType, &profileType)) {
123 sk_throw();
124 }
125 return SkImageInfo::Make(this->width(), this->height(), colorType, alphaType,
126 profileType);
127 }
128
129 // TODO: This should probably be a non-member helper function. It might only be needed in
130 // debug or developer builds.
savePixels(const char * filename)131 bool GrSurface::savePixels(const char* filename) {
132 SkBitmap bm;
133 if (!bm.tryAllocPixels(SkImageInfo::MakeN32Premul(this->width(), this->height()))) {
134 return false;
135 }
136
137 bool result = this->readPixels(0, 0, this->width(), this->height(), kSkia8888_GrPixelConfig,
138 bm.getPixels());
139 if (!result) {
140 SkDebugf("------ failed to read pixels for %s\n", filename);
141 return false;
142 }
143
144 // remove any previous version of this file
145 remove(filename);
146
147 if (!SkImageEncoder::EncodeFile(filename, bm, SkImageEncoder::kPNG_Type, 100)) {
148 SkDebugf("------ failed to encode %s\n", filename);
149 remove(filename); // remove any partial file
150 return false;
151 }
152
153 return true;
154 }
155
flushWrites()156 void GrSurface::flushWrites() {
157 if (!this->wasDestroyed()) {
158 this->getContext()->flushSurfaceWrites(this);
159 }
160 }
161
prepareForExternalIO()162 void GrSurface::prepareForExternalIO() {
163 if (!this->wasDestroyed()) {
164 this->getContext()->prepareSurfaceForExternalIO(this);
165 }
166 }
167
hasPendingRead() const168 bool GrSurface::hasPendingRead() const {
169 const GrTexture* thisTex = this->asTexture();
170 if (thisTex && thisTex->internalHasPendingRead()) {
171 return true;
172 }
173 const GrRenderTarget* thisRT = this->asRenderTarget();
174 if (thisRT && thisRT->internalHasPendingRead()) {
175 return true;
176 }
177 return false;
178 }
179
hasPendingWrite() const180 bool GrSurface::hasPendingWrite() const {
181 const GrTexture* thisTex = this->asTexture();
182 if (thisTex && thisTex->internalHasPendingWrite()) {
183 return true;
184 }
185 const GrRenderTarget* thisRT = this->asRenderTarget();
186 if (thisRT && thisRT->internalHasPendingWrite()) {
187 return true;
188 }
189 return false;
190 }
191
hasPendingIO() const192 bool GrSurface::hasPendingIO() const {
193 const GrTexture* thisTex = this->asTexture();
194 if (thisTex && thisTex->internalHasPendingIO()) {
195 return true;
196 }
197 const GrRenderTarget* thisRT = this->asRenderTarget();
198 if (thisRT && thisRT->internalHasPendingIO()) {
199 return true;
200 }
201 return false;
202 }
203
onRelease()204 void GrSurface::onRelease() {
205 this->invokeReleaseProc();
206 this->INHERITED::onRelease();
207 }
208
onAbandon()209 void GrSurface::onAbandon() {
210 this->invokeReleaseProc();
211 this->INHERITED::onAbandon();
212 }
213