1 /* 2 * Copyright 2011 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 "GrGpuGL.h" 9 10 #include "GrProcessor.h" 11 #include "GrGLProcessor.h" 12 #include "GrGLPathRendering.h" 13 #include "GrOptDrawState.h" 14 #include "SkRTConf.h" 15 #include "SkTSearch.h" 16 17 #ifdef PROGRAM_CACHE_STATS 18 SK_CONF_DECLARE(bool, c_DisplayCache, "gpu.displayCache", false, 19 "Display program cache usage."); 20 #endif 21 22 typedef GrGLProgramDataManager::UniformHandle UniformHandle; 23 24 struct GrGpuGL::ProgramCache::Entry { 25 SK_DECLARE_INST_COUNT_ROOT(Entry); 26 Entry() : fProgram(NULL), fLRUStamp(0) {} 27 28 SkAutoTUnref<GrGLProgram> fProgram; 29 unsigned int fLRUStamp; 30 }; 31 32 struct GrGpuGL::ProgramCache::ProgDescLess { 33 bool operator() (const GrGLProgramDesc& desc, const Entry* entry) { 34 SkASSERT(entry->fProgram.get()); 35 return GrGLProgramDesc::Less(desc, entry->fProgram->getDesc()); 36 } 37 38 bool operator() (const Entry* entry, const GrGLProgramDesc& desc) { 39 SkASSERT(entry->fProgram.get()); 40 return GrGLProgramDesc::Less(entry->fProgram->getDesc(), desc); 41 } 42 }; 43 44 GrGpuGL::ProgramCache::ProgramCache(GrGpuGL* gpu) 45 : fCount(0) 46 , fCurrLRUStamp(0) 47 , fGpu(gpu) 48 #ifdef PROGRAM_CACHE_STATS 49 , fTotalRequests(0) 50 , fCacheMisses(0) 51 , fHashMisses(0) 52 #endif 53 { 54 for (int i = 0; i < 1 << kHashBits; ++i) { 55 fHashTable[i] = NULL; 56 } 57 } 58 59 GrGpuGL::ProgramCache::~ProgramCache() { 60 for (int i = 0; i < fCount; ++i){ 61 SkDELETE(fEntries[i]); 62 } 63 // dump stats 64 #ifdef PROGRAM_CACHE_STATS 65 if (c_DisplayCache) { 66 SkDebugf("--- Program Cache ---\n"); 67 SkDebugf("Total requests: %d\n", fTotalRequests); 68 SkDebugf("Cache misses: %d\n", fCacheMisses); 69 SkDebugf("Cache miss %%: %f\n", (fTotalRequests > 0) ? 70 100.f * fCacheMisses / fTotalRequests : 71 0.f); 72 int cacheHits = fTotalRequests - fCacheMisses; 73 SkDebugf("Hash miss %%: %f\n", (cacheHits > 0) ? 100.f * fHashMisses / cacheHits : 0.f); 74 SkDebugf("---------------------\n"); 75 } 76 #endif 77 } 78 79 void GrGpuGL::ProgramCache::abandon() { 80 for (int i = 0; i < fCount; ++i) { 81 SkASSERT(fEntries[i]->fProgram.get()); 82 fEntries[i]->fProgram->abandon(); 83 SkDELETE(fEntries[i]); 84 } 85 fCount = 0; 86 } 87 88 int GrGpuGL::ProgramCache::search(const GrGLProgramDesc& desc) const { 89 ProgDescLess less; 90 return SkTSearch(fEntries, fCount, desc, sizeof(Entry*), less); 91 } 92 93 GrGLProgram* GrGpuGL::ProgramCache::getProgram(const GrGLProgramDesc& desc, 94 const GrGeometryStage* geometryProcessor, 95 const GrFragmentStage* colorStages[], 96 const GrFragmentStage* coverageStages[]) { 97 #ifdef PROGRAM_CACHE_STATS 98 ++fTotalRequests; 99 #endif 100 101 Entry* entry = NULL; 102 103 uint32_t hashIdx = desc.getChecksum(); 104 hashIdx ^= hashIdx >> 16; 105 if (kHashBits <= 8) { 106 hashIdx ^= hashIdx >> 8; 107 } 108 hashIdx &=((1 << kHashBits) - 1); 109 Entry* hashedEntry = fHashTable[hashIdx]; 110 if (hashedEntry && hashedEntry->fProgram->getDesc() == desc) { 111 SkASSERT(hashedEntry->fProgram); 112 entry = hashedEntry; 113 } 114 115 int entryIdx; 116 if (NULL == entry) { 117 entryIdx = this->search(desc); 118 if (entryIdx >= 0) { 119 entry = fEntries[entryIdx]; 120 #ifdef PROGRAM_CACHE_STATS 121 ++fHashMisses; 122 #endif 123 } 124 } 125 126 if (NULL == entry) { 127 // We have a cache miss 128 #ifdef PROGRAM_CACHE_STATS 129 ++fCacheMisses; 130 #endif 131 GrGLProgram* program = GrGLProgram::Create(fGpu, desc, geometryProcessor, 132 colorStages, coverageStages); 133 if (NULL == program) { 134 return NULL; 135 } 136 int purgeIdx = 0; 137 if (fCount < kMaxEntries) { 138 entry = SkNEW(Entry); 139 purgeIdx = fCount++; 140 fEntries[purgeIdx] = entry; 141 } else { 142 SkASSERT(fCount == kMaxEntries); 143 purgeIdx = 0; 144 for (int i = 1; i < kMaxEntries; ++i) { 145 if (fEntries[i]->fLRUStamp < fEntries[purgeIdx]->fLRUStamp) { 146 purgeIdx = i; 147 } 148 } 149 entry = fEntries[purgeIdx]; 150 int purgedHashIdx = entry->fProgram->getDesc().getChecksum() & ((1 << kHashBits) - 1); 151 if (fHashTable[purgedHashIdx] == entry) { 152 fHashTable[purgedHashIdx] = NULL; 153 } 154 } 155 SkASSERT(fEntries[purgeIdx] == entry); 156 entry->fProgram.reset(program); 157 // We need to shift fEntries around so that the entry currently at purgeIdx is placed 158 // just before the entry at ~entryIdx (in order to keep fEntries sorted by descriptor). 159 entryIdx = ~entryIdx; 160 if (entryIdx < purgeIdx) { 161 // Let E and P be the entries at index entryIdx and purgeIdx, respectively. 162 // If the entries array looks like this: 163 // aaaaEbbbbbPccccc 164 // we rearrange it to look like this: 165 // aaaaPEbbbbbccccc 166 size_t copySize = (purgeIdx - entryIdx) * sizeof(Entry*); 167 memmove(fEntries + entryIdx + 1, fEntries + entryIdx, copySize); 168 fEntries[entryIdx] = entry; 169 } else if (purgeIdx < entryIdx) { 170 // If the entries array looks like this: 171 // aaaaPbbbbbEccccc 172 // we rearrange it to look like this: 173 // aaaabbbbbPEccccc 174 size_t copySize = (entryIdx - purgeIdx - 1) * sizeof(Entry*); 175 memmove(fEntries + purgeIdx, fEntries + purgeIdx + 1, copySize); 176 fEntries[entryIdx - 1] = entry; 177 } 178 #ifdef SK_DEBUG 179 SkASSERT(fEntries[0]->fProgram.get()); 180 for (int i = 0; i < fCount - 1; ++i) { 181 SkASSERT(fEntries[i + 1]->fProgram.get()); 182 const GrGLProgramDesc& a = fEntries[i]->fProgram->getDesc(); 183 const GrGLProgramDesc& b = fEntries[i + 1]->fProgram->getDesc(); 184 SkASSERT(GrGLProgramDesc::Less(a, b)); 185 SkASSERT(!GrGLProgramDesc::Less(b, a)); 186 } 187 #endif 188 } 189 190 fHashTable[hashIdx] = entry; 191 entry->fLRUStamp = fCurrLRUStamp; 192 193 if (SK_MaxU32 == fCurrLRUStamp) { 194 // wrap around! just trash our LRU, one time hit. 195 for (int i = 0; i < fCount; ++i) { 196 fEntries[i]->fLRUStamp = 0; 197 } 198 } 199 ++fCurrLRUStamp; 200 return entry->fProgram; 201 } 202 203 //////////////////////////////////////////////////////////////////////////////// 204 205 #define GL_CALL(X) GR_GL_CALL(this->glInterface(), X) 206 207 bool GrGpuGL::flushGraphicsState(DrawType type, const GrDeviceCoordTexture* dstCopy) { 208 SkAutoTUnref<GrOptDrawState> optState(this->getDrawState().createOptState(*this->caps())); 209 210 // GrGpu::setupClipAndFlushState should have already checked this and bailed if not true. 211 SkASSERT(optState->getRenderTarget()); 212 213 if (kStencilPath_DrawType == type) { 214 const GrRenderTarget* rt = optState->getRenderTarget(); 215 SkISize size; 216 size.set(rt->width(), rt->height()); 217 this->glPathRendering()->setProjectionMatrix(optState->getViewMatrix(), size, rt->origin()); 218 } else { 219 this->flushMiscFixedFunctionState(*optState.get()); 220 221 GrBlendCoeff srcCoeff = optState->getSrcBlendCoeff(); 222 GrBlendCoeff dstCoeff = optState->getDstBlendCoeff(); 223 224 // In these blend coeff's we end up drawing nothing so we can skip draw all together 225 if (kZero_GrBlendCoeff == srcCoeff && kOne_GrBlendCoeff == dstCoeff && 226 !optState->getStencil().doesWrite()) { 227 return false; 228 } 229 230 const GrGeometryStage* geometryProcessor = NULL; 231 SkSTArray<8, const GrFragmentStage*, true> colorStages; 232 SkSTArray<8, const GrFragmentStage*, true> coverageStages; 233 GrGLProgramDesc desc; 234 if (!GrGLProgramDesc::Build(*optState.get(), 235 type, 236 srcCoeff, 237 dstCoeff, 238 this, 239 dstCopy, 240 &geometryProcessor, 241 &colorStages, 242 &coverageStages, 243 &desc)) { 244 SkDEBUGFAIL("Failed to generate GL program descriptor"); 245 return false; 246 } 247 248 fCurrentProgram.reset(fProgramCache->getProgram(desc, 249 geometryProcessor, 250 colorStages.begin(), 251 coverageStages.begin())); 252 if (NULL == fCurrentProgram.get()) { 253 SkDEBUGFAIL("Failed to create program!"); 254 return false; 255 } 256 257 fCurrentProgram.get()->ref(); 258 259 GrGLuint programID = fCurrentProgram->programID(); 260 if (fHWProgramID != programID) { 261 GL_CALL(UseProgram(programID)); 262 fHWProgramID = programID; 263 } 264 265 this->flushBlend(*optState.get(), kDrawLines_DrawType == type, srcCoeff, dstCoeff); 266 267 fCurrentProgram->setData(*optState.get(), 268 type, 269 geometryProcessor, 270 colorStages.begin(), 271 coverageStages.begin(), 272 dstCopy, 273 &fSharedGLProgramState); 274 } 275 276 GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(optState->getRenderTarget()); 277 this->flushStencil(type); 278 this->flushScissor(glRT->getViewport(), glRT->origin()); 279 this->flushAAState(*optState.get(), type); 280 281 SkIRect* devRect = NULL; 282 SkIRect devClipBounds; 283 if (optState->isClipState()) { 284 this->getClip()->getConservativeBounds(optState->getRenderTarget(), &devClipBounds); 285 devRect = &devClipBounds; 286 } 287 // This must come after textures are flushed because a texture may need 288 // to be msaa-resolved (which will modify bound FBO state). 289 this->flushRenderTarget(glRT, devRect); 290 291 return true; 292 } 293 294 void GrGpuGL::setupGeometry(const DrawInfo& info, size_t* indexOffsetInBytes) { 295 SkAutoTUnref<GrOptDrawState> optState(this->getDrawState().createOptState(*this->caps())); 296 297 GrGLsizei stride = static_cast<GrGLsizei>(optState->getVertexStride()); 298 299 size_t vertexOffsetInBytes = stride * info.startVertex(); 300 301 const GeometryPoolState& geoPoolState = this->getGeomPoolState(); 302 303 GrGLVertexBuffer* vbuf; 304 switch (this->getGeomSrc().fVertexSrc) { 305 case kBuffer_GeometrySrcType: 306 vbuf = (GrGLVertexBuffer*) this->getGeomSrc().fVertexBuffer; 307 break; 308 case kArray_GeometrySrcType: 309 case kReserved_GeometrySrcType: 310 this->finalizeReservedVertices(); 311 vertexOffsetInBytes += geoPoolState.fPoolStartVertex * this->getGeomSrc().fVertexSize; 312 vbuf = (GrGLVertexBuffer*) geoPoolState.fPoolVertexBuffer; 313 break; 314 default: 315 vbuf = NULL; // suppress warning 316 SkFAIL("Unknown geometry src type!"); 317 } 318 319 SkASSERT(vbuf); 320 SkASSERT(!vbuf->isMapped()); 321 vertexOffsetInBytes += vbuf->baseOffset(); 322 323 GrGLIndexBuffer* ibuf = NULL; 324 if (info.isIndexed()) { 325 SkASSERT(indexOffsetInBytes); 326 327 switch (this->getGeomSrc().fIndexSrc) { 328 case kBuffer_GeometrySrcType: 329 *indexOffsetInBytes = 0; 330 ibuf = (GrGLIndexBuffer*)this->getGeomSrc().fIndexBuffer; 331 break; 332 case kArray_GeometrySrcType: 333 case kReserved_GeometrySrcType: 334 this->finalizeReservedIndices(); 335 *indexOffsetInBytes = geoPoolState.fPoolStartIndex * sizeof(GrGLushort); 336 ibuf = (GrGLIndexBuffer*) geoPoolState.fPoolIndexBuffer; 337 break; 338 default: 339 ibuf = NULL; // suppress warning 340 SkFAIL("Unknown geometry src type!"); 341 } 342 343 SkASSERT(ibuf); 344 SkASSERT(!ibuf->isMapped()); 345 *indexOffsetInBytes += ibuf->baseOffset(); 346 } 347 GrGLAttribArrayState* attribState = 348 fHWGeometryState.bindArrayAndBuffersToDraw(this, vbuf, ibuf); 349 350 if (fCurrentProgram->hasVertexShader()) { 351 int vertexAttribCount = optState->getVertexAttribCount(); 352 uint32_t usedAttribArraysMask = 0; 353 const GrVertexAttrib* vertexAttrib = optState->getVertexAttribs(); 354 355 for (int vertexAttribIndex = 0; vertexAttribIndex < vertexAttribCount; 356 ++vertexAttribIndex, ++vertexAttrib) { 357 usedAttribArraysMask |= (1 << vertexAttribIndex); 358 GrVertexAttribType attribType = vertexAttrib->fType; 359 attribState->set(this, 360 vertexAttribIndex, 361 vbuf, 362 GrGLAttribTypeToLayout(attribType).fCount, 363 GrGLAttribTypeToLayout(attribType).fType, 364 GrGLAttribTypeToLayout(attribType).fNormalized, 365 stride, 366 reinterpret_cast<GrGLvoid*>( 367 vertexOffsetInBytes + vertexAttrib->fOffset)); 368 } 369 attribState->disableUnusedArrays(this, usedAttribArraysMask); 370 } 371 } 372