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