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 
WorstCaseSize(const GrSurfaceDesc & desc)17 size_t GrSurface::WorstCaseSize(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 
33         size = (size_t) colorValuesPerPixel * desc.fWidth * desc.fHeight * colorBytes;
34     } else {
35         if (GrPixelConfigIsCompressed(desc.fConfig)) {
36             size = GrCompressedFormatDataSize(desc.fConfig, desc.fWidth, desc.fHeight);
37         } else {
38             size = (size_t) desc.fWidth * desc.fHeight * GrBytesPerPixel(desc.fConfig);
39         }
40 
41         size += size/3;  // in case we have to mipmap
42     }
43 
44     return size;
45 }
46 
adjust_params(int surfaceWidth,int surfaceHeight,size_t bpp,int * left,int * top,int * width,int * height,T ** data,size_t * rowBytes)47 template<typename T> static bool adjust_params(int surfaceWidth,
48                                                int surfaceHeight,
49                                                size_t bpp,
50                                                int* left, int* top, int* width, int* height,
51                                                T** data,
52                                                size_t* rowBytes) {
53     if (!*rowBytes) {
54         *rowBytes = *width * bpp;
55     }
56 
57     SkIRect subRect = SkIRect::MakeXYWH(*left, *top, *width, *height);
58     SkIRect bounds = SkIRect::MakeWH(surfaceWidth, surfaceHeight);
59 
60     if (!subRect.intersect(bounds)) {
61         return false;
62     }
63     *data = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(*data) +
64             (subRect.fTop - *top) * *rowBytes + (subRect.fLeft - *left) * bpp);
65 
66     *left = subRect.fLeft;
67     *top = subRect.fTop;
68     *width = subRect.width();
69     *height = subRect.height();
70     return true;
71 }
72 
AdjustReadPixelParams(int surfaceWidth,int surfaceHeight,size_t bpp,int * left,int * top,int * width,int * height,void ** data,size_t * rowBytes)73 bool GrSurfacePriv::AdjustReadPixelParams(int surfaceWidth,
74                                           int surfaceHeight,
75                                           size_t bpp,
76                                           int* left, int* top, int* width, int* height,
77                                           void** data,
78                                           size_t* rowBytes) {
79     return adjust_params<void>(surfaceWidth, surfaceHeight, bpp, left, top, width, height, data,
80                                rowBytes);
81 }
82 
AdjustWritePixelParams(int surfaceWidth,int surfaceHeight,size_t bpp,int * left,int * top,int * width,int * height,const void ** data,size_t * rowBytes)83 bool GrSurfacePriv::AdjustWritePixelParams(int surfaceWidth,
84                                            int surfaceHeight,
85                                            size_t bpp,
86                                            int* left, int* top, int* width, int* height,
87                                            const void** data,
88                                            size_t* rowBytes) {
89     return adjust_params<const void>(surfaceWidth, surfaceHeight, bpp, left, top, width, height,
90                                      data, rowBytes);
91 }
92 
93 
94 //////////////////////////////////////////////////////////////////////////////
95 
writePixels(int left,int top,int width,int height,GrPixelConfig config,const void * buffer,size_t rowBytes,uint32_t pixelOpsFlags)96 bool GrSurface::writePixels(int left, int top, int width, int height,
97                             GrPixelConfig config, const void* buffer, size_t rowBytes,
98                             uint32_t pixelOpsFlags) {
99     // go through context so that all necessary flushing occurs
100     GrContext* context = this->getContext();
101     if (nullptr == context) {
102         return false;
103     }
104     return context->writeSurfacePixels(this, left, top, width, height, config, buffer,
105                                        rowBytes, pixelOpsFlags);
106 }
107 
readPixels(int left,int top,int width,int height,GrPixelConfig config,void * buffer,size_t rowBytes,uint32_t pixelOpsFlags)108 bool GrSurface::readPixels(int left, int top, int width, int height,
109                            GrPixelConfig config, void* buffer, size_t rowBytes,
110                            uint32_t pixelOpsFlags) {
111     // go through context so that all necessary flushing occurs
112     GrContext* context = this->getContext();
113     if (nullptr == context) {
114         return false;
115     }
116     return context->readSurfacePixels(this, left, top, width, height, config, buffer,
117                                       rowBytes, pixelOpsFlags);
118 }
119 
120 // TODO: This should probably be a non-member helper function. It might only be needed in
121 // debug or developer builds.
savePixels(const char * filename)122 bool GrSurface::savePixels(const char* filename) {
123     SkBitmap bm;
124     if (!bm.tryAllocPixels(SkImageInfo::MakeN32Premul(this->width(), this->height()))) {
125         return false;
126     }
127 
128     bool result = this->readPixels(0, 0, this->width(), this->height(), kSkia8888_GrPixelConfig,
129                                    bm.getPixels());
130     if (!result) {
131         SkDebugf("------ failed to read pixels for %s\n", filename);
132         return false;
133     }
134 
135     // remove any previous version of this file
136     remove(filename);
137 
138     if (!SkImageEncoder::EncodeFile(filename, bm, SkImageEncoder::kPNG_Type, 100)) {
139         SkDebugf("------ failed to encode %s\n", filename);
140         remove(filename);   // remove any partial file
141         return false;
142     }
143 
144     return true;
145 }
146 
flushWrites()147 void GrSurface::flushWrites() {
148     if (!this->wasDestroyed()) {
149         this->getContext()->flushSurfaceWrites(this);
150     }
151 }
152 
hasPendingRead() const153 bool GrSurface::hasPendingRead() const {
154     const GrTexture* thisTex = this->asTexture();
155     if (thisTex && thisTex->internalHasPendingRead()) {
156         return true;
157     }
158     const GrRenderTarget* thisRT = this->asRenderTarget();
159     if (thisRT && thisRT->internalHasPendingRead()) {
160         return true;
161     }
162     return false;
163 }
164 
hasPendingWrite() const165 bool GrSurface::hasPendingWrite() const {
166     const GrTexture* thisTex = this->asTexture();
167     if (thisTex && thisTex->internalHasPendingWrite()) {
168         return true;
169     }
170     const GrRenderTarget* thisRT = this->asRenderTarget();
171     if (thisRT && thisRT->internalHasPendingWrite()) {
172         return true;
173     }
174     return false;
175 }
176 
hasPendingIO() const177 bool GrSurface::hasPendingIO() const {
178     const GrTexture* thisTex = this->asTexture();
179     if (thisTex && thisTex->internalHasPendingIO()) {
180         return true;
181     }
182     const GrRenderTarget* thisRT = this->asRenderTarget();
183     if (thisRT && thisRT->internalHasPendingIO()) {
184         return true;
185     }
186     return false;
187 }
188 
onRelease()189 void GrSurface::onRelease() {
190     this->invokeReleaseProc();
191     this->INHERITED::onRelease();
192 }
193 
onAbandon()194 void GrSurface::onAbandon() {
195     this->invokeReleaseProc();
196     this->INHERITED::onAbandon();
197 }
198