GrGpu.cpp revision 02a44a488605112aa6683c9d919e13b188112ce1
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 "GrBufferAllocPool.h" 13#include "GrContext.h" 14#include "GrDrawTargetCaps.h" 15#include "GrGpuResourcePriv.h" 16#include "GrIndexBuffer.h" 17#include "GrResourceCache.h" 18#include "GrStencilBuffer.h" 19#include "GrVertexBuffer.h" 20 21//////////////////////////////////////////////////////////////////////////////// 22 23GrGpu::GrGpu(GrContext* context) 24 : fResetTimestamp(kExpiredTimestamp+1) 25 , fResetBits(kAll_GrBackendState) 26 , fQuadIndexBuffer(NULL) 27 , fContext(context) { 28} 29 30GrGpu::~GrGpu() { 31 SkSafeSetNull(fQuadIndexBuffer); 32} 33 34void GrGpu::contextAbandoned() {} 35 36//////////////////////////////////////////////////////////////////////////////// 37 38GrTexture* GrGpu::createTexture(const GrSurfaceDesc& desc, bool budgeted, 39 const void* srcData, size_t rowBytes) { 40 if (!this->caps()->isConfigTexturable(desc.fConfig)) { 41 return NULL; 42 } 43 44 bool isRT = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag); 45 if (isRT && !this->caps()->isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) { 46 return NULL; 47 } 48 49 GrTexture *tex = NULL; 50 if (GrPixelConfigIsCompressed(desc.fConfig)) { 51 // We shouldn't be rendering into this 52 SkASSERT((desc.fFlags & kRenderTarget_GrSurfaceFlag) == 0); 53 54 if (!this->caps()->npotTextureTileSupport() && 55 (!SkIsPow2(desc.fWidth) || !SkIsPow2(desc.fHeight))) { 56 return NULL; 57 } 58 59 this->handleDirtyContext(); 60 tex = this->onCreateCompressedTexture(desc, budgeted, srcData); 61 } else { 62 this->handleDirtyContext(); 63 tex = this->onCreateTexture(desc, budgeted, srcData, rowBytes); 64 if (tex && 65 (kRenderTarget_GrSurfaceFlag & desc.fFlags) && 66 !(kNoStencil_GrSurfaceFlag & desc.fFlags)) { 67 SkASSERT(tex->asRenderTarget()); 68 // TODO: defer this and attach dynamically 69 if (!this->attachStencilBufferToRenderTarget(tex->asRenderTarget())) { 70 tex->unref(); 71 return NULL; 72 } 73 } 74 } 75 if (!this->caps()->reuseScratchTextures() && !isRT) { 76 tex->resourcePriv().removeScratchKey(); 77 } 78 if (tex) { 79 fStats.incTextureCreates(); 80 if (srcData) { 81 fStats.incTextureUploads(); 82 } 83 } 84 return tex; 85} 86 87bool GrGpu::attachStencilBufferToRenderTarget(GrRenderTarget* rt) { 88 SkASSERT(NULL == rt->getStencilBuffer()); 89 GrUniqueKey sbKey; 90 GrStencilBuffer::ComputeSharedStencilBufferKey(rt->width(), rt->height(), rt->numSamples(), 91 &sbKey); 92 SkAutoTUnref<GrStencilBuffer> sb(static_cast<GrStencilBuffer*>( 93 this->getContext()->getResourceCache()->findAndRefUniqueResource(sbKey))); 94 if (sb) { 95 rt->setStencilBuffer(sb); 96 bool attached = this->attachStencilBufferToRenderTarget(sb, rt); 97 if (!attached) { 98 rt->setStencilBuffer(NULL); 99 } 100 return attached; 101 } 102 if (this->createStencilBufferForRenderTarget(rt, rt->width(), rt->height())) { 103 // Right now we're clearing the stencil buffer here after it is 104 // attached to an RT for the first time. When we start matching 105 // stencil buffers with smaller color targets this will no longer 106 // be correct because it won't be guaranteed to clear the entire 107 // sb. 108 // We used to clear down in the GL subclass using a special purpose 109 // FBO. But iOS doesn't allow a stencil-only FBO. It reports unsupported 110 // FBO status. 111 this->clearStencil(rt); 112 rt->getStencilBuffer()->resourcePriv().setUniqueKey(sbKey); 113 return true; 114 } else { 115 return false; 116 } 117} 118 119GrTexture* GrGpu::wrapBackendTexture(const GrBackendTextureDesc& desc) { 120 this->handleDirtyContext(); 121 GrTexture* tex = this->onWrapBackendTexture(desc); 122 if (NULL == tex) { 123 return NULL; 124 } 125 // TODO: defer this and attach dynamically 126 GrRenderTarget* tgt = tex->asRenderTarget(); 127 if (tgt && !this->attachStencilBufferToRenderTarget(tgt)) { 128 tex->unref(); 129 return NULL; 130 } else { 131 return tex; 132 } 133} 134 135GrRenderTarget* GrGpu::wrapBackendRenderTarget(const GrBackendRenderTargetDesc& desc) { 136 this->handleDirtyContext(); 137 return this->onWrapBackendRenderTarget(desc); 138} 139 140GrVertexBuffer* GrGpu::createVertexBuffer(size_t size, bool dynamic) { 141 this->handleDirtyContext(); 142 return this->onCreateVertexBuffer(size, dynamic); 143} 144 145GrIndexBuffer* GrGpu::createIndexBuffer(size_t size, bool dynamic) { 146 this->handleDirtyContext(); 147 return this->onCreateIndexBuffer(size, dynamic); 148} 149 150GrIndexBuffer* GrGpu::createInstancedIndexBuffer(const uint16_t* pattern, 151 int patternSize, 152 int reps, 153 int vertCount, 154 bool isDynamic) { 155 size_t bufferSize = patternSize * reps * sizeof(uint16_t); 156 GrGpu* me = const_cast<GrGpu*>(this); 157 GrIndexBuffer* buffer = me->createIndexBuffer(bufferSize, isDynamic); 158 if (buffer) { 159 uint16_t* data = (uint16_t*) buffer->map(); 160 bool useTempData = (NULL == data); 161 if (useTempData) { 162 data = SkNEW_ARRAY(uint16_t, reps * patternSize); 163 } 164 for (int i = 0; i < reps; ++i) { 165 int baseIdx = i * patternSize; 166 uint16_t baseVert = (uint16_t)(i * vertCount); 167 for (int j = 0; j < patternSize; ++j) { 168 data[baseIdx+j] = baseVert + pattern[j]; 169 } 170 } 171 if (useTempData) { 172 if (!buffer->updateData(data, bufferSize)) { 173 SkFAIL("Can't get indices into buffer!"); 174 } 175 SkDELETE_ARRAY(data); 176 } else { 177 buffer->unmap(); 178 } 179 } 180 return buffer; 181} 182 183void GrGpu::clear(const SkIRect* rect, 184 GrColor color, 185 bool canIgnoreRect, 186 GrRenderTarget* renderTarget) { 187 SkASSERT(renderTarget); 188 this->handleDirtyContext(); 189 this->onClear(renderTarget, rect, color, canIgnoreRect); 190} 191 192void GrGpu::clearStencilClip(const SkIRect& rect, 193 bool insideClip, 194 GrRenderTarget* renderTarget) { 195 SkASSERT(renderTarget); 196 this->handleDirtyContext(); 197 this->onClearStencilClip(renderTarget, rect, insideClip); 198} 199 200bool GrGpu::readPixels(GrRenderTarget* target, 201 int left, int top, int width, int height, 202 GrPixelConfig config, void* buffer, 203 size_t rowBytes) { 204 this->handleDirtyContext(); 205 return this->onReadPixels(target, left, top, width, height, 206 config, buffer, rowBytes); 207} 208 209bool GrGpu::writeTexturePixels(GrTexture* texture, 210 int left, int top, int width, int height, 211 GrPixelConfig config, const void* buffer, 212 size_t rowBytes) { 213 this->handleDirtyContext(); 214 if (this->onWriteTexturePixels(texture, left, top, width, height, 215 config, buffer, rowBytes)) { 216 fStats.incTextureUploads(); 217 return true; 218 } 219 return false; 220} 221 222void GrGpu::resolveRenderTarget(GrRenderTarget* target) { 223 SkASSERT(target); 224 this->handleDirtyContext(); 225 this->onResolveRenderTarget(target); 226} 227 228typedef GrTraceMarkerSet::Iter TMIter; 229void GrGpu::saveActiveTraceMarkers() { 230 if (this->caps()->gpuTracingSupport()) { 231 SkASSERT(0 == fStoredTraceMarkers.count()); 232 fStoredTraceMarkers.addSet(fActiveTraceMarkers); 233 for (TMIter iter = fStoredTraceMarkers.begin(); iter != fStoredTraceMarkers.end(); ++iter) { 234 this->removeGpuTraceMarker(&(*iter)); 235 } 236 } 237} 238 239void GrGpu::restoreActiveTraceMarkers() { 240 if (this->caps()->gpuTracingSupport()) { 241 SkASSERT(0 == fActiveTraceMarkers.count()); 242 for (TMIter iter = fStoredTraceMarkers.begin(); iter != fStoredTraceMarkers.end(); ++iter) { 243 this->addGpuTraceMarker(&(*iter)); 244 } 245 for (TMIter iter = fActiveTraceMarkers.begin(); iter != fActiveTraceMarkers.end(); ++iter) { 246 this->fStoredTraceMarkers.remove(*iter); 247 } 248 } 249} 250 251void GrGpu::addGpuTraceMarker(const GrGpuTraceMarker* marker) { 252 if (this->caps()->gpuTracingSupport()) { 253 SkASSERT(fGpuTraceMarkerCount >= 0); 254 this->fActiveTraceMarkers.add(*marker); 255 this->didAddGpuTraceMarker(); 256 ++fGpuTraceMarkerCount; 257 } 258} 259 260void GrGpu::removeGpuTraceMarker(const GrGpuTraceMarker* marker) { 261 if (this->caps()->gpuTracingSupport()) { 262 SkASSERT(fGpuTraceMarkerCount >= 1); 263 this->fActiveTraceMarkers.remove(*marker); 264 this->didRemoveGpuTraceMarker(); 265 --fGpuTraceMarkerCount; 266 } 267} 268 269//////////////////////////////////////////////////////////////////////////////// 270 271static const int MAX_QUADS = 1 << 12; // max possible: (1 << 14) - 1; 272 273GR_STATIC_ASSERT(4 * MAX_QUADS <= 65535); 274 275static const uint16_t gQuadIndexPattern[] = { 276 0, 1, 2, 0, 2, 3 277}; 278 279const GrIndexBuffer* GrGpu::getQuadIndexBuffer() const { 280 if (NULL == fQuadIndexBuffer || fQuadIndexBuffer->wasDestroyed()) { 281 SkSafeUnref(fQuadIndexBuffer); 282 GrGpu* me = const_cast<GrGpu*>(this); 283 fQuadIndexBuffer = me->createInstancedIndexBuffer(gQuadIndexPattern, 284 6, 285 MAX_QUADS, 286 4); 287 } 288 289 return fQuadIndexBuffer; 290} 291 292//////////////////////////////////////////////////////////////////////////////// 293 294void GrGpu::draw(const DrawArgs& args, const GrDrawTarget::DrawInfo& info) { 295 this->handleDirtyContext(); 296 this->onDraw(args, info); 297} 298 299void GrGpu::stencilPath(const GrPath* path, const StencilPathState& state) { 300 this->handleDirtyContext(); 301 this->onStencilPath(path, state); 302} 303 304void GrGpu::drawPath(const DrawArgs& args, 305 const GrPath* path, 306 const GrStencilSettings& stencilSettings) { 307 this->handleDirtyContext(); 308 this->onDrawPath(args, path, stencilSettings); 309} 310 311void GrGpu::drawPaths(const DrawArgs& args, 312 const GrPathRange* pathRange, 313 const void* indices, 314 GrDrawTarget::PathIndexType indexType, 315 const float transformValues[], 316 GrDrawTarget::PathTransformType transformType, 317 int count, 318 const GrStencilSettings& stencilSettings) { 319 this->handleDirtyContext(); 320 pathRange->willDrawPaths(indices, indexType, count); 321 this->onDrawPaths(args, pathRange, indices, indexType, transformValues, 322 transformType, count, stencilSettings); 323} 324