GrGLGpuProgramCache.cpp revision 47bb38283072dc87dc93220cd2f370ca109972ff
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
1047bb38283072dc87dc93220cd2f370ca109972ffjoshualitt#include "builders/GrGLProgramBuilder.h"
11b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt#include "GrProcessor.h"
12b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt#include "GrGLProcessor.h"
138a4c1030ff4b8336b5ac5b0712691e2f65383440egdaniel#include "GrGLPathRendering.h"
14170f90b4576f291879371ecd6ae4bc2b1d85c64aegdaniel#include "GrOptDrawState.h"
15170f90b4576f291879371ecd6ae4bc2b1d85c64aegdaniel#include "SkRTConf.h"
162db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com#include "SkTSearch.h"
17f93e717c7f7ca679a80acbfda6a34013ae1e2b8djunov@google.com
18a2f4b15d4e861b8b29e20ec37743fd3fd4b05b03jvanverth@google.com#ifdef PROGRAM_CACHE_STATS
195c9b6faefff735110a59932793e81cf5b9dec51djvanverth@google.comSK_CONF_DECLARE(bool, c_DisplayCache, "gpu.displayCache", false,
205c9b6faefff735110a59932793e81cf5b9dec51djvanverth@google.com                "Display program cache usage.");
21a2f4b15d4e861b8b29e20ec37743fd3fd4b05b03jvanverth@google.com#endif
225c9b6faefff735110a59932793e81cf5b9dec51djvanverth@google.com
237510b224e52b9518a8ddf7418db0e9c258f79539kkinnunentypedef GrGLProgramDataManager::UniformHandle UniformHandle;
24dbbc4e2da93cef5c0cfb0b3c92ff6c2c80f6e67absalomon@google.com
252db3ded335fdb6697623bece61cabc307a414770bsalomon@google.comstruct GrGpuGL::ProgramCache::Entry {
262db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    SK_DECLARE_INST_COUNT_ROOT(Entry);
272db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    Entry() : fProgram(NULL), fLRUStamp(0) {}
282db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com
292db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    SkAutoTUnref<GrGLProgram>   fProgram;
302db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    unsigned int                fLRUStamp;
312db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com};
322db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com
332db3ded335fdb6697623bece61cabc307a414770bsalomon@google.comstruct GrGpuGL::ProgramCache::ProgDescLess {
342db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    bool operator() (const GrGLProgramDesc& desc, const Entry* entry) {
3549f085dddff10473b6ebf832a974288300224e60bsalomon        SkASSERT(entry->fProgram.get());
362db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        return GrGLProgramDesc::Less(desc, entry->fProgram->getDesc());
372db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    }
382db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com
392db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    bool operator() (const Entry* entry, const GrGLProgramDesc& desc) {
4049f085dddff10473b6ebf832a974288300224e60bsalomon        SkASSERT(entry->fProgram.get());
412db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        return GrGLProgramDesc::Less(entry->fProgram->getDesc(), desc);
422db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    }
432db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com};
44f93e717c7f7ca679a80acbfda6a34013ae1e2b8djunov@google.com
459188a15f846ae79892c332aed2a72ee38116bdc6commit-bot@chromium.orgGrGpuGL::ProgramCache::ProgramCache(GrGpuGL* gpu)
46c1d2a58ec8510b226e080f5415a05723a686aab3bsalomon@google.com    : fCount(0)
47c1d2a58ec8510b226e080f5415a05723a686aab3bsalomon@google.com    , fCurrLRUStamp(0)
489188a15f846ae79892c332aed2a72ee38116bdc6commit-bot@chromium.org    , fGpu(gpu)
49948787737b77555318fa2433e7ff941516fe950ejvanverth@google.com#ifdef PROGRAM_CACHE_STATS
50948787737b77555318fa2433e7ff941516fe950ejvanverth@google.com    , fTotalRequests(0)
51948787737b77555318fa2433e7ff941516fe950ejvanverth@google.com    , fCacheMisses(0)
522db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    , fHashMisses(0)
53948787737b77555318fa2433e7ff941516fe950ejvanverth@google.com#endif
54948787737b77555318fa2433e7ff941516fe950ejvanverth@google.com{
552db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    for (int i = 0; i < 1 << kHashBits; ++i) {
562db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        fHashTable[i] = NULL;
572db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    }
58948787737b77555318fa2433e7ff941516fe950ejvanverth@google.com}
59948787737b77555318fa2433e7ff941516fe950ejvanverth@google.com
60948787737b77555318fa2433e7ff941516fe950ejvanverth@google.comGrGpuGL::ProgramCache::~ProgramCache() {
612db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    for (int i = 0; i < fCount; ++i){
622db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        SkDELETE(fEntries[i]);
632db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    }
64948787737b77555318fa2433e7ff941516fe950ejvanverth@google.com    // dump stats
65948787737b77555318fa2433e7ff941516fe950ejvanverth@google.com#ifdef PROGRAM_CACHE_STATS
665c9b6faefff735110a59932793e81cf5b9dec51djvanverth@google.com    if (c_DisplayCache) {
675c9b6faefff735110a59932793e81cf5b9dec51djvanverth@google.com        SkDebugf("--- Program Cache ---\n");
685c9b6faefff735110a59932793e81cf5b9dec51djvanverth@google.com        SkDebugf("Total requests: %d\n", fTotalRequests);
695c9b6faefff735110a59932793e81cf5b9dec51djvanverth@google.com        SkDebugf("Cache misses: %d\n", fCacheMisses);
705c9b6faefff735110a59932793e81cf5b9dec51djvanverth@google.com        SkDebugf("Cache miss %%: %f\n", (fTotalRequests > 0) ?
715c9b6faefff735110a59932793e81cf5b9dec51djvanverth@google.com                                            100.f * fCacheMisses / fTotalRequests :
725c9b6faefff735110a59932793e81cf5b9dec51djvanverth@google.com                                            0.f);
735c9b6faefff735110a59932793e81cf5b9dec51djvanverth@google.com        int cacheHits = fTotalRequests - fCacheMisses;
745c9b6faefff735110a59932793e81cf5b9dec51djvanverth@google.com        SkDebugf("Hash miss %%: %f\n", (cacheHits > 0) ? 100.f * fHashMisses / cacheHits : 0.f);
755c9b6faefff735110a59932793e81cf5b9dec51djvanverth@google.com        SkDebugf("---------------------\n");
765c9b6faefff735110a59932793e81cf5b9dec51djvanverth@google.com    }
77948787737b77555318fa2433e7ff941516fe950ejvanverth@google.com#endif
78c1d2a58ec8510b226e080f5415a05723a686aab3bsalomon@google.com}
79f93e717c7f7ca679a80acbfda6a34013ae1e2b8djunov@google.com
80ecb60aad5c6fe5b1dbcfc86ac00bfc9326103c8dbsalomon@google.comvoid GrGpuGL::ProgramCache::abandon() {
81c1d2a58ec8510b226e080f5415a05723a686aab3bsalomon@google.com    for (int i = 0; i < fCount; ++i) {
8249f085dddff10473b6ebf832a974288300224e60bsalomon        SkASSERT(fEntries[i]->fProgram.get());
832db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        fEntries[i]->fProgram->abandon();
84944bcf0acb78f8f9da01e991f1307629959e338absalomon        SkDELETE(fEntries[i]);
85f93e717c7f7ca679a80acbfda6a34013ae1e2b8djunov@google.com    }
86c1d2a58ec8510b226e080f5415a05723a686aab3bsalomon@google.com    fCount = 0;
87c1d2a58ec8510b226e080f5415a05723a686aab3bsalomon@google.com}
88f93e717c7f7ca679a80acbfda6a34013ae1e2b8djunov@google.com
892db3ded335fdb6697623bece61cabc307a414770bsalomon@google.comint GrGpuGL::ProgramCache::search(const GrGLProgramDesc& desc) const {
902db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    ProgDescLess less;
912db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    return SkTSearch(fEntries, fCount, desc, sizeof(Entry*), less);
922db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com}
932db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com
94307796bc2e3731099d96773db7385fe70cb94f7degdanielGrGLProgram* GrGpuGL::ProgramCache::getProgram(const GrOptDrawState& optState,
95307796bc2e3731099d96773db7385fe70cb94f7degdaniel                                               const GrGLProgramDesc& desc,
9647bb38283072dc87dc93220cd2f370ca109972ffjoshualitt                                               DrawType type,
97b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                               const GrGeometryStage* geometryProcessor,
98b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                               const GrFragmentStage* colorStages[],
99b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                               const GrFragmentStage* coverageStages[]) {
100948787737b77555318fa2433e7ff941516fe950ejvanverth@google.com#ifdef PROGRAM_CACHE_STATS
101948787737b77555318fa2433e7ff941516fe950ejvanverth@google.com    ++fTotalRequests;
102948787737b77555318fa2433e7ff941516fe950ejvanverth@google.com#endif
1039ba4fa6f0fb8ef496d81ccac36e780aa806fea83bsalomon@google.com
1042db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    Entry* entry = NULL;
1052db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com
1062db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    uint32_t hashIdx = desc.getChecksum();
1072db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    hashIdx ^= hashIdx >> 16;
1082db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    if (kHashBits <= 8) {
1092db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        hashIdx ^= hashIdx >> 8;
1102db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    }
1112db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    hashIdx &=((1 << kHashBits) - 1);
1122db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    Entry* hashedEntry = fHashTable[hashIdx];
11349f085dddff10473b6ebf832a974288300224e60bsalomon    if (hashedEntry && hashedEntry->fProgram->getDesc() == desc) {
11449f085dddff10473b6ebf832a974288300224e60bsalomon        SkASSERT(hashedEntry->fProgram);
1152db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        entry = hashedEntry;
1162db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    }
1172db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com
1182db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    int entryIdx;
1192db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    if (NULL == entry) {
1202db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        entryIdx = this->search(desc);
1212db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        if (entryIdx >= 0) {
1222db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            entry = fEntries[entryIdx];
1232db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com#ifdef PROGRAM_CACHE_STATS
1242db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            ++fHashMisses;
1252db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com#endif
1262db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        }
1272db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    }
1282db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com
129c1d2a58ec8510b226e080f5415a05723a686aab3bsalomon@google.com    if (NULL == entry) {
1302db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        // We have a cache miss
131948787737b77555318fa2433e7ff941516fe950ejvanverth@google.com#ifdef PROGRAM_CACHE_STATS
132948787737b77555318fa2433e7ff941516fe950ejvanverth@google.com        ++fCacheMisses;
133948787737b77555318fa2433e7ff941516fe950ejvanverth@google.com#endif
13447bb38283072dc87dc93220cd2f370ca109972ffjoshualitt        GrGLProgram* program = GrGLProgramBuilder::CreateProgram(optState, desc, type,
13547bb38283072dc87dc93220cd2f370ca109972ffjoshualitt                                                                 geometryProcessor, colorStages,
13647bb38283072dc87dc93220cd2f370ca109972ffjoshualitt                                                                 coverageStages, fGpu);
1372db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        if (NULL == program) {
138c1d2a58ec8510b226e080f5415a05723a686aab3bsalomon@google.com            return NULL;
139c1d2a58ec8510b226e080f5415a05723a686aab3bsalomon@google.com        }
1402db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        int purgeIdx = 0;
141c1d2a58ec8510b226e080f5415a05723a686aab3bsalomon@google.com        if (fCount < kMaxEntries) {
1422db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            entry = SkNEW(Entry);
1432db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            purgeIdx = fCount++;
1442db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            fEntries[purgeIdx] = entry;
145c1d2a58ec8510b226e080f5415a05723a686aab3bsalomon@google.com        } else {
146f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org            SkASSERT(fCount == kMaxEntries);
1472db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            purgeIdx = 0;
148c1d2a58ec8510b226e080f5415a05723a686aab3bsalomon@google.com            for (int i = 1; i < kMaxEntries; ++i) {
1492db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com                if (fEntries[i]->fLRUStamp < fEntries[purgeIdx]->fLRUStamp) {
1502db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com                    purgeIdx = i;
151f93e717c7f7ca679a80acbfda6a34013ae1e2b8djunov@google.com                }
152f93e717c7f7ca679a80acbfda6a34013ae1e2b8djunov@google.com            }
1532db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            entry = fEntries[purgeIdx];
1542db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            int purgedHashIdx = entry->fProgram->getDesc().getChecksum() & ((1 << kHashBits) - 1);
1552db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            if (fHashTable[purgedHashIdx] == entry) {
1562db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com                fHashTable[purgedHashIdx] = NULL;
1572db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            }
158f93e717c7f7ca679a80acbfda6a34013ae1e2b8djunov@google.com        }
159f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org        SkASSERT(fEntries[purgeIdx] == entry);
1602db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        entry->fProgram.reset(program);
1612d816ad36e806e5b1cf3c447e547829bbbe74fd1skia.committer@gmail.com        // We need to shift fEntries around so that the entry currently at purgeIdx is placed
1622db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        // just before the entry at ~entryIdx (in order to keep fEntries sorted by descriptor).
1632db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        entryIdx = ~entryIdx;
1642db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        if (entryIdx < purgeIdx) {
1652db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            //  Let E and P be the entries at index entryIdx and purgeIdx, respectively.
1662db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            //  If the entries array looks like this:
1672db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            //       aaaaEbbbbbPccccc
1682db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            //  we rearrange it to look like this:
1692db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            //       aaaaPEbbbbbccccc
1702db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            size_t copySize = (purgeIdx - entryIdx) * sizeof(Entry*);
1712db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            memmove(fEntries + entryIdx + 1, fEntries + entryIdx, copySize);
1722db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            fEntries[entryIdx] = entry;
1732db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        } else if (purgeIdx < entryIdx) {
1742db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            //  If the entries array looks like this:
1752db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            //       aaaaPbbbbbEccccc
1762db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            //  we rearrange it to look like this:
1772db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            //       aaaabbbbbPEccccc
1782db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            size_t copySize = (entryIdx - purgeIdx - 1) * sizeof(Entry*);
1792db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            memmove(fEntries + purgeIdx, fEntries + purgeIdx + 1, copySize);
1802db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            fEntries[entryIdx - 1] = entry;
1812db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        }
182515dcd36032997ce335daa0163c6d67e851bcad1commit-bot@chromium.org#ifdef SK_DEBUG
18349f085dddff10473b6ebf832a974288300224e60bsalomon        SkASSERT(fEntries[0]->fProgram.get());
1842db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        for (int i = 0; i < fCount - 1; ++i) {
18549f085dddff10473b6ebf832a974288300224e60bsalomon            SkASSERT(fEntries[i + 1]->fProgram.get());
1862db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            const GrGLProgramDesc& a = fEntries[i]->fProgram->getDesc();
1872db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            const GrGLProgramDesc& b = fEntries[i + 1]->fProgram->getDesc();
188f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org            SkASSERT(GrGLProgramDesc::Less(a, b));
189f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org            SkASSERT(!GrGLProgramDesc::Less(b, a));
1902db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com        }
1912db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com#endif
192c1d2a58ec8510b226e080f5415a05723a686aab3bsalomon@google.com    }
193f93e717c7f7ca679a80acbfda6a34013ae1e2b8djunov@google.com
1942db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    fHashTable[hashIdx] = entry;
195c1d2a58ec8510b226e080f5415a05723a686aab3bsalomon@google.com    entry->fLRUStamp = fCurrLRUStamp;
1962db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com
1972db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com    if (SK_MaxU32 == fCurrLRUStamp) {
198c1d2a58ec8510b226e080f5415a05723a686aab3bsalomon@google.com        // wrap around! just trash our LRU, one time hit.
199c1d2a58ec8510b226e080f5415a05723a686aab3bsalomon@google.com        for (int i = 0; i < fCount; ++i) {
2002db3ded335fdb6697623bece61cabc307a414770bsalomon@google.com            fEntries[i]->fLRUStamp = 0;
201f93e717c7f7ca679a80acbfda6a34013ae1e2b8djunov@google.com        }
202f93e717c7f7ca679a80acbfda6a34013ae1e2b8djunov@google.com    }
203c1d2a58ec8510b226e080f5415a05723a686aab3bsalomon@google.com    ++fCurrLRUStamp;
2049ba4fa6f0fb8ef496d81ccac36e780aa806fea83bsalomon@google.com    return entry->fProgram;
205c1d2a58ec8510b226e080f5415a05723a686aab3bsalomon@google.com}
206f93e717c7f7ca679a80acbfda6a34013ae1e2b8djunov@google.com
2071e257a5db32e1c9e3b0dba80f43470816ef948afbsalomon@google.com////////////////////////////////////////////////////////////////////////////////
2081e257a5db32e1c9e3b0dba80f43470816ef948afbsalomon@google.com
2090b77d6892b067ad402c9678b0226bff70599fbe2bsalomon@google.com#define GL_CALL(X) GR_GL_CALL(this->glInterface(), X)
2100b77d6892b067ad402c9678b0226bff70599fbe2bsalomon@google.com
21126e18b593ab65e4d92dfbce92579d8bc180d4c2cbsalomon@google.combool GrGpuGL::flushGraphicsState(DrawType type, const GrDeviceCoordTexture* dstCopy) {
212b109ac22b4ec3ab3478f5304c96564a0e9df6170egdaniel    SkAutoTUnref<GrOptDrawState> optState(GrOptDrawState::Create(this->getDrawState(),
213b109ac22b4ec3ab3478f5304c96564a0e9df6170egdaniel                                                                 *this->caps(),
214b109ac22b4ec3ab3478f5304c96564a0e9df6170egdaniel                                                                 type));
215b109ac22b4ec3ab3478f5304c96564a0e9df6170egdaniel
216b109ac22b4ec3ab3478f5304c96564a0e9df6170egdaniel    if (!optState) {
217b109ac22b4ec3ab3478f5304c96564a0e9df6170egdaniel        return false;
218b109ac22b4ec3ab3478f5304c96564a0e9df6170egdaniel    }
2198f9cbd62ec108d410b91155dcf6a4789c641246fbsalomon@google.com
2206a51dcbf81cff6d92996ab3f4c7457478e441896bsalomon@google.com    // GrGpu::setupClipAndFlushState should have already checked this and bailed if not true.
221170f90b4576f291879371ecd6ae4bc2b1d85c64aegdaniel    SkASSERT(optState->getRenderTarget());
222c96cb3a929f954cd2e7b6319efdfa6b758b20bd3bsalomon@google.com
2236a51dcbf81cff6d92996ab3f4c7457478e441896bsalomon@google.com    if (kStencilPath_DrawType == type) {
224170f90b4576f291879371ecd6ae4bc2b1d85c64aegdaniel        const GrRenderTarget* rt = optState->getRenderTarget();
2256b30e457409f37c91c301cd82040e733e2930286commit-bot@chromium.org        SkISize size;
2266b30e457409f37c91c301cd82040e733e2930286commit-bot@chromium.org        size.set(rt->width(), rt->height());
227170f90b4576f291879371ecd6ae4bc2b1d85c64aegdaniel        this->glPathRendering()->setProjectionMatrix(optState->getViewMatrix(), size, rt->origin());
2286a51dcbf81cff6d92996ab3f4c7457478e441896bsalomon@google.com    } else {
229d632ea4b9eec5be3f83a9fa4982a30202e1239a7egdaniel        this->flushMiscFixedFunctionState(*optState.get());
2304be283f3a82895530d1b70372cd48ddb1c663fd8bsalomon@google.com
231170f90b4576f291879371ecd6ae4bc2b1d85c64aegdaniel        GrBlendCoeff srcCoeff = optState->getSrcBlendCoeff();
232170f90b4576f291879371ecd6ae4bc2b1d85c64aegdaniel        GrBlendCoeff dstCoeff = optState->getDstBlendCoeff();
233170f90b4576f291879371ecd6ae4bc2b1d85c64aegdaniel
234170f90b4576f291879371ecd6ae4bc2b1d85c64aegdaniel        // In these blend coeff's we end up drawing nothing so we can skip draw all together
235170f90b4576f291879371ecd6ae4bc2b1d85c64aegdaniel        if (kZero_GrBlendCoeff == srcCoeff && kOne_GrBlendCoeff == dstCoeff &&
236170f90b4576f291879371ecd6ae4bc2b1d85c64aegdaniel            !optState->getStencil().doesWrite()) {
237ded4f4b163f5aa19c22c871178c55ecb34623846bsalomon@google.com            return false;
238ded4f4b163f5aa19c22c871178c55ecb34623846bsalomon@google.com        }
239f93e717c7f7ca679a80acbfda6a34013ae1e2b8djunov@google.com
240b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt        const GrGeometryStage* geometryProcessor = NULL;
241b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt        SkSTArray<8, const GrFragmentStage*, true> colorStages;
242b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt        SkSTArray<8, const GrFragmentStage*, true> coverageStages;
24331ec7985f2b52a0cab4aa714a613b918cf663c08bsalomon@google.com        GrGLProgramDesc desc;
244170f90b4576f291879371ecd6ae4bc2b1d85c64aegdaniel        if (!GrGLProgramDesc::Build(*optState.get(),
245d909759832d5a6bb476597098e05bbe7ba0ccbd2joshualitt                               type,
246d909759832d5a6bb476597098e05bbe7ba0ccbd2joshualitt                               srcCoeff,
247d909759832d5a6bb476597098e05bbe7ba0ccbd2joshualitt                               dstCoeff,
248d909759832d5a6bb476597098e05bbe7ba0ccbd2joshualitt                               this,
249d909759832d5a6bb476597098e05bbe7ba0ccbd2joshualitt                               dstCopy,
250d909759832d5a6bb476597098e05bbe7ba0ccbd2joshualitt                               &geometryProcessor,
251d909759832d5a6bb476597098e05bbe7ba0ccbd2joshualitt                               &colorStages,
252d909759832d5a6bb476597098e05bbe7ba0ccbd2joshualitt                               &coverageStages,
253d909759832d5a6bb476597098e05bbe7ba0ccbd2joshualitt                               &desc)) {
254848faf00ec33d39ab3e31e9a11d805cae6ac6562bsalomon            SkDEBUGFAIL("Failed to generate GL program descriptor");
255848faf00ec33d39ab3e31e9a11d805cae6ac6562bsalomon            return false;
256848faf00ec33d39ab3e31e9a11d805cae6ac6562bsalomon        }
2579ba4fa6f0fb8ef496d81ccac36e780aa806fea83bsalomon@google.com
258307796bc2e3731099d96773db7385fe70cb94f7degdaniel        fCurrentProgram.reset(fProgramCache->getProgram(*optState.get(),
259307796bc2e3731099d96773db7385fe70cb94f7degdaniel                                                        desc,
26047bb38283072dc87dc93220cd2f370ca109972ffjoshualitt                                                        type,
261bd769d0f1c8cf6ccbb2738dfad1624a4c828e4ebjoshualitt                                                        geometryProcessor,
2622c84aa35988c661b3e5513c8ba9b3959832ff288bsalomon@google.com                                                        colorStages.begin(),
2632c84aa35988c661b3e5513c8ba9b3959832ff288bsalomon@google.com                                                        coverageStages.begin()));
2649ba4fa6f0fb8ef496d81ccac36e780aa806fea83bsalomon@google.com        if (NULL == fCurrentProgram.get()) {
265330313a8a8343876ee596da39da06a5d69badd9cmtklein@google.com            SkDEBUGFAIL("Failed to create program!");
266ded4f4b163f5aa19c22c871178c55ecb34623846bsalomon@google.com            return false;
267ded4f4b163f5aa19c22c871178c55ecb34623846bsalomon@google.com        }
268c4dc0ad8e252a7e30d19b47d3d0d9f2c69faf854commit-bot@chromium.org
2699ba4fa6f0fb8ef496d81ccac36e780aa806fea83bsalomon@google.com        fCurrentProgram.get()->ref();
2704c8837867add05f8d25520f92f6ec52305dda02ebsalomon@google.com
2716a51dcbf81cff6d92996ab3f4c7457478e441896bsalomon@google.com        GrGLuint programID = fCurrentProgram->programID();
2726a51dcbf81cff6d92996ab3f4c7457478e441896bsalomon@google.com        if (fHWProgramID != programID) {
2736a51dcbf81cff6d92996ab3f4c7457478e441896bsalomon@google.com            GL_CALL(UseProgram(programID));
2746a51dcbf81cff6d92996ab3f4c7457478e441896bsalomon@google.com            fHWProgramID = programID;
275ded4f4b163f5aa19c22c871178c55ecb34623846bsalomon@google.com        }
2766a51dcbf81cff6d92996ab3f4c7457478e441896bsalomon@google.com
277d632ea4b9eec5be3f83a9fa4982a30202e1239a7egdaniel        this->flushBlend(*optState.get(), kDrawLines_DrawType == type, srcCoeff, dstCoeff);
278ded4f4b163f5aa19c22c871178c55ecb34623846bsalomon@google.com
279170f90b4576f291879371ecd6ae4bc2b1d85c64aegdaniel        fCurrentProgram->setData(*optState.get(),
280170f90b4576f291879371ecd6ae4bc2b1d85c64aegdaniel                                 type,
281bd769d0f1c8cf6ccbb2738dfad1624a4c828e4ebjoshualitt                                 geometryProcessor,
2822c84aa35988c661b3e5513c8ba9b3959832ff288bsalomon@google.com                                 colorStages.begin(),
2832c84aa35988c661b3e5513c8ba9b3959832ff288bsalomon@google.com                                 coverageStages.begin(),
2842c84aa35988c661b3e5513c8ba9b3959832ff288bsalomon@google.com                                 dstCopy,
2852c84aa35988c661b3e5513c8ba9b3959832ff288bsalomon@google.com                                 &fSharedGLProgramState);
286f93e717c7f7ca679a80acbfda6a34013ae1e2b8djunov@google.com    }
287b0bd4f64a6827dda6f4ec48e4746b0f0b72a975fbsalomon
288170f90b4576f291879371ecd6ae4bc2b1d85c64aegdaniel    GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(optState->getRenderTarget());
289ded4f4b163f5aa19c22c871178c55ecb34623846bsalomon@google.com    this->flushStencil(type);
290b0bd4f64a6827dda6f4ec48e4746b0f0b72a975fbsalomon    this->flushScissor(glRT->getViewport(), glRT->origin());
291d632ea4b9eec5be3f83a9fa4982a30202e1239a7egdaniel    this->flushAAState(*optState.get(), type);
2924c8837867add05f8d25520f92f6ec52305dda02ebsalomon@google.com
293fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org    SkIRect* devRect = NULL;
294fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org    SkIRect devClipBounds;
295170f90b4576f291879371ecd6ae4bc2b1d85c64aegdaniel    if (optState->isClipState()) {
296170f90b4576f291879371ecd6ae4bc2b1d85c64aegdaniel        this->getClip()->getConservativeBounds(optState->getRenderTarget(), &devClipBounds);
2977b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com        devRect = &devClipBounds;
2984c8837867add05f8d25520f92f6ec52305dda02ebsalomon@google.com    }
2994c8837867add05f8d25520f92f6ec52305dda02ebsalomon@google.com    // This must come after textures are flushed because a texture may need
3004c8837867add05f8d25520f92f6ec52305dda02ebsalomon@google.com    // to be msaa-resolved (which will modify bound FBO state).
301b0bd4f64a6827dda6f4ec48e4746b0f0b72a975fbsalomon    this->flushRenderTarget(glRT, devRect);
3024c8837867add05f8d25520f92f6ec52305dda02ebsalomon@google.com
303f93e717c7f7ca679a80acbfda6a34013ae1e2b8djunov@google.com    return true;
304f93e717c7f7ca679a80acbfda6a34013ae1e2b8djunov@google.com}
305f93e717c7f7ca679a80acbfda6a34013ae1e2b8djunov@google.com
306880b8fcf255e67a15687e8b7cc47397372db683cbsalomon@google.comvoid GrGpuGL::setupGeometry(const DrawInfo& info, size_t* indexOffsetInBytes) {
307b109ac22b4ec3ab3478f5304c96564a0e9df6170egdaniel    SkAutoTUnref<GrOptDrawState> optState(
308b109ac22b4ec3ab3478f5304c96564a0e9df6170egdaniel        GrOptDrawState::Create(this->getDrawState(), *this->caps(),
309b109ac22b4ec3ab3478f5304c96564a0e9df6170egdaniel                               PrimTypeToDrawType(info.primitiveType())));
310b109ac22b4ec3ab3478f5304c96564a0e9df6170egdaniel
311b109ac22b4ec3ab3478f5304c96564a0e9df6170egdaniel    // If the optState would is NULL it should have been caught in flushGraphicsState before getting
312b109ac22b4ec3ab3478f5304c96564a0e9df6170egdaniel    // here.
313b109ac22b4ec3ab3478f5304c96564a0e9df6170egdaniel    SkASSERT(optState);
314f93e717c7f7ca679a80acbfda6a34013ae1e2b8djunov@google.com
315170f90b4576f291879371ecd6ae4bc2b1d85c64aegdaniel    GrGLsizei stride = static_cast<GrGLsizei>(optState->getVertexStride());
316880b8fcf255e67a15687e8b7cc47397372db683cbsalomon@google.com
3176918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com    size_t vertexOffsetInBytes = stride * info.startVertex();
3186918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com
3196918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com    const GeometryPoolState& geoPoolState = this->getGeomPoolState();
3206918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com
3216918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com    GrGLVertexBuffer* vbuf;
3226918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com    switch (this->getGeomSrc().fVertexSrc) {
3236918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com        case kBuffer_GeometrySrcType:
3246918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com            vbuf = (GrGLVertexBuffer*) this->getGeomSrc().fVertexBuffer;
3256918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com            break;
3266918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com        case kArray_GeometrySrcType:
3276918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com        case kReserved_GeometrySrcType:
3286918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com            this->finalizeReservedVertices();
3296918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com            vertexOffsetInBytes += geoPoolState.fPoolStartVertex * this->getGeomSrc().fVertexSize;
3306918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com            vbuf = (GrGLVertexBuffer*) geoPoolState.fPoolVertexBuffer;
3316918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com            break;
3326918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com        default:
3336918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com            vbuf = NULL; // suppress warning
33488cb22b6b4816c7a9ca6c5b795965b4606f9eb7bcommit-bot@chromium.org            SkFAIL("Unknown geometry src type!");
3356918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com    }
3366918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com
33749f085dddff10473b6ebf832a974288300224e60bsalomon    SkASSERT(vbuf);
3388341eb76fbc54593e873f5589961e02793e7f15fcommit-bot@chromium.org    SkASSERT(!vbuf->isMapped());
3396918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com    vertexOffsetInBytes += vbuf->baseOffset();
3406918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com
3416918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com    GrGLIndexBuffer* ibuf = NULL;
3426918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com    if (info.isIndexed()) {
34349f085dddff10473b6ebf832a974288300224e60bsalomon        SkASSERT(indexOffsetInBytes);
3446918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com
3456918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com        switch (this->getGeomSrc().fIndexSrc) {
3466918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com        case kBuffer_GeometrySrcType:
3476918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com            *indexOffsetInBytes = 0;
3486918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com            ibuf = (GrGLIndexBuffer*)this->getGeomSrc().fIndexBuffer;
3496918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com            break;
3506918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com        case kArray_GeometrySrcType:
3516918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com        case kReserved_GeometrySrcType:
3526918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com            this->finalizeReservedIndices();
3536918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com            *indexOffsetInBytes = geoPoolState.fPoolStartIndex * sizeof(GrGLushort);
3546918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com            ibuf = (GrGLIndexBuffer*) geoPoolState.fPoolIndexBuffer;
3556918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com            break;
3566918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com        default:
3576918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com            ibuf = NULL; // suppress warning
35888cb22b6b4816c7a9ca6c5b795965b4606f9eb7bcommit-bot@chromium.org            SkFAIL("Unknown geometry src type!");
3596918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com        }
3606918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com
36149f085dddff10473b6ebf832a974288300224e60bsalomon        SkASSERT(ibuf);
3628341eb76fbc54593e873f5589961e02793e7f15fcommit-bot@chromium.org        SkASSERT(!ibuf->isMapped());
3636918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com        *indexOffsetInBytes += ibuf->baseOffset();
3646918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com    }
3656918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com    GrGLAttribArrayState* attribState =
3666918d482d64f045a4c980b2fb267bc939953638ebsalomon@google.com        fHWGeometryState.bindArrayAndBuffersToDraw(this, vbuf, ibuf);
367880b8fcf255e67a15687e8b7cc47397372db683cbsalomon@google.com
3680a6fe71f1bc0e601b41b7ae6d28b8c96a2c41116commit-bot@chromium.org    if (fCurrentProgram->hasVertexShader()) {
369170f90b4576f291879371ecd6ae4bc2b1d85c64aegdaniel        int vertexAttribCount = optState->getVertexAttribCount();
3706b30e457409f37c91c301cd82040e733e2930286commit-bot@chromium.org        uint32_t usedAttribArraysMask = 0;
371170f90b4576f291879371ecd6ae4bc2b1d85c64aegdaniel        const GrVertexAttrib* vertexAttrib = optState->getVertexAttribs();
37202cafcc1bf6e2968c2efdf459871167970da150eegdaniel
3736b30e457409f37c91c301cd82040e733e2930286commit-bot@chromium.org        for (int vertexAttribIndex = 0; vertexAttribIndex < vertexAttribCount;
3746b30e457409f37c91c301cd82040e733e2930286commit-bot@chromium.org             ++vertexAttribIndex, ++vertexAttrib) {
3756b30e457409f37c91c301cd82040e733e2930286commit-bot@chromium.org            usedAttribArraysMask |= (1 << vertexAttribIndex);
3766b30e457409f37c91c301cd82040e733e2930286commit-bot@chromium.org            GrVertexAttribType attribType = vertexAttrib->fType;
3776b30e457409f37c91c301cd82040e733e2930286commit-bot@chromium.org            attribState->set(this,
3786b30e457409f37c91c301cd82040e733e2930286commit-bot@chromium.org                             vertexAttribIndex,
3796b30e457409f37c91c301cd82040e733e2930286commit-bot@chromium.org                             vbuf,
3806b30e457409f37c91c301cd82040e733e2930286commit-bot@chromium.org                             GrGLAttribTypeToLayout(attribType).fCount,
3816b30e457409f37c91c301cd82040e733e2930286commit-bot@chromium.org                             GrGLAttribTypeToLayout(attribType).fType,
3826b30e457409f37c91c301cd82040e733e2930286commit-bot@chromium.org                             GrGLAttribTypeToLayout(attribType).fNormalized,
3836b30e457409f37c91c301cd82040e733e2930286commit-bot@chromium.org                             stride,
3846b30e457409f37c91c301cd82040e733e2930286commit-bot@chromium.org                             reinterpret_cast<GrGLvoid*>(
3856ebfbf9968c76b0238f1b48296ff1b507e110ba1commit-bot@chromium.org                                 vertexOffsetInBytes + vertexAttrib->fOffset));
3866b30e457409f37c91c301cd82040e733e2930286commit-bot@chromium.org        }
3876ebfbf9968c76b0238f1b48296ff1b507e110ba1commit-bot@chromium.org        attribState->disableUnusedArrays(this, usedAttribArraysMask);
3886b30e457409f37c91c301cd82040e733e2930286commit-bot@chromium.org    }
389f93e717c7f7ca679a80acbfda6a34013ae1e2b8djunov@google.com}
390