1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/gpu/gl/GrGpuGL_program.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,387 @@ 1.4 +/* 1.5 + * Copyright 2011 Google Inc. 1.6 + * 1.7 + * Use of this source code is governed by a BSD-style license that can be 1.8 + * found in the LICENSE file. 1.9 + */ 1.10 + 1.11 +#include "GrGpuGL.h" 1.12 + 1.13 +#include "GrEffect.h" 1.14 +#include "GrGLEffect.h" 1.15 +#include "SkRTConf.h" 1.16 +#include "SkTSearch.h" 1.17 + 1.18 +#ifdef PROGRAM_CACHE_STATS 1.19 +SK_CONF_DECLARE(bool, c_DisplayCache, "gpu.displayCache", false, 1.20 + "Display program cache usage."); 1.21 +#endif 1.22 + 1.23 +typedef GrGLUniformManager::UniformHandle UniformHandle; 1.24 + 1.25 +struct GrGpuGL::ProgramCache::Entry { 1.26 + SK_DECLARE_INST_COUNT_ROOT(Entry); 1.27 + Entry() : fProgram(NULL), fLRUStamp(0) {} 1.28 + 1.29 + SkAutoTUnref<GrGLProgram> fProgram; 1.30 + unsigned int fLRUStamp; 1.31 +}; 1.32 + 1.33 +struct GrGpuGL::ProgramCache::ProgDescLess { 1.34 + bool operator() (const GrGLProgramDesc& desc, const Entry* entry) { 1.35 + SkASSERT(NULL != entry->fProgram.get()); 1.36 + return GrGLProgramDesc::Less(desc, entry->fProgram->getDesc()); 1.37 + } 1.38 + 1.39 + bool operator() (const Entry* entry, const GrGLProgramDesc& desc) { 1.40 + SkASSERT(NULL != entry->fProgram.get()); 1.41 + return GrGLProgramDesc::Less(entry->fProgram->getDesc(), desc); 1.42 + } 1.43 +}; 1.44 + 1.45 +GrGpuGL::ProgramCache::ProgramCache(GrGpuGL* gpu) 1.46 + : fCount(0) 1.47 + , fCurrLRUStamp(0) 1.48 + , fGpu(gpu) 1.49 +#ifdef PROGRAM_CACHE_STATS 1.50 + , fTotalRequests(0) 1.51 + , fCacheMisses(0) 1.52 + , fHashMisses(0) 1.53 +#endif 1.54 +{ 1.55 + for (int i = 0; i < 1 << kHashBits; ++i) { 1.56 + fHashTable[i] = NULL; 1.57 + } 1.58 +} 1.59 + 1.60 +GrGpuGL::ProgramCache::~ProgramCache() { 1.61 + for (int i = 0; i < fCount; ++i){ 1.62 + SkDELETE(fEntries[i]); 1.63 + } 1.64 + // dump stats 1.65 +#ifdef PROGRAM_CACHE_STATS 1.66 + if (c_DisplayCache) { 1.67 + SkDebugf("--- Program Cache ---\n"); 1.68 + SkDebugf("Total requests: %d\n", fTotalRequests); 1.69 + SkDebugf("Cache misses: %d\n", fCacheMisses); 1.70 + SkDebugf("Cache miss %%: %f\n", (fTotalRequests > 0) ? 1.71 + 100.f * fCacheMisses / fTotalRequests : 1.72 + 0.f); 1.73 + int cacheHits = fTotalRequests - fCacheMisses; 1.74 + SkDebugf("Hash miss %%: %f\n", (cacheHits > 0) ? 100.f * fHashMisses / cacheHits : 0.f); 1.75 + SkDebugf("---------------------\n"); 1.76 + } 1.77 +#endif 1.78 +} 1.79 + 1.80 +void GrGpuGL::ProgramCache::abandon() { 1.81 + for (int i = 0; i < fCount; ++i) { 1.82 + SkASSERT(NULL != fEntries[i]->fProgram.get()); 1.83 + fEntries[i]->fProgram->abandon(); 1.84 + fEntries[i]->fProgram.reset(NULL); 1.85 + } 1.86 + fCount = 0; 1.87 +} 1.88 + 1.89 +int GrGpuGL::ProgramCache::search(const GrGLProgramDesc& desc) const { 1.90 + ProgDescLess less; 1.91 + return SkTSearch(fEntries, fCount, desc, sizeof(Entry*), less); 1.92 +} 1.93 + 1.94 +GrGLProgram* GrGpuGL::ProgramCache::getProgram(const GrGLProgramDesc& desc, 1.95 + const GrEffectStage* colorStages[], 1.96 + const GrEffectStage* coverageStages[]) { 1.97 +#ifdef PROGRAM_CACHE_STATS 1.98 + ++fTotalRequests; 1.99 +#endif 1.100 + 1.101 + Entry* entry = NULL; 1.102 + 1.103 + uint32_t hashIdx = desc.getChecksum(); 1.104 + hashIdx ^= hashIdx >> 16; 1.105 + if (kHashBits <= 8) { 1.106 + hashIdx ^= hashIdx >> 8; 1.107 + } 1.108 + hashIdx &=((1 << kHashBits) - 1); 1.109 + Entry* hashedEntry = fHashTable[hashIdx]; 1.110 + if (NULL != hashedEntry && hashedEntry->fProgram->getDesc() == desc) { 1.111 + SkASSERT(NULL != hashedEntry->fProgram); 1.112 + entry = hashedEntry; 1.113 + } 1.114 + 1.115 + int entryIdx; 1.116 + if (NULL == entry) { 1.117 + entryIdx = this->search(desc); 1.118 + if (entryIdx >= 0) { 1.119 + entry = fEntries[entryIdx]; 1.120 +#ifdef PROGRAM_CACHE_STATS 1.121 + ++fHashMisses; 1.122 +#endif 1.123 + } 1.124 + } 1.125 + 1.126 + if (NULL == entry) { 1.127 + // We have a cache miss 1.128 +#ifdef PROGRAM_CACHE_STATS 1.129 + ++fCacheMisses; 1.130 +#endif 1.131 + GrGLProgram* program = GrGLProgram::Create(fGpu, desc, colorStages, coverageStages); 1.132 + if (NULL == program) { 1.133 + return NULL; 1.134 + } 1.135 + int purgeIdx = 0; 1.136 + if (fCount < kMaxEntries) { 1.137 + entry = SkNEW(Entry); 1.138 + purgeIdx = fCount++; 1.139 + fEntries[purgeIdx] = entry; 1.140 + } else { 1.141 + SkASSERT(fCount == kMaxEntries); 1.142 + purgeIdx = 0; 1.143 + for (int i = 1; i < kMaxEntries; ++i) { 1.144 + if (fEntries[i]->fLRUStamp < fEntries[purgeIdx]->fLRUStamp) { 1.145 + purgeIdx = i; 1.146 + } 1.147 + } 1.148 + entry = fEntries[purgeIdx]; 1.149 + int purgedHashIdx = entry->fProgram->getDesc().getChecksum() & ((1 << kHashBits) - 1); 1.150 + if (fHashTable[purgedHashIdx] == entry) { 1.151 + fHashTable[purgedHashIdx] = NULL; 1.152 + } 1.153 + } 1.154 + SkASSERT(fEntries[purgeIdx] == entry); 1.155 + entry->fProgram.reset(program); 1.156 + // We need to shift fEntries around so that the entry currently at purgeIdx is placed 1.157 + // just before the entry at ~entryIdx (in order to keep fEntries sorted by descriptor). 1.158 + entryIdx = ~entryIdx; 1.159 + if (entryIdx < purgeIdx) { 1.160 + // Let E and P be the entries at index entryIdx and purgeIdx, respectively. 1.161 + // If the entries array looks like this: 1.162 + // aaaaEbbbbbPccccc 1.163 + // we rearrange it to look like this: 1.164 + // aaaaPEbbbbbccccc 1.165 + size_t copySize = (purgeIdx - entryIdx) * sizeof(Entry*); 1.166 + memmove(fEntries + entryIdx + 1, fEntries + entryIdx, copySize); 1.167 + fEntries[entryIdx] = entry; 1.168 + } else if (purgeIdx < entryIdx) { 1.169 + // If the entries array looks like this: 1.170 + // aaaaPbbbbbEccccc 1.171 + // we rearrange it to look like this: 1.172 + // aaaabbbbbPEccccc 1.173 + size_t copySize = (entryIdx - purgeIdx - 1) * sizeof(Entry*); 1.174 + memmove(fEntries + purgeIdx, fEntries + purgeIdx + 1, copySize); 1.175 + fEntries[entryIdx - 1] = entry; 1.176 + } 1.177 +#ifdef SK_DEBUG 1.178 + SkASSERT(NULL != fEntries[0]->fProgram.get()); 1.179 + for (int i = 0; i < fCount - 1; ++i) { 1.180 + SkASSERT(NULL != fEntries[i + 1]->fProgram.get()); 1.181 + const GrGLProgramDesc& a = fEntries[i]->fProgram->getDesc(); 1.182 + const GrGLProgramDesc& b = fEntries[i + 1]->fProgram->getDesc(); 1.183 + SkASSERT(GrGLProgramDesc::Less(a, b)); 1.184 + SkASSERT(!GrGLProgramDesc::Less(b, a)); 1.185 + } 1.186 +#endif 1.187 + } 1.188 + 1.189 + fHashTable[hashIdx] = entry; 1.190 + entry->fLRUStamp = fCurrLRUStamp; 1.191 + 1.192 + if (SK_MaxU32 == fCurrLRUStamp) { 1.193 + // wrap around! just trash our LRU, one time hit. 1.194 + for (int i = 0; i < fCount; ++i) { 1.195 + fEntries[i]->fLRUStamp = 0; 1.196 + } 1.197 + } 1.198 + ++fCurrLRUStamp; 1.199 + return entry->fProgram; 1.200 +} 1.201 + 1.202 +//////////////////////////////////////////////////////////////////////////////// 1.203 + 1.204 +void GrGpuGL::abandonResources(){ 1.205 + INHERITED::abandonResources(); 1.206 + fProgramCache->abandon(); 1.207 + fHWProgramID = 0; 1.208 +} 1.209 + 1.210 +//////////////////////////////////////////////////////////////////////////////// 1.211 + 1.212 +#define GL_CALL(X) GR_GL_CALL(this->glInterface(), X) 1.213 + 1.214 +bool GrGpuGL::flushGraphicsState(DrawType type, const GrDeviceCoordTexture* dstCopy) { 1.215 + const GrDrawState& drawState = this->getDrawState(); 1.216 + 1.217 + // GrGpu::setupClipAndFlushState should have already checked this and bailed if not true. 1.218 + SkASSERT(NULL != drawState.getRenderTarget()); 1.219 + 1.220 + if (kStencilPath_DrawType == type) { 1.221 + const GrRenderTarget* rt = this->getDrawState().getRenderTarget(); 1.222 + SkISize size; 1.223 + size.set(rt->width(), rt->height()); 1.224 + this->setProjectionMatrix(drawState.getViewMatrix(), size, rt->origin()); 1.225 + } else { 1.226 + this->flushMiscFixedFunctionState(); 1.227 + 1.228 + GrBlendCoeff srcCoeff; 1.229 + GrBlendCoeff dstCoeff; 1.230 + GrDrawState::BlendOptFlags blendOpts = drawState.getBlendOpts(false, &srcCoeff, &dstCoeff); 1.231 + if (GrDrawState::kSkipDraw_BlendOptFlag & blendOpts) { 1.232 + return false; 1.233 + } 1.234 + 1.235 + SkSTArray<8, const GrEffectStage*, true> colorStages; 1.236 + SkSTArray<8, const GrEffectStage*, true> coverageStages; 1.237 + GrGLProgramDesc desc; 1.238 + GrGLProgramDesc::Build(this->getDrawState(), 1.239 + kDrawPoints_DrawType == type, 1.240 + blendOpts, 1.241 + srcCoeff, 1.242 + dstCoeff, 1.243 + this, 1.244 + dstCopy, 1.245 + &colorStages, 1.246 + &coverageStages, 1.247 + &desc); 1.248 + 1.249 + fCurrentProgram.reset(fProgramCache->getProgram(desc, 1.250 + colorStages.begin(), 1.251 + coverageStages.begin())); 1.252 + if (NULL == fCurrentProgram.get()) { 1.253 + SkDEBUGFAIL("Failed to create program!"); 1.254 + return false; 1.255 + } 1.256 + 1.257 + SkASSERT(kDrawPath_DrawType != type || !fCurrentProgram->hasVertexShader()); 1.258 + 1.259 + fCurrentProgram.get()->ref(); 1.260 + 1.261 + GrGLuint programID = fCurrentProgram->programID(); 1.262 + if (fHWProgramID != programID) { 1.263 + GL_CALL(UseProgram(programID)); 1.264 + fHWProgramID = programID; 1.265 + } 1.266 + 1.267 + fCurrentProgram->overrideBlend(&srcCoeff, &dstCoeff); 1.268 + this->flushBlend(kDrawLines_DrawType == type, srcCoeff, dstCoeff); 1.269 + 1.270 + fCurrentProgram->setData(blendOpts, 1.271 + colorStages.begin(), 1.272 + coverageStages.begin(), 1.273 + dstCopy, 1.274 + &fSharedGLProgramState); 1.275 + } 1.276 + this->flushStencil(type); 1.277 + this->flushScissor(); 1.278 + this->flushAAState(type); 1.279 + 1.280 + SkIRect* devRect = NULL; 1.281 + SkIRect devClipBounds; 1.282 + if (drawState.isClipState()) { 1.283 + this->getClip()->getConservativeBounds(drawState.getRenderTarget(), &devClipBounds); 1.284 + devRect = &devClipBounds; 1.285 + } 1.286 + // This must come after textures are flushed because a texture may need 1.287 + // to be msaa-resolved (which will modify bound FBO state). 1.288 + this->flushRenderTarget(devRect); 1.289 + 1.290 + return true; 1.291 +} 1.292 + 1.293 +void GrGpuGL::setupGeometry(const DrawInfo& info, size_t* indexOffsetInBytes) { 1.294 + 1.295 + GrGLsizei stride = static_cast<GrGLsizei>(this->getDrawState().getVertexSize()); 1.296 + 1.297 + size_t vertexOffsetInBytes = stride * info.startVertex(); 1.298 + 1.299 + const GeometryPoolState& geoPoolState = this->getGeomPoolState(); 1.300 + 1.301 + GrGLVertexBuffer* vbuf; 1.302 + switch (this->getGeomSrc().fVertexSrc) { 1.303 + case kBuffer_GeometrySrcType: 1.304 + vbuf = (GrGLVertexBuffer*) this->getGeomSrc().fVertexBuffer; 1.305 + break; 1.306 + case kArray_GeometrySrcType: 1.307 + case kReserved_GeometrySrcType: 1.308 + this->finalizeReservedVertices(); 1.309 + vertexOffsetInBytes += geoPoolState.fPoolStartVertex * this->getGeomSrc().fVertexSize; 1.310 + vbuf = (GrGLVertexBuffer*) geoPoolState.fPoolVertexBuffer; 1.311 + break; 1.312 + default: 1.313 + vbuf = NULL; // suppress warning 1.314 + GrCrash("Unknown geometry src type!"); 1.315 + } 1.316 + 1.317 + SkASSERT(NULL != vbuf); 1.318 + SkASSERT(!vbuf->isLocked()); 1.319 + vertexOffsetInBytes += vbuf->baseOffset(); 1.320 + 1.321 + GrGLIndexBuffer* ibuf = NULL; 1.322 + if (info.isIndexed()) { 1.323 + SkASSERT(NULL != indexOffsetInBytes); 1.324 + 1.325 + switch (this->getGeomSrc().fIndexSrc) { 1.326 + case kBuffer_GeometrySrcType: 1.327 + *indexOffsetInBytes = 0; 1.328 + ibuf = (GrGLIndexBuffer*)this->getGeomSrc().fIndexBuffer; 1.329 + break; 1.330 + case kArray_GeometrySrcType: 1.331 + case kReserved_GeometrySrcType: 1.332 + this->finalizeReservedIndices(); 1.333 + *indexOffsetInBytes = geoPoolState.fPoolStartIndex * sizeof(GrGLushort); 1.334 + ibuf = (GrGLIndexBuffer*) geoPoolState.fPoolIndexBuffer; 1.335 + break; 1.336 + default: 1.337 + ibuf = NULL; // suppress warning 1.338 + GrCrash("Unknown geometry src type!"); 1.339 + } 1.340 + 1.341 + SkASSERT(NULL != ibuf); 1.342 + SkASSERT(!ibuf->isLocked()); 1.343 + *indexOffsetInBytes += ibuf->baseOffset(); 1.344 + } 1.345 + GrGLAttribArrayState* attribState = 1.346 + fHWGeometryState.bindArrayAndBuffersToDraw(this, vbuf, ibuf); 1.347 + 1.348 + if (!fCurrentProgram->hasVertexShader()) { 1.349 + int posIdx = this->getDrawState().positionAttributeIndex(); 1.350 + const GrVertexAttrib* vertexAttrib = this->getDrawState().getVertexAttribs() + posIdx; 1.351 + GrVertexAttribType attribType = vertexAttrib->fType; 1.352 + SkASSERT(!GrGLAttribTypeToLayout(attribType).fNormalized); 1.353 + SkASSERT(GrGLAttribTypeToLayout(attribType).fCount == 2); 1.354 + 1.355 + // Attrib at location 0 is defined to be bound to vertex in fixed-function pipe. Asserts 1.356 + // above should make sure position attribute goes to location 0 when below code is executed. 1.357 + 1.358 + attribState->set(this, 1.359 + 0, 1.360 + vbuf, 1.361 + GrGLAttribTypeToLayout(attribType).fCount, 1.362 + GrGLAttribTypeToLayout(attribType).fType, 1.363 + GrGLAttribTypeToLayout(attribType).fNormalized, 1.364 + stride, 1.365 + reinterpret_cast<GrGLvoid*>( 1.366 + vertexOffsetInBytes + vertexAttrib->fOffset)); 1.367 + attribState->disableUnusedArrays(this, 1); 1.368 + } else { 1.369 + int vertexAttribCount = this->getDrawState().getVertexAttribCount(); 1.370 + uint32_t usedAttribArraysMask = 0; 1.371 + const GrVertexAttrib* vertexAttrib = this->getDrawState().getVertexAttribs(); 1.372 + 1.373 + for (int vertexAttribIndex = 0; vertexAttribIndex < vertexAttribCount; 1.374 + ++vertexAttribIndex, ++vertexAttrib) { 1.375 + 1.376 + usedAttribArraysMask |= (1 << vertexAttribIndex); 1.377 + GrVertexAttribType attribType = vertexAttrib->fType; 1.378 + attribState->set(this, 1.379 + vertexAttribIndex, 1.380 + vbuf, 1.381 + GrGLAttribTypeToLayout(attribType).fCount, 1.382 + GrGLAttribTypeToLayout(attribType).fType, 1.383 + GrGLAttribTypeToLayout(attribType).fNormalized, 1.384 + stride, 1.385 + reinterpret_cast<GrGLvoid*>( 1.386 + vertexOffsetInBytes + vertexAttrib->fOffset)); 1.387 + } 1.388 + attribState->disableUnusedArrays(this, usedAttribArraysMask); 1.389 + } 1.390 +}