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 "GrOpList.h"
11 #include "GrSurfacePriv.h"
12 #include "GrTexture.h"
13 
14 #include "SkGr.h"
15 #include "SkMathPriv.h"
16 
~GrSurface()17 GrSurface::~GrSurface() {
18     if (fLastOpList) {
19         fLastOpList->clearTarget();
20     }
21     SkSafeUnref(fLastOpList);
22 
23     // check that invokeReleaseProc has been called (if needed)
24     SkASSERT(NULL == fReleaseProc);
25 }
26 
WorstCaseSize(const GrSurfaceDesc & desc,bool useNextPow2)27 size_t GrSurface::WorstCaseSize(const GrSurfaceDesc& desc, bool useNextPow2) {
28     size_t size;
29 
30     int width = useNextPow2 ? GrNextPow2(desc.fWidth) : desc.fWidth;
31     int height = useNextPow2 ? GrNextPow2(desc.fHeight) : desc.fHeight;
32 
33     bool isRenderTarget = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag);
34     if (isRenderTarget) {
35         // We own one color value for each MSAA sample.
36         int colorValuesPerPixel = SkTMax(1, desc.fSampleCnt);
37         if (desc.fSampleCnt) {
38             // Worse case, we own the resolve buffer so that is one more sample per pixel.
39             colorValuesPerPixel += 1;
40         }
41         SkASSERT(kUnknown_GrPixelConfig != desc.fConfig);
42         SkASSERT(!GrPixelConfigIsCompressed(desc.fConfig));
43         size_t colorBytes = (size_t) width * height * GrBytesPerPixel(desc.fConfig);
44 
45         // This would be a nice assert to have (i.e., we aren't creating 0 width/height surfaces).
46         // Unfortunately Chromium seems to want to do this.
47         //SkASSERT(colorBytes > 0);
48 
49         size = colorValuesPerPixel * colorBytes;
50         size += colorBytes/3; // in case we have to mipmap
51     } else {
52         if (GrPixelConfigIsCompressed(desc.fConfig)) {
53             size = GrCompressedFormatDataSize(desc.fConfig, width, height);
54         } else {
55             size = (size_t) width * height * GrBytesPerPixel(desc.fConfig);
56         }
57 
58         size += size/3;  // in case we have to mipmap
59     }
60 
61     return size;
62 }
63 
ComputeSize(const GrSurfaceDesc & desc,int colorSamplesPerPixel,bool hasMIPMaps,bool useNextPow2)64 size_t GrSurface::ComputeSize(const GrSurfaceDesc& desc,
65                               int colorSamplesPerPixel,
66                               bool hasMIPMaps,
67                               bool useNextPow2) {
68     size_t colorSize;
69 
70     int width = useNextPow2 ? GrNextPow2(desc.fWidth) : desc.fWidth;
71     int height = useNextPow2 ? GrNextPow2(desc.fHeight) : desc.fHeight;
72 
73     SkASSERT(kUnknown_GrPixelConfig != desc.fConfig);
74     if (GrPixelConfigIsCompressed(desc.fConfig)) {
75         colorSize = GrCompressedFormatDataSize(desc.fConfig, width, height);
76     } else {
77         colorSize = (size_t) width * height * GrBytesPerPixel(desc.fConfig);
78     }
79     SkASSERT(colorSize > 0);
80 
81     size_t finalSize = colorSamplesPerPixel * colorSize;
82 
83     if (hasMIPMaps) {
84         // We don't have to worry about the mipmaps being a different size than
85         // we'd expect because we never change fDesc.fWidth/fHeight.
86         finalSize += colorSize/3;
87     }
88 
89     SkASSERT(finalSize <= WorstCaseSize(desc, useNextPow2));
90     return finalSize;
91 }
92 
adjust_params(int surfaceWidth,int surfaceHeight,size_t bpp,int * left,int * top,int * width,int * height,T ** data,size_t * rowBytes)93 template<typename T> static bool adjust_params(int surfaceWidth,
94                                                int surfaceHeight,
95                                                size_t bpp,
96                                                int* left, int* top, int* width, int* height,
97                                                T** data,
98                                                size_t* rowBytes) {
99     if (!*rowBytes) {
100         *rowBytes = *width * bpp;
101     }
102 
103     SkIRect subRect = SkIRect::MakeXYWH(*left, *top, *width, *height);
104     SkIRect bounds = SkIRect::MakeWH(surfaceWidth, surfaceHeight);
105 
106     if (!subRect.intersect(bounds)) {
107         return false;
108     }
109     *data = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(*data) +
110             (subRect.fTop - *top) * *rowBytes + (subRect.fLeft - *left) * bpp);
111 
112     *left = subRect.fLeft;
113     *top = subRect.fTop;
114     *width = subRect.width();
115     *height = subRect.height();
116     return true;
117 }
118 
AdjustReadPixelParams(int surfaceWidth,int surfaceHeight,size_t bpp,int * left,int * top,int * width,int * height,void ** data,size_t * rowBytes)119 bool GrSurfacePriv::AdjustReadPixelParams(int surfaceWidth,
120                                           int surfaceHeight,
121                                           size_t bpp,
122                                           int* left, int* top, int* width, int* height,
123                                           void** data,
124                                           size_t* rowBytes) {
125     return adjust_params<void>(surfaceWidth, surfaceHeight, bpp, left, top, width, height, data,
126                                rowBytes);
127 }
128 
AdjustWritePixelParams(int surfaceWidth,int surfaceHeight,size_t bpp,int * left,int * top,int * width,int * height,const void ** data,size_t * rowBytes)129 bool GrSurfacePriv::AdjustWritePixelParams(int surfaceWidth,
130                                            int surfaceHeight,
131                                            size_t bpp,
132                                            int* left, int* top, int* width, int* height,
133                                            const void** data,
134                                            size_t* rowBytes) {
135     return adjust_params<const void>(surfaceWidth, surfaceHeight, bpp, left, top, width, height,
136                                      data, rowBytes);
137 }
138 
139 
140 //////////////////////////////////////////////////////////////////////////////
141 
writePixels(SkColorSpace * dstColorSpace,int left,int top,int width,int height,GrPixelConfig config,SkColorSpace * srcColorSpace,const void * buffer,size_t rowBytes,uint32_t pixelOpsFlags)142 bool GrSurface::writePixels(SkColorSpace* dstColorSpace, int left, int top, int width, int height,
143                             GrPixelConfig config, SkColorSpace* srcColorSpace, const void* buffer,
144                             size_t rowBytes, uint32_t pixelOpsFlags) {
145     // go through context so that all necessary flushing occurs
146     GrContext* context = this->getContext();
147     if (nullptr == context) {
148         return false;
149     }
150     return context->writeSurfacePixels(this, dstColorSpace, left, top, width, height, config,
151                                        srcColorSpace, buffer, rowBytes, pixelOpsFlags);
152 }
153 
readPixels(SkColorSpace * srcColorSpace,int left,int top,int width,int height,GrPixelConfig config,SkColorSpace * dstColorSpace,void * buffer,size_t rowBytes,uint32_t pixelOpsFlags)154 bool GrSurface::readPixels(SkColorSpace* srcColorSpace, int left, int top, int width, int height,
155                            GrPixelConfig config, SkColorSpace* dstColorSpace, void* buffer,
156                            size_t rowBytes, uint32_t pixelOpsFlags) {
157     // go through context so that all necessary flushing occurs
158     GrContext* context = this->getContext();
159     if (nullptr == context) {
160         return false;
161     }
162     return context->readSurfacePixels(this, srcColorSpace, left, top, width, height, config,
163                                       dstColorSpace, buffer, rowBytes, pixelOpsFlags);
164 }
165 
flushWrites()166 void GrSurface::flushWrites() {
167     if (!this->wasDestroyed()) {
168         this->getContext()->flushSurfaceWrites(this);
169     }
170 }
171 
hasPendingRead() const172 bool GrSurface::hasPendingRead() const {
173     const GrTexture* thisTex = this->asTexture();
174     if (thisTex && thisTex->internalHasPendingRead()) {
175         return true;
176     }
177     const GrRenderTarget* thisRT = this->asRenderTarget();
178     if (thisRT && thisRT->internalHasPendingRead()) {
179         return true;
180     }
181     return false;
182 }
183 
hasPendingWrite() const184 bool GrSurface::hasPendingWrite() const {
185     const GrTexture* thisTex = this->asTexture();
186     if (thisTex && thisTex->internalHasPendingWrite()) {
187         return true;
188     }
189     const GrRenderTarget* thisRT = this->asRenderTarget();
190     if (thisRT && thisRT->internalHasPendingWrite()) {
191         return true;
192     }
193     return false;
194 }
195 
hasPendingIO() const196 bool GrSurface::hasPendingIO() const {
197     const GrTexture* thisTex = this->asTexture();
198     if (thisTex && thisTex->internalHasPendingIO()) {
199         return true;
200     }
201     const GrRenderTarget* thisRT = this->asRenderTarget();
202     if (thisRT && thisRT->internalHasPendingIO()) {
203         return true;
204     }
205     return false;
206 }
207 
onRelease()208 void GrSurface::onRelease() {
209     this->invokeReleaseProc();
210     this->INHERITED::onRelease();
211 }
212 
onAbandon()213 void GrSurface::onAbandon() {
214     this->invokeReleaseProc();
215     this->INHERITED::onAbandon();
216 }
217 
setLastOpList(GrOpList * opList)218 void GrSurface::setLastOpList(GrOpList* opList) {
219     if (fLastOpList) {
220         // The non-MDB world never closes so we can't check this condition
221 #ifdef ENABLE_MDB
222         SkASSERT(fLastOpList->isClosed());
223 #endif
224         fLastOpList->clearTarget();
225     }
226 
227     SkRefCnt_SafeAssign(fLastOpList, opList);
228 }
229