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 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 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 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 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 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 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 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 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 166 void GrSurface::flushWrites() { 167 if (!this->wasDestroyed()) { 168 this->getContext()->flushSurfaceWrites(this); 169 } 170 } 171 172 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 184 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 196 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 208 void GrSurface::onRelease() { 209 this->invokeReleaseProc(); 210 this->INHERITED::onRelease(); 211 } 212 213 void GrSurface::onAbandon() { 214 this->invokeReleaseProc(); 215 this->INHERITED::onAbandon(); 216 } 217 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