1 2 /* 3 * Copyright 2010 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 10 #include "GrGpu.h" 11 12 #include "GrContext.h" 13 #include "GrDrawTargetCaps.h" 14 #include "GrGpuResourcePriv.h" 15 #include "GrIndexBuffer.h" 16 #include "GrResourceCache.h" 17 #include "GrRenderTargetPriv.h" 18 #include "GrStencilAttachment.h" 19 #include "GrVertexBuffer.h" 20 #include "GrVertices.h" 21 22 GrVertices& GrVertices::operator =(const GrVertices& di) { 23 fPrimitiveType = di.fPrimitiveType; 24 fStartVertex = di.fStartVertex; 25 fStartIndex = di.fStartIndex; 26 fVertexCount = di.fVertexCount; 27 fIndexCount = di.fIndexCount; 28 29 fInstanceCount = di.fInstanceCount; 30 fVerticesPerInstance = di.fVerticesPerInstance; 31 fIndicesPerInstance = di.fIndicesPerInstance; 32 fMaxInstancesPerDraw = di.fMaxInstancesPerDraw; 33 34 fVertexBuffer.reset(di.vertexBuffer()); 35 fIndexBuffer.reset(di.indexBuffer()); 36 37 return *this; 38 } 39 40 //////////////////////////////////////////////////////////////////////////////// 41 42 GrGpu::GrGpu(GrContext* context) 43 : fResetTimestamp(kExpiredTimestamp+1) 44 , fResetBits(kAll_GrBackendState) 45 , fGpuTraceMarkerCount(0) 46 , fContext(context) { 47 } 48 49 GrGpu::~GrGpu() {} 50 51 void GrGpu::contextAbandoned() {} 52 53 //////////////////////////////////////////////////////////////////////////////// 54 55 static GrSurfaceOrigin resolve_origin(GrSurfaceOrigin origin, bool renderTarget) { 56 // By default, GrRenderTargets are GL's normal orientation so that they 57 // can be drawn to by the outside world without the client having 58 // to render upside down. 59 if (kDefault_GrSurfaceOrigin == origin) { 60 return renderTarget ? kBottomLeft_GrSurfaceOrigin : kTopLeft_GrSurfaceOrigin; 61 } else { 62 return origin; 63 } 64 } 65 66 GrTexture* GrGpu::createTexture(const GrSurfaceDesc& origDesc, bool budgeted, 67 const void* srcData, size_t rowBytes) { 68 GrSurfaceDesc desc = origDesc; 69 70 if (!this->caps()->isConfigTexturable(desc.fConfig)) { 71 return NULL; 72 } 73 74 bool isRT = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag); 75 if (isRT && !this->caps()->isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) { 76 return NULL; 77 } 78 79 // We currently not support multisampled textures 80 if (!isRT && desc.fSampleCnt > 0) { 81 return NULL; 82 } 83 84 GrTexture *tex = NULL; 85 86 if (isRT) { 87 int maxRTSize = this->caps()->maxRenderTargetSize(); 88 if (desc.fWidth > maxRTSize || desc.fHeight > maxRTSize) { 89 return NULL; 90 } 91 } else { 92 int maxSize = this->caps()->maxTextureSize(); 93 if (desc.fWidth > maxSize || desc.fHeight > maxSize) { 94 return NULL; 95 } 96 } 97 98 GrGpuResource::LifeCycle lifeCycle = budgeted ? GrGpuResource::kCached_LifeCycle : 99 GrGpuResource::kUncached_LifeCycle; 100 101 desc.fSampleCnt = SkTMin(desc.fSampleCnt, this->caps()->maxSampleCount()); 102 // Attempt to catch un- or wrongly initialized sample counts; 103 SkASSERT(desc.fSampleCnt >= 0 && desc.fSampleCnt <= 64); 104 105 desc.fOrigin = resolve_origin(desc.fOrigin, isRT); 106 107 if (GrPixelConfigIsCompressed(desc.fConfig)) { 108 // We shouldn't be rendering into this 109 SkASSERT(!isRT); 110 SkASSERT(0 == desc.fSampleCnt); 111 112 if (!this->caps()->npotTextureTileSupport() && 113 (!SkIsPow2(desc.fWidth) || !SkIsPow2(desc.fHeight))) { 114 return NULL; 115 } 116 117 this->handleDirtyContext(); 118 tex = this->onCreateCompressedTexture(desc, lifeCycle, srcData); 119 } else { 120 this->handleDirtyContext(); 121 tex = this->onCreateTexture(desc, lifeCycle, srcData, rowBytes); 122 } 123 if (!this->caps()->reuseScratchTextures() && !isRT) { 124 tex->resourcePriv().removeScratchKey(); 125 } 126 if (tex) { 127 fStats.incTextureCreates(); 128 if (srcData) { 129 fStats.incTextureUploads(); 130 } 131 } 132 return tex; 133 } 134 135 bool GrGpu::attachStencilAttachmentToRenderTarget(GrRenderTarget* rt) { 136 SkASSERT(NULL == rt->renderTargetPriv().getStencilAttachment()); 137 GrUniqueKey sbKey; 138 139 int width = rt->width(); 140 int height = rt->height(); 141 #if 0 142 if (this->caps()->oversizedStencilSupport()) { 143 width = SkNextPow2(width); 144 height = SkNextPow2(height); 145 } 146 #endif 147 148 GrStencilAttachment::ComputeSharedStencilAttachmentKey(width, height, rt->numSamples(), &sbKey); 149 SkAutoTUnref<GrStencilAttachment> sb(static_cast<GrStencilAttachment*>( 150 this->getContext()->getResourceCache()->findAndRefUniqueResource(sbKey))); 151 if (sb) { 152 if (this->attachStencilAttachmentToRenderTarget(sb, rt)) { 153 rt->renderTargetPriv().didAttachStencilAttachment(sb); 154 return true; 155 } 156 return false; 157 } 158 if (this->createStencilAttachmentForRenderTarget(rt, width, height)) { 159 // Right now we're clearing the stencil buffer here after it is 160 // attached to an RT for the first time. When we start matching 161 // stencil buffers with smaller color targets this will no longer 162 // be correct because it won't be guaranteed to clear the entire 163 // sb. 164 // We used to clear down in the GL subclass using a special purpose 165 // FBO. But iOS doesn't allow a stencil-only FBO. It reports unsupported 166 // FBO status. 167 this->clearStencil(rt); 168 GrStencilAttachment* sb = rt->renderTargetPriv().getStencilAttachment(); 169 sb->resourcePriv().setUniqueKey(sbKey); 170 return true; 171 } else { 172 return false; 173 } 174 } 175 176 GrTexture* GrGpu::wrapBackendTexture(const GrBackendTextureDesc& desc) { 177 this->handleDirtyContext(); 178 GrTexture* tex = this->onWrapBackendTexture(desc); 179 if (NULL == tex) { 180 return NULL; 181 } 182 // TODO: defer this and attach dynamically 183 GrRenderTarget* tgt = tex->asRenderTarget(); 184 if (tgt && !this->attachStencilAttachmentToRenderTarget(tgt)) { 185 tex->unref(); 186 return NULL; 187 } else { 188 return tex; 189 } 190 } 191 192 GrRenderTarget* GrGpu::wrapBackendRenderTarget(const GrBackendRenderTargetDesc& desc) { 193 this->handleDirtyContext(); 194 return this->onWrapBackendRenderTarget(desc); 195 } 196 197 GrVertexBuffer* GrGpu::createVertexBuffer(size_t size, bool dynamic) { 198 this->handleDirtyContext(); 199 return this->onCreateVertexBuffer(size, dynamic); 200 } 201 202 GrIndexBuffer* GrGpu::createIndexBuffer(size_t size, bool dynamic) { 203 this->handleDirtyContext(); 204 return this->onCreateIndexBuffer(size, dynamic); 205 } 206 207 void GrGpu::clear(const SkIRect* rect, 208 GrColor color, 209 bool canIgnoreRect, 210 GrRenderTarget* renderTarget) { 211 SkASSERT(renderTarget); 212 this->handleDirtyContext(); 213 this->onClear(renderTarget, rect, color, canIgnoreRect); 214 } 215 216 void GrGpu::clearStencilClip(const SkIRect& rect, 217 bool insideClip, 218 GrRenderTarget* renderTarget) { 219 SkASSERT(renderTarget); 220 this->handleDirtyContext(); 221 this->onClearStencilClip(renderTarget, rect, insideClip); 222 } 223 224 bool GrGpu::readPixels(GrRenderTarget* target, 225 int left, int top, int width, int height, 226 GrPixelConfig config, void* buffer, 227 size_t rowBytes) { 228 this->handleDirtyContext(); 229 return this->onReadPixels(target, left, top, width, height, 230 config, buffer, rowBytes); 231 } 232 233 bool GrGpu::writeTexturePixels(GrTexture* texture, 234 int left, int top, int width, int height, 235 GrPixelConfig config, const void* buffer, 236 size_t rowBytes) { 237 this->handleDirtyContext(); 238 if (this->onWriteTexturePixels(texture, left, top, width, height, 239 config, buffer, rowBytes)) { 240 fStats.incTextureUploads(); 241 return true; 242 } 243 return false; 244 } 245 246 void GrGpu::resolveRenderTarget(GrRenderTarget* target) { 247 SkASSERT(target); 248 this->handleDirtyContext(); 249 this->onResolveRenderTarget(target); 250 } 251 252 typedef GrTraceMarkerSet::Iter TMIter; 253 void GrGpu::saveActiveTraceMarkers() { 254 if (this->caps()->gpuTracingSupport()) { 255 SkASSERT(0 == fStoredTraceMarkers.count()); 256 fStoredTraceMarkers.addSet(fActiveTraceMarkers); 257 for (TMIter iter = fStoredTraceMarkers.begin(); iter != fStoredTraceMarkers.end(); ++iter) { 258 this->removeGpuTraceMarker(&(*iter)); 259 } 260 } 261 } 262 263 void GrGpu::restoreActiveTraceMarkers() { 264 if (this->caps()->gpuTracingSupport()) { 265 SkASSERT(0 == fActiveTraceMarkers.count()); 266 for (TMIter iter = fStoredTraceMarkers.begin(); iter != fStoredTraceMarkers.end(); ++iter) { 267 this->addGpuTraceMarker(&(*iter)); 268 } 269 for (TMIter iter = fActiveTraceMarkers.begin(); iter != fActiveTraceMarkers.end(); ++iter) { 270 this->fStoredTraceMarkers.remove(*iter); 271 } 272 } 273 } 274 275 void GrGpu::addGpuTraceMarker(const GrGpuTraceMarker* marker) { 276 if (this->caps()->gpuTracingSupport()) { 277 SkASSERT(fGpuTraceMarkerCount >= 0); 278 this->fActiveTraceMarkers.add(*marker); 279 this->didAddGpuTraceMarker(); 280 ++fGpuTraceMarkerCount; 281 } 282 } 283 284 void GrGpu::removeGpuTraceMarker(const GrGpuTraceMarker* marker) { 285 if (this->caps()->gpuTracingSupport()) { 286 SkASSERT(fGpuTraceMarkerCount >= 1); 287 this->fActiveTraceMarkers.remove(*marker); 288 this->didRemoveGpuTraceMarker(); 289 --fGpuTraceMarkerCount; 290 } 291 } 292 293 //////////////////////////////////////////////////////////////////////////////// 294 295 void GrGpu::draw(const DrawArgs& args, const GrVertices& vertices) { 296 this->handleDirtyContext(); 297 GrVertices::Iterator iter; 298 const GrNonInstancedVertices* verts = iter.init(vertices); 299 do { 300 this->onDraw(args, *verts); 301 } while ((verts = iter.next())); 302 } 303 304 void GrGpu::stencilPath(const GrPath* path, const StencilPathState& state) { 305 this->handleDirtyContext(); 306 this->onStencilPath(path, state); 307 } 308 309 void GrGpu::drawPath(const DrawArgs& args, 310 const GrPath* path, 311 const GrStencilSettings& stencilSettings) { 312 this->handleDirtyContext(); 313 this->onDrawPath(args, path, stencilSettings); 314 } 315 316 void GrGpu::drawPaths(const DrawArgs& args, 317 const GrPathRange* pathRange, 318 const void* indices, 319 GrDrawTarget::PathIndexType indexType, 320 const float transformValues[], 321 GrDrawTarget::PathTransformType transformType, 322 int count, 323 const GrStencilSettings& stencilSettings) { 324 this->handleDirtyContext(); 325 pathRange->willDrawPaths(indices, indexType, count); 326 this->onDrawPaths(args, pathRange, indices, indexType, transformValues, 327 transformType, count, stencilSettings); 328 } 329