1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/*
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2011 Google Inc.
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com *
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
6f93e717c7f7ca679a80acbfda6a34013ae1e2b8djunov@google.com */
7f93e717c7f7ca679a80acbfda6a34013ae1e2b8djunov@google.com
85739d2c168819394502e20cbe6071979b9c1038cbsalomon@google.com#include "GrGpuGL.h"
9ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
10a469c28c3c16214733a25201a286970f57b3d944bsalomon@google.com#include "GrEffect.h"
11d698f77c13d97c61109b861eac4d25b14a5de935bsalomon@google.com#include "GrGLEffect.h"
125c9b6faefff735110a59932793e81cf5b9dec51djvanverth@google.com#include "SkRTConf.h"
13511923443facc611b3735b4688342c12071feaa0cdalton#include "GrGLNameAllocator.h"
142db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com#include "SkTSearch.h"
15f93e717c7f7ca679a80acbfda6a34013ae1e2b8djunov@google.com
16a2f4b15d4e861b8b29e20ec37743fd3fd4b05b03jvanverth@google.com#ifdef PROGRAM_CACHE_STATS
175c9b6faefff735110a59932793e81cf5b9dec51djvanverth@google.comSK_CONF_DECLARE(bool, c_DisplayCache, "gpu.displayCache", false,
185c9b6faefff735110a59932793e81cf5b9dec51djvanverth@google.com                "Display program cache usage.");
19a2f4b15d4e861b8b29e20ec37743fd3fd4b05b03jvanverth@google.com#endif
205c9b6faefff735110a59932793e81cf5b9dec51djvanverth@google.com
21dbbc4e2da93cef5c0cfb0b3c92ff6c2c80f6e67absalomon@google.comtypedef GrGLUniformManager::UniformHandle UniformHandle;
22dbbc4e2da93cef5c0cfb0b3c92ff6c2c80f6e67absalomon@google.com
232db3ded335fdb6697623bece61cabc307a414770bsalomon@google.comstruct GrGpuGL::ProgramCache::Entry {
242db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    SK_DECLARE_INST_COUNT_ROOT(Entry);
252db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    Entry() : fProgram(NULL), fLRUStamp(0) {}
262db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com
272db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    SkAutoTUnref<GrGLProgram>   fProgram;
282db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    unsigned int                fLRUStamp;
292db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com};
302db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com
312db3ded335fdb6697623bece61cabc307a414770bsalomon@google.comstruct GrGpuGL::ProgramCache::ProgDescLess {
322db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    bool operator() (const GrGLProgramDesc& desc, const Entry* entry) {
33f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org        SkASSERT(NULL != entry->fProgram.get());
342db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        return GrGLProgramDesc::Less(desc, entry->fProgram->getDesc());
352db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    }
362db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com
372db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    bool operator() (const Entry* entry, const GrGLProgramDesc& desc) {
38f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org        SkASSERT(NULL != entry->fProgram.get());
392db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        return GrGLProgramDesc::Less(entry->fProgram->getDesc(), desc);
402db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    }
412db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com};
42f93e717c7f7ca679a80acbfda6a34013ae1e2b8djunov@google.com
439188a15f846ae79892c332aed2a72ee38116bdc6commit-bot@chromium.orgGrGpuGL::ProgramCache::ProgramCache(GrGpuGL* gpu)
44c1d2a58ec8510b226e080f5415a05723a686aab3bsalomon@google.com    : fCount(0)
45c1d2a58ec8510b226e080f5415a05723a686aab3bsalomon@google.com    , fCurrLRUStamp(0)
469188a15f846ae79892c332aed2a72ee38116bdc6commit-bot@chromium.org    , fGpu(gpu)
47948787737b77555318fa2433e7ff941516fe950ejvanverth@google.com#ifdef PROGRAM_CACHE_STATS
48948787737b77555318fa2433e7ff941516fe950ejvanverth@google.com    , fTotalRequests(0)
49948787737b77555318fa2433e7ff941516fe950ejvanverth@google.com    , fCacheMisses(0)
502db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    , fHashMisses(0)
51948787737b77555318fa2433e7ff941516fe950ejvanverth@google.com#endif
52948787737b77555318fa2433e7ff941516fe950ejvanverth@google.com{
532db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    for (int i = 0; i < 1 << kHashBits; ++i) {
542db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        fHashTable[i] = NULL;
552db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    }
56948787737b77555318fa2433e7ff941516fe950ejvanverth@google.com}
57948787737b77555318fa2433e7ff941516fe950ejvanverth@google.com
58948787737b77555318fa2433e7ff941516fe950ejvanverth@google.comGrGpuGL::ProgramCache::~ProgramCache() {
592db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    for (int i = 0; i < fCount; ++i){
602db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        SkDELETE(fEntries[i]);
612db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    }
62948787737b77555318fa2433e7ff941516fe950ejvanverth@google.com    // dump stats
63948787737b77555318fa2433e7ff941516fe950ejvanverth@google.com#ifdef PROGRAM_CACHE_STATS
645c9b6faefff735110a59932793e81cf5b9dec51djvanverth@google.com    if (c_DisplayCache) {
655c9b6faefff735110a59932793e81cf5b9dec51djvanverth@google.com        SkDebugf("--- Program Cache ---\n");
665c9b6faefff735110a59932793e81cf5b9dec51djvanverth@google.com        SkDebugf("Total requests: %d\n", fTotalRequests);
675c9b6faefff735110a59932793e81cf5b9dec51djvanverth@google.com        SkDebugf("Cache misses: %d\n", fCacheMisses);
685c9b6faefff735110a59932793e81cf5b9dec51djvanverth@google.com        SkDebugf("Cache miss %%: %f\n", (fTotalRequests > 0) ?
695c9b6faefff735110a59932793e81cf5b9dec51djvanverth@google.com                                            100.f * fCacheMisses / fTotalRequests :
705c9b6faefff735110a59932793e81cf5b9dec51djvanverth@google.com                                            0.f);
715c9b6faefff735110a59932793e81cf5b9dec51djvanverth@google.com        int cacheHits = fTotalRequests - fCacheMisses;
725c9b6faefff735110a59932793e81cf5b9dec51djvanverth@google.com        SkDebugf("Hash miss %%: %f\n", (cacheHits > 0) ? 100.f * fHashMisses / cacheHits : 0.f);
735c9b6faefff735110a59932793e81cf5b9dec51djvanverth@google.com        SkDebugf("---------------------\n");
745c9b6faefff735110a59932793e81cf5b9dec51djvanverth@google.com    }
75948787737b77555318fa2433e7ff941516fe950ejvanverth@google.com#endif
76c1d2a58ec8510b226e080f5415a05723a686aab3bsalomon@google.com}
77f93e717c7f7ca679a80acbfda6a34013ae1e2b8djunov@google.com
78ecb60aad5c6fe5b1dbcfc86ac00bfc9326103c8dbsalomon@google.comvoid GrGpuGL::ProgramCache::abandon() {
79c1d2a58ec8510b226e080f5415a05723a686aab3bsalomon@google.com    for (int i = 0; i < fCount; ++i) {
80f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org        SkASSERT(NULL != fEntries[i]->fProgram.get());
812db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        fEntries[i]->fProgram->abandon();
822db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        fEntries[i]->fProgram.reset(NULL);
83f93e717c7f7ca679a80acbfda6a34013ae1e2b8djunov@google.com    }
84c1d2a58ec8510b226e080f5415a05723a686aab3bsalomon@google.com    fCount = 0;
85c1d2a58ec8510b226e080f5415a05723a686aab3bsalomon@google.com}
86f93e717c7f7ca679a80acbfda6a34013ae1e2b8djunov@google.com
872db3ded335fdb6697623bece61cabc307a414770bsalomon@google.comint GrGpuGL::ProgramCache::search(const GrGLProgramDesc& desc) const {
882db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    ProgDescLess less;
892db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    return SkTSearch(fEntries, fCount, desc, sizeof(Entry*), less);
902db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com}
912db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com
9231ec7985f2b52a0cab4aa714a613b918cf663c08bsalomon@google.comGrGLProgram* GrGpuGL::ProgramCache::getProgram(const GrGLProgramDesc& desc,
932c84aa35988c661b3e5513c8ba9b3959832ff288bsalomon@google.com                                               const GrEffectStage* colorStages[],
942c84aa35988c661b3e5513c8ba9b3959832ff288bsalomon@google.com                                               const GrEffectStage* coverageStages[]) {
95948787737b77555318fa2433e7ff941516fe950ejvanverth@google.com#ifdef PROGRAM_CACHE_STATS
96948787737b77555318fa2433e7ff941516fe950ejvanverth@google.com    ++fTotalRequests;
97948787737b77555318fa2433e7ff941516fe950ejvanverth@google.com#endif
989ba4fa6f0fb8ef496d81ccac36e780aa806fea83bsalomon@google.com
992db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    Entry* entry = NULL;
1002db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com
1012db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    uint32_t hashIdx = desc.getChecksum();
1022db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    hashIdx ^= hashIdx >> 16;
1032db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    if (kHashBits <= 8) {
1042db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        hashIdx ^= hashIdx >> 8;
1052db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    }
1062db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    hashIdx &=((1 << kHashBits) - 1);
1072db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    Entry* hashedEntry = fHashTable[hashIdx];
1082db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    if (NULL != hashedEntry && hashedEntry->fProgram->getDesc() == desc) {
109f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org        SkASSERT(NULL != hashedEntry->fProgram);
1102db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        entry = hashedEntry;
1112db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    }
1122db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com
1132db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    int entryIdx;
1142db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    if (NULL == entry) {
1152db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        entryIdx = this->search(desc);
1162db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        if (entryIdx >= 0) {
1172db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            entry = fEntries[entryIdx];
1182db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com#ifdef PROGRAM_CACHE_STATS
1192db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            ++fHashMisses;
1202db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com#endif
1212db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        }
1222db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    }
1232db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com
124c1d2a58ec8510b226e080f5415a05723a686aab3bsalomon@google.com    if (NULL == entry) {
1252db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        // We have a cache miss
126948787737b77555318fa2433e7ff941516fe950ejvanverth@google.com#ifdef PROGRAM_CACHE_STATS
127948787737b77555318fa2433e7ff941516fe950ejvanverth@google.com        ++fCacheMisses;
128948787737b77555318fa2433e7ff941516fe950ejvanverth@google.com#endif
1299188a15f846ae79892c332aed2a72ee38116bdc6commit-bot@chromium.org        GrGLProgram* program = GrGLProgram::Create(fGpu, desc, colorStages, coverageStages);
1302db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        if (NULL == program) {
131c1d2a58ec8510b226e080f5415a05723a686aab3bsalomon@google.com            return NULL;
132c1d2a58ec8510b226e080f5415a05723a686aab3bsalomon@google.com        }
1332db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        int purgeIdx = 0;
134c1d2a58ec8510b226e080f5415a05723a686aab3bsalomon@google.com        if (fCount < kMaxEntries) {
1352db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            entry = SkNEW(Entry);
1362db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            purgeIdx = fCount++;
1372db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            fEntries[purgeIdx] = entry;
138c1d2a58ec8510b226e080f5415a05723a686aab3bsalomon@google.com        } else {
139f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org            SkASSERT(fCount == kMaxEntries);
1402db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            purgeIdx = 0;
141c1d2a58ec8510b226e080f5415a05723a686aab3bsalomon@google.com            for (int i = 1; i < kMaxEntries; ++i) {
1422db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com                if (fEntries[i]->fLRUStamp < fEntries[purgeIdx]->fLRUStamp) {
1432db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com                    purgeIdx = i;
144f93e717c7f7ca679a80acbfda6a34013ae1e2b8djunov@google.com                }
145f93e717c7f7ca679a80acbfda6a34013ae1e2b8djunov@google.com            }
1462db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            entry = fEntries[purgeIdx];
1472db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            int purgedHashIdx = entry->fProgram->getDesc().getChecksum() & ((1 << kHashBits) - 1);
1482db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            if (fHashTable[purgedHashIdx] == entry) {
1492db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com                fHashTable[purgedHashIdx] = NULL;
1502db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            }
151f93e717c7f7ca679a80acbfda6a34013ae1e2b8djunov@google.com        }
152f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org        SkASSERT(fEntries[purgeIdx] == entry);
1532db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        entry->fProgram.reset(program);
1542d816ad36e806e5b1cf3c447e547829bbbe74fd1skia.committer@gmail.com        // We need to shift fEntries around so that the entry currently at purgeIdx is placed
1552db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        // just before the entry at ~entryIdx (in order to keep fEntries sorted by descriptor).
1562db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        entryIdx = ~entryIdx;
1572db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        if (entryIdx < purgeIdx) {
1582db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            //  Let E and P be the entries at index entryIdx and purgeIdx, respectively.
1592db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            //  If the entries array looks like this:
1602db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            //       aaaaEbbbbbPccccc
1612db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            //  we rearrange it to look like this:
1622db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            //       aaaaPEbbbbbccccc
1632db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            size_t copySize = (purgeIdx - entryIdx) * sizeof(Entry*);
1642db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            memmove(fEntries + entryIdx + 1, fEntries + entryIdx, copySize);
1652db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            fEntries[entryIdx] = entry;
1662db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        } else if (purgeIdx < entryIdx) {
1672db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            //  If the entries array looks like this:
1682db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            //       aaaaPbbbbbEccccc
1692db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            //  we rearrange it to look like this:
1702db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            //       aaaabbbbbPEccccc
1712db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            size_t copySize = (entryIdx - purgeIdx - 1) * sizeof(Entry*);
1722db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            memmove(fEntries + purgeIdx, fEntries + purgeIdx + 1, copySize);
1732db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            fEntries[entryIdx - 1] = entry;
1742db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        }
175515dcd36032997ce335daa0163c6d67e851bcad1commit-bot@chromium.org#ifdef SK_DEBUG
176f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org        SkASSERT(NULL != fEntries[0]->fProgram.get());
1772db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        for (int i = 0; i < fCount - 1; ++i) {
178f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org            SkASSERT(NULL != fEntries[i + 1]->fProgram.get());
1792db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            const GrGLProgramDesc& a = fEntries[i]->fProgram->getDesc();
1802db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            const GrGLProgramDesc& b = fEntries[i + 1]->fProgram->getDesc();
181f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org            SkASSERT(GrGLProgramDesc::Less(a, b));
182f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org            SkASSERT(!GrGLProgramDesc::Less(b, a));
1832db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        }
1842db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com#endif
185c1d2a58ec8510b226e080f5415a05723a686aab3bsalomon@google.com    }
186f93e717c7f7ca679a80acbfda6a34013ae1e2b8djunov@google.com
1872db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    fHashTable[hashIdx] = entry;
188c1d2a58ec8510b226e080f5415a05723a686aab3bsalomon@google.com    entry->fLRUStamp = fCurrLRUStamp;
1892db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com
1902db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    if (SK_MaxU32 == fCurrLRUStamp) {
191c1d2a58ec8510b226e080f5415a05723a686aab3bsalomon@google.com        // wrap around! just trash our LRU, one time hit.
192c1d2a58ec8510b226e080f5415a05723a686aab3bsalomon@google.com        for (int i = 0; i < fCount; ++i) {
1932db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            fEntries[i]->fLRUStamp = 0;
194f93e717c7f7ca679a80acbfda6a34013ae1e2b8djunov@google.com        }
195f93e717c7f7ca679a80acbfda6a34013ae1e2b8djunov@google.com    }
196c1d2a58ec8510b226e080f5415a05723a686aab3bsalomon@google.com    ++fCurrLRUStamp;
1979ba4fa6f0fb8ef496d81ccac36e780aa806fea83bsalomon@google.com    return entry->fProgram;
198c1d2a58ec8510b226e080f5415a05723a686aab3bsalomon@google.com}
199f93e717c7f7ca679a80acbfda6a34013ae1e2b8djunov@google.com
2001e257a5db32e1c9e3b0dba80f43470816ef948afbsalomon@google.com////////////////////////////////////////////////////////////////////////////////
2011e257a5db32e1c9e3b0dba80f43470816ef948afbsalomon@google.com
2025739d2c168819394502e20cbe6071979b9c1038cbsalomon@google.comvoid GrGpuGL::abandonResources(){
2035739d2c168819394502e20cbe6071979b9c1038cbsalomon@google.com    INHERITED::abandonResources();
2045739d2c168819394502e20cbe6071979b9c1038cbsalomon@google.com    fProgramCache->abandon();
2055739d2c168819394502e20cbe6071979b9c1038cbsalomon@google.com    fHWProgramID = 0;
206511923443facc611b3735b4688342c12071feaa0cdalton    fPathNameAllocator.reset(NULL);
2075739d2c168819394502e20cbe6071979b9c1038cbsalomon@google.com}
2085739d2c168819394502e20cbe6071979b9c1038cbsalomon@google.com
2095739d2c168819394502e20cbe6071979b9c1038cbsalomon@google.com////////////////////////////////////////////////////////////////////////////////
2105739d2c168819394502e20cbe6071979b9c1038cbsalomon@google.com
2110b77d6892b067ad402c9678b0226bff70599fbe2bsalomon@google.com#define GL_CALL(X) GR_GL_CALL(this->glInterface(), X)
2120b77d6892b067ad402c9678b0226bff70599fbe2bsalomon@google.com
21326e18b593ab65e4d92dfbce92579d8bc180d4c2cbsalomon@google.combool GrGpuGL::flushGraphicsState(DrawType type, const GrDeviceCoordTexture* dstCopy) {
2148f9cbd62ec108d410b91155dcf6a4789c641246fbsalomon@google.com    const GrDrawState& drawState = this->getDrawState();
2158f9cbd62ec108d410b91155dcf6a4789c641246fbsalomon@google.com
2166a51dcbf81cff6d92996ab3f4c7457478e441896bsalomon@google.com    // GrGpu::setupClipAndFlushState should have already checked this and bailed if not true.
217f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(NULL != drawState.getRenderTarget());
218c96cb3a929f954cd2e7b6319efdfa6b758b20bd3bsalomon@google.com
2196a51dcbf81cff6d92996ab3f4c7457478e441896bsalomon@google.com    if (kStencilPath_DrawType == type) {
2206b30e457409f37c91c301cd82040e733e2930286commit-bot@chromium.org        const GrRenderTarget* rt = this->getDrawState().getRenderTarget();
2216b30e457409f37c91c301cd82040e733e2930286commit-bot@chromium.org        SkISize size;
2226b30e457409f37c91c301cd82040e733e2930286commit-bot@chromium.org        size.set(rt->width(), rt->height());
2236b30e457409f37c91c301cd82040e733e2930286commit-bot@chromium.org        this->setProjectionMatrix(drawState.getViewMatrix(), size, rt->origin());
2246a51dcbf81cff6d92996ab3f4c7457478e441896bsalomon@google.com    } else {
225ded4f4b163f5aa19c22c871178c55ecb34623846bsalomon@google.com        this->flushMiscFixedFunctionState();
2264be283f3a82895530d1b70372cd48ddb1c663fd8bsalomon@google.com
227ded4f4b163f5aa19c22c871178c55ecb34623846bsalomon@google.com        GrBlendCoeff srcCoeff;
228ded4f4b163f5aa19c22c871178c55ecb34623846bsalomon@google.com        GrBlendCoeff dstCoeff;
2292b446734cfa8201e5478648988de86b646cb9544bsalomon@google.com        GrDrawState::BlendOptFlags blendOpts = drawState.getBlendOpts(false, &srcCoeff, &dstCoeff);
2302b446734cfa8201e5478648988de86b646cb9544bsalomon@google.com        if (GrDrawState::kSkipDraw_BlendOptFlag & blendOpts) {
231ded4f4b163f5aa19c22c871178c55ecb34623846bsalomon@google.com            return false;
232ded4f4b163f5aa19c22c871178c55ecb34623846bsalomon@google.com        }
233f93e717c7f7ca679a80acbfda6a34013ae1e2b8djunov@google.com
2342c84aa35988c661b3e5513c8ba9b3959832ff288bsalomon@google.com        SkSTArray<8, const GrEffectStage*, true> colorStages;
2352c84aa35988c661b3e5513c8ba9b3959832ff288bsalomon@google.com        SkSTArray<8, const GrEffectStage*, true> coverageStages;
23631ec7985f2b52a0cab4aa714a613b918cf663c08bsalomon@google.com        GrGLProgramDesc desc;
23731ec7985f2b52a0cab4aa714a613b918cf663c08bsalomon@google.com        GrGLProgramDesc::Build(this->getDrawState(),
2380a6fe71f1bc0e601b41b7ae6d28b8c96a2c41116commit-bot@chromium.org                               type,
23991207482c9398944fc997aeb99ed5f8674be58cbbsalomon@google.com                               blendOpts,
24091207482c9398944fc997aeb99ed5f8674be58cbbsalomon@google.com                               srcCoeff,
24191207482c9398944fc997aeb99ed5f8674be58cbbsalomon@google.com                               dstCoeff,
24291207482c9398944fc997aeb99ed5f8674be58cbbsalomon@google.com                               this,
24326e18b593ab65e4d92dfbce92579d8bc180d4c2cbsalomon@google.com                               dstCopy,
2442c84aa35988c661b3e5513c8ba9b3959832ff288bsalomon@google.com                               &colorStages,
2452c84aa35988c661b3e5513c8ba9b3959832ff288bsalomon@google.com                               &coverageStages,
24691207482c9398944fc997aeb99ed5f8674be58cbbsalomon@google.com                               &desc);
2479ba4fa6f0fb8ef496d81ccac36e780aa806fea83bsalomon@google.com
2482c84aa35988c661b3e5513c8ba9b3959832ff288bsalomon@google.com        fCurrentProgram.reset(fProgramCache->getProgram(desc,
2492c84aa35988c661b3e5513c8ba9b3959832ff288bsalomon@google.com                                                        colorStages.begin(),
2502c84aa35988c661b3e5513c8ba9b3959832ff288bsalomon@google.com                                                        coverageStages.begin()));
2519ba4fa6f0fb8ef496d81ccac36e780aa806fea83bsalomon@google.com        if (NULL == fCurrentProgram.get()) {
252330313a8a8343876ee596da39da06a5d69badd9cmtklein@google.com            SkDEBUGFAIL("Failed to create program!");
253ded4f4b163f5aa19c22c871178c55ecb34623846bsalomon@google.com            return false;
254ded4f4b163f5aa19c22c871178c55ecb34623846bsalomon@google.com        }
255c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org
2569b62aa156bcf1db6f11af9302bf8bb8ef2567142commit-bot@chromium.org        SkASSERT((kDrawPath_DrawType != type && kDrawPaths_DrawType != type)
2579b62aa156bcf1db6f11af9302bf8bb8ef2567142commit-bot@chromium.org                 || !fCurrentProgram->hasVertexShader());
258c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org
2599ba4fa6f0fb8ef496d81ccac36e780aa806fea83bsalomon@google.com        fCurrentProgram.get()->ref();
2604c8837867add05f8d25520f92f6ec52305dda02ebsalomon@google.com
2616a51dcbf81cff6d92996ab3f4c7457478e441896bsalomon@google.com        GrGLuint programID = fCurrentProgram->programID();
2626a51dcbf81cff6d92996ab3f4c7457478e441896bsalomon@google.com        if (fHWProgramID != programID) {
2636a51dcbf81cff6d92996ab3f4c7457478e441896bsalomon@google.com            GL_CALL(UseProgram(programID));
2646a51dcbf81cff6d92996ab3f4c7457478e441896bsalomon@google.com            fHWProgramID = programID;
265ded4f4b163f5aa19c22c871178c55ecb34623846bsalomon@google.com        }
2666a51dcbf81cff6d92996ab3f4c7457478e441896bsalomon@google.com
2679ba4fa6f0fb8ef496d81ccac36e780aa806fea83bsalomon@google.com        fCurrentProgram->overrideBlend(&srcCoeff, &dstCoeff);
268ded4f4b163f5aa19c22c871178c55ecb34623846bsalomon@google.com        this->flushBlend(kDrawLines_DrawType == type, srcCoeff, dstCoeff);
269ded4f4b163f5aa19c22c871178c55ecb34623846bsalomon@google.com
2709188a15f846ae79892c332aed2a72ee38116bdc6commit-bot@chromium.org        fCurrentProgram->setData(blendOpts,
2712c84aa35988c661b3e5513c8ba9b3959832ff288bsalomon@google.com                                 colorStages.begin(),
2722c84aa35988c661b3e5513c8ba9b3959832ff288bsalomon@google.com                                 coverageStages.begin(),
2732c84aa35988c661b3e5513c8ba9b3959832ff288bsalomon@google.com                                 dstCopy,
2742c84aa35988c661b3e5513c8ba9b3959832ff288bsalomon@google.com                                 &fSharedGLProgramState);
275f93e717c7f7ca679a80acbfda6a34013ae1e2b8djunov@google.com    }
276ded4f4b163f5aa19c22c871178c55ecb34623846bsalomon@google.com    this->flushStencil(type);
277a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    this->flushScissor();
278ded4f4b163f5aa19c22c871178c55ecb34623846bsalomon@google.com    this->flushAAState(type);
2794c8837867add05f8d25520f92f6ec52305dda02ebsalomon@google.com
280fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org    SkIRect* devRect = NULL;
281fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org    SkIRect devClipBounds;
2823e11c0bd92fbd12f59080c3f9450201d6105db83robertphillips@google.com    if (drawState.isClipState()) {
28302ddc8b85ace91b15feb329a6a1d5d62b2b846c6bsalomon@google.com        this->getClip()->getConservativeBounds(drawState.getRenderTarget(), &devClipBounds);
2847b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com        devRect = &devClipBounds;
2854c8837867add05f8d25520f92f6ec52305dda02ebsalomon@google.com    }
2864c8837867add05f8d25520f92f6ec52305dda02ebsalomon@google.com    // This must come after textures are flushed because a texture may need
2874c8837867add05f8d25520f92f6ec52305dda02ebsalomon@google.com    // to be msaa-resolved (which will modify bound FBO state).
2887b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com    this->flushRenderTarget(devRect);
2894c8837867add05f8d25520f92f6ec52305dda02ebsalomon@google.com
290f93e717c7f7ca679a80acbfda6a34013ae1e2b8djunov@google.com    return true;
291f93e717c7f7ca679a80acbfda6a34013ae1e2b8djunov@google.com}
292f93e717c7f7ca679a80acbfda6a34013ae1e2b8djunov@google.com
293880b8fcf255e67a15687e8b7cc47397372db683cbsalomon@google.comvoid GrGpuGL::setupGeometry(const DrawInfo& info, size_t* indexOffsetInBytes) {
294f93e717c7f7ca679a80acbfda6a34013ae1e2b8djunov@google.com
295a4662865e37a2ca95b5e3379072f6a274acc8ac8robertphillips@google.com    GrGLsizei stride = static_cast<GrGLsizei>(this->getDrawState().getVertexSize());
296880b8fcf255e67a15687e8b7cc47397372db683cbsalomon@google.com
2976918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com    size_t vertexOffsetInBytes = stride * info.startVertex();
2986918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com
2996918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com    const GeometryPoolState& geoPoolState = this->getGeomPoolState();
3006918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com
3016918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com    GrGLVertexBuffer* vbuf;
3026918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com    switch (this->getGeomSrc().fVertexSrc) {
3036918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com        case kBuffer_GeometrySrcType:
3046918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com            vbuf = (GrGLVertexBuffer*) this->getGeomSrc().fVertexBuffer;
3056918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com            break;
3066918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com        case kArray_GeometrySrcType:
3076918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com        case kReserved_GeometrySrcType:
3086918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com            this->finalizeReservedVertices();
3096918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com            vertexOffsetInBytes += geoPoolState.fPoolStartVertex * this->getGeomSrc().fVertexSize;
3106918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com            vbuf = (GrGLVertexBuffer*) geoPoolState.fPoolVertexBuffer;
3116918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com            break;
3126918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com        default:
3136918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com            vbuf = NULL; // suppress warning
31488cb22b6b4816c7a9ca6c5b795965b4606f9eb7bcommit-bot@chromium.org            SkFAIL("Unknown geometry src type!");
3156918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com    }
3166918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com
317f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(NULL != vbuf);
3188341eb76fbc54593e873f5589961e02793e7f15fcommit-bot@chromium.org    SkASSERT(!vbuf->isMapped());
3196918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com    vertexOffsetInBytes += vbuf->baseOffset();
3206918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com
3216918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com    GrGLIndexBuffer* ibuf = NULL;
3226918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com    if (info.isIndexed()) {
323f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org        SkASSERT(NULL != indexOffsetInBytes);
3246918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com
3256918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com        switch (this->getGeomSrc().fIndexSrc) {
3266918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com        case kBuffer_GeometrySrcType:
3276918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com            *indexOffsetInBytes = 0;
3286918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com            ibuf = (GrGLIndexBuffer*)this->getGeomSrc().fIndexBuffer;
3296918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com            break;
3306918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com        case kArray_GeometrySrcType:
3316918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com        case kReserved_GeometrySrcType:
3326918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com            this->finalizeReservedIndices();
3336918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com            *indexOffsetInBytes = geoPoolState.fPoolStartIndex * sizeof(GrGLushort);
3346918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com            ibuf = (GrGLIndexBuffer*) geoPoolState.fPoolIndexBuffer;
3356918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com            break;
3366918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com        default:
3376918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com            ibuf = NULL; // suppress warning
33888cb22b6b4816c7a9ca6c5b795965b4606f9eb7bcommit-bot@chromium.org            SkFAIL("Unknown geometry src type!");
3396918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com        }
3406918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com
341f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org        SkASSERT(NULL != ibuf);
3428341eb76fbc54593e873f5589961e02793e7f15fcommit-bot@chromium.org        SkASSERT(!ibuf->isMapped());
3436918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com        *indexOffsetInBytes += ibuf->baseOffset();
3446918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com    }
3456918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com    GrGLAttribArrayState* attribState =
3466918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com        fHWGeometryState.bindArrayAndBuffersToDraw(this, vbuf, ibuf);
347880b8fcf255e67a15687e8b7cc47397372db683cbsalomon@google.com
3480a6fe71f1bc0e601b41b7ae6d28b8c96a2c41116commit-bot@chromium.org    if (fCurrentProgram->hasVertexShader()) {
3496ebfbf9968c76b0238f1b48296ff1b507e110ba1commit-bot@chromium.org        int vertexAttribCount = this->getDrawState().getVertexAttribCount();
3506b30e457409f37c91c301cd82040e733e2930286commit-bot@chromium.org        uint32_t usedAttribArraysMask = 0;
3516b30e457409f37c91c301cd82040e733e2930286commit-bot@chromium.org        const GrVertexAttrib* vertexAttrib = this->getDrawState().getVertexAttribs();
3526ebfbf9968c76b0238f1b48296ff1b507e110ba1commit-bot@chromium.org
3536b30e457409f37c91c301cd82040e733e2930286commit-bot@chromium.org        for (int vertexAttribIndex = 0; vertexAttribIndex < vertexAttribCount;
3546b30e457409f37c91c301cd82040e733e2930286commit-bot@chromium.org             ++vertexAttribIndex, ++vertexAttrib) {
3556b30e457409f37c91c301cd82040e733e2930286commit-bot@chromium.org
3566b30e457409f37c91c301cd82040e733e2930286commit-bot@chromium.org            usedAttribArraysMask |= (1 << vertexAttribIndex);
3576b30e457409f37c91c301cd82040e733e2930286commit-bot@chromium.org            GrVertexAttribType attribType = vertexAttrib->fType;
3586b30e457409f37c91c301cd82040e733e2930286commit-bot@chromium.org            attribState->set(this,
3596b30e457409f37c91c301cd82040e733e2930286commit-bot@chromium.org                             vertexAttribIndex,
3606b30e457409f37c91c301cd82040e733e2930286commit-bot@chromium.org                             vbuf,
3616b30e457409f37c91c301cd82040e733e2930286commit-bot@chromium.org                             GrGLAttribTypeToLayout(attribType).fCount,
3626b30e457409f37c91c301cd82040e733e2930286commit-bot@chromium.org                             GrGLAttribTypeToLayout(attribType).fType,
3636b30e457409f37c91c301cd82040e733e2930286commit-bot@chromium.org                             GrGLAttribTypeToLayout(attribType).fNormalized,
3646b30e457409f37c91c301cd82040e733e2930286commit-bot@chromium.org                             stride,
3656b30e457409f37c91c301cd82040e733e2930286commit-bot@chromium.org                             reinterpret_cast<GrGLvoid*>(
3666ebfbf9968c76b0238f1b48296ff1b507e110ba1commit-bot@chromium.org                                 vertexOffsetInBytes + vertexAttrib->fOffset));
3676b30e457409f37c91c301cd82040e733e2930286commit-bot@chromium.org        }
3686ebfbf9968c76b0238f1b48296ff1b507e110ba1commit-bot@chromium.org        attribState->disableUnusedArrays(this, usedAttribArraysMask);
3696b30e457409f37c91c301cd82040e733e2930286commit-bot@chromium.org    }
370f93e717c7f7ca679a80acbfda6a34013ae1e2b8djunov@google.com}
371