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 22GrVertices& 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 42GrGpu::GrGpu(GrContext* context) 43 : fResetTimestamp(kExpiredTimestamp+1) 44 , fResetBits(kAll_GrBackendState) 45 , fGpuTraceMarkerCount(0) 46 , fContext(context) { 47} 48 49GrGpu::~GrGpu() {} 50 51void GrGpu::contextAbandoned() {} 52 53//////////////////////////////////////////////////////////////////////////////// 54 55static 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 66GrTexture* 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 135bool 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 176GrTexture* 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 192GrRenderTarget* GrGpu::wrapBackendRenderTarget(const GrBackendRenderTargetDesc& desc) { 193 this->handleDirtyContext(); 194 return this->onWrapBackendRenderTarget(desc); 195} 196 197GrVertexBuffer* GrGpu::createVertexBuffer(size_t size, bool dynamic) { 198 this->handleDirtyContext(); 199 return this->onCreateVertexBuffer(size, dynamic); 200} 201 202GrIndexBuffer* GrGpu::createIndexBuffer(size_t size, bool dynamic) { 203 this->handleDirtyContext(); 204 return this->onCreateIndexBuffer(size, dynamic); 205} 206 207void 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 216void 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 224bool 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 233bool 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 246void GrGpu::resolveRenderTarget(GrRenderTarget* target) { 247 SkASSERT(target); 248 this->handleDirtyContext(); 249 this->onResolveRenderTarget(target); 250} 251 252typedef GrTraceMarkerSet::Iter TMIter; 253void 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 263void 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 275void 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 284void 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 295void 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 304void GrGpu::stencilPath(const GrPath* path, const StencilPathState& state) { 305 this->handleDirtyContext(); 306 this->onStencilPath(path, state); 307} 308 309void GrGpu::drawPath(const DrawArgs& args, 310 const GrPath* path, 311 const GrStencilSettings& stencilSettings) { 312 this->handleDirtyContext(); 313 this->onDrawPath(args, path, stencilSettings); 314} 315 316void 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