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