17361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com/*
27361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com * Copyright 2012 Google Inc.
37361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com *
47361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com * Use of this source code is governed by a BSD-style license that can be
57361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com * found in the LICENSE file.
67361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com */
77361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com
87361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com#ifndef GrContextFactory_DEFINED
97361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com#define GrContextFactory_DEFINED
107361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com
117361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com#if SK_ANGLE
127361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com    #include "gl/SkANGLEGLContext.h"
137361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com#endif
147361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com#include "gl/SkDebugGLContext.h"
157361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com#if SK_MESA
167361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com    #include "gl/SkMesaGLContext.h"
177361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com#endif
187361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com#include "gl/SkNativeGLContext.h"
197361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com#include "gl/SkNullGLContext.h"
207361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com
217361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com#include "GrContext.h"
22a2d71482db8b6d752a51c96da74768d7dfc27932robertphillips@google.com#include "SkTArray.h"
237361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com
247361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com/**
25fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com * This is a simple class that is useful in test apps that use different
267361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com * GrContexts backed by different types of GL contexts. It manages creating the
277361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com * GL context and a GrContext that uses it. The GL/Gr contexts persist until the
287361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com * factory is destroyed (though the caller can always grab a ref on the returned
29d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org * Gr and GL contexts to make them outlive the factory).
307361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com */
31e3beb6bd7de7fa211681abbb0be58e80b19885e0commit-bot@chromium.orgclass GrContextFactory : SkNoncopyable {
327361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.compublic:
337361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com    /**
34d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org     * Types of GL contexts supported. For historical and testing reasons the native GrContext will
35d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org     * not use "GL_NV_path_rendering" even when the driver supports it. There is a separate context
36d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org     * type that does not remove NVPR support and which will fail when the driver does not support
37d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org     * the extension.
387361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com     */
397361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com    enum GLContextType {
407361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com      kNative_GLContextType,
417361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com#if SK_ANGLE
427361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com      kANGLE_GLContextType,
437361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com#endif
447361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com#if SK_MESA
457361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com      kMESA_GLContextType,
467361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com#endif
47d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org      /** Similar to kNative but does not filter NVPR. It will fail if the GL driver does not
48d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org          support NVPR */
49d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org      kNVPR_GLContextType,
507361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com      kNull_GLContextType,
517361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com      kDebug_GLContextType,
5267b915de99e6b89d476907930ac8c27afb64d10ebsalomon@google.com
5367b915de99e6b89d476907930ac8c27afb64d10ebsalomon@google.com      kLastGLContextType = kDebug_GLContextType
547361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com    };
557361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com
5667b915de99e6b89d476907930ac8c27afb64d10ebsalomon@google.com    static const int kGLContextTypeCnt = kLastGLContextType + 1;
5767b915de99e6b89d476907930ac8c27afb64d10ebsalomon@google.com
5867b915de99e6b89d476907930ac8c27afb64d10ebsalomon@google.com    static bool IsRenderingGLContext(GLContextType type) {
5967b915de99e6b89d476907930ac8c27afb64d10ebsalomon@google.com        switch (type) {
6067b915de99e6b89d476907930ac8c27afb64d10ebsalomon@google.com            case kNull_GLContextType:
6167b915de99e6b89d476907930ac8c27afb64d10ebsalomon@google.com            case kDebug_GLContextType:
6267b915de99e6b89d476907930ac8c27afb64d10ebsalomon@google.com                return false;
6367b915de99e6b89d476907930ac8c27afb64d10ebsalomon@google.com            default:
6467b915de99e6b89d476907930ac8c27afb64d10ebsalomon@google.com                return true;
6567b915de99e6b89d476907930ac8c27afb64d10ebsalomon@google.com        }
6667b915de99e6b89d476907930ac8c27afb64d10ebsalomon@google.com    }
6767b915de99e6b89d476907930ac8c27afb64d10ebsalomon@google.com
68cb26535ff71fc323278892d6b90546b3b1c54649bsalomon@google.com    static const char* GLContextTypeName(GLContextType type) {
69cb26535ff71fc323278892d6b90546b3b1c54649bsalomon@google.com        switch (type) {
70cb26535ff71fc323278892d6b90546b3b1c54649bsalomon@google.com            case kNative_GLContextType:
71cb26535ff71fc323278892d6b90546b3b1c54649bsalomon@google.com                return "native";
72cb26535ff71fc323278892d6b90546b3b1c54649bsalomon@google.com            case kNull_GLContextType:
73cb26535ff71fc323278892d6b90546b3b1c54649bsalomon@google.com                return "null";
74cb26535ff71fc323278892d6b90546b3b1c54649bsalomon@google.com#if SK_ANGLE
75cb26535ff71fc323278892d6b90546b3b1c54649bsalomon@google.com            case kANGLE_GLContextType:
76cb26535ff71fc323278892d6b90546b3b1c54649bsalomon@google.com                return "angle";
77cb26535ff71fc323278892d6b90546b3b1c54649bsalomon@google.com#endif
78cb26535ff71fc323278892d6b90546b3b1c54649bsalomon@google.com#if SK_MESA
79cb26535ff71fc323278892d6b90546b3b1c54649bsalomon@google.com            case kMESA_GLContextType:
80cb26535ff71fc323278892d6b90546b3b1c54649bsalomon@google.com                return "mesa";
81cb26535ff71fc323278892d6b90546b3b1c54649bsalomon@google.com#endif
82d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org            case kNVPR_GLContextType:
83d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org                return "nvpr";
84cb26535ff71fc323278892d6b90546b3b1c54649bsalomon@google.com            case kDebug_GLContextType:
85cb26535ff71fc323278892d6b90546b3b1c54649bsalomon@google.com                return "debug";
86cb26535ff71fc323278892d6b90546b3b1c54649bsalomon@google.com            default:
8788cb22b6b4816c7a9ca6c5b795965b4606f9eb7bcommit-bot@chromium.org                SkFAIL("Unknown GL Context type.");
88cb26535ff71fc323278892d6b90546b3b1c54649bsalomon@google.com        }
89cb26535ff71fc323278892d6b90546b3b1c54649bsalomon@google.com    }
90cb26535ff71fc323278892d6b90546b3b1c54649bsalomon@google.com
917361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com    GrContextFactory() {
927361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com    }
937361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com
9467b915de99e6b89d476907930ac8c27afb64d10ebsalomon@google.com    ~GrContextFactory() { this->destroyContexts(); }
9567b915de99e6b89d476907930ac8c27afb64d10ebsalomon@google.com
9667b915de99e6b89d476907930ac8c27afb64d10ebsalomon@google.com    void destroyContexts() {
977361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com        for (int i = 0; i < fContexts.count(); ++i) {
98d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org            fContexts[i].fGLContext->makeCurrent();
997361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com            fContexts[i].fGrContext->unref();
1007361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com            fContexts[i].fGLContext->unref();
1017361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com        }
10267b915de99e6b89d476907930ac8c27afb64d10ebsalomon@google.com        fContexts.reset();
1037361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com    }
1047361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com
1057361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com    /**
10667b915de99e6b89d476907930ac8c27afb64d10ebsalomon@google.com     * Get a GrContext initialized with a type of GL context. It also makes the GL context current.
1077361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com     */
1087361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com    GrContext* get(GLContextType type) {
1097361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com
1107361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com        for (int i = 0; i < fContexts.count(); ++i) {
1117361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com            if (fContexts[i].fType == type) {
11267b915de99e6b89d476907930ac8c27afb64d10ebsalomon@google.com                fContexts[i].fGLContext->makeCurrent();
1137361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com                return fContexts[i].fGrContext;
1147361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com            }
1157361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com        }
1166177e6999d23a4268ffd98dedfb1da00e272a89brobertphillips@google.com        SkAutoTUnref<SkGLContextHelper> glCtx;
1177361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com        SkAutoTUnref<GrContext> grCtx;
1187361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com        switch (type) {
119d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org            case kNVPR_GLContextType: // fallthru
1207361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com            case kNative_GLContextType:
121c377baf406996aed18d82d328029c82dbc3b8ddatomhudson@google.com                glCtx.reset(SkNEW(SkNativeGLContext));
1227361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com                break;
1237361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com#ifdef SK_ANGLE
1247361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com            case kANGLE_GLContextType:
125c377baf406996aed18d82d328029c82dbc3b8ddatomhudson@google.com                glCtx.reset(SkNEW(SkANGLEGLContext));
1267361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com                break;
1277361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com#endif
1287361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com#ifdef SK_MESA
1297361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com            case kMESA_GLContextType:
130c377baf406996aed18d82d328029c82dbc3b8ddatomhudson@google.com                glCtx.reset(SkNEW(SkMesaGLContext));
1317361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com                break;
1327361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com#endif
1337361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com            case kNull_GLContextType:
134c377baf406996aed18d82d328029c82dbc3b8ddatomhudson@google.com                glCtx.reset(SkNEW(SkNullGLContext));
1357361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com                break;
1367361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com            case kDebug_GLContextType:
137c377baf406996aed18d82d328029c82dbc3b8ddatomhudson@google.com                glCtx.reset(SkNEW(SkDebugGLContext));
1387361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com                break;
1397361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com        }
1407361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com        static const int kBogusSize = 1;
1417361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com        if (!glCtx.get()) {
1427361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com            return NULL;
1437361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com        }
1447361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com        if (!glCtx.get()->init(kBogusSize, kBogusSize)) {
1457361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com            return NULL;
1467361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com        }
147d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org
148d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org        // Ensure NVPR is available for the NVPR type and block it from other types.
149d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org        SkAutoTUnref<const GrGLInterface> glInterface(SkRef(glCtx.get()->gl()));
150d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org        if (kNVPR_GLContextType == type) {
151d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org            if (!glInterface->hasExtension("GL_NV_path_rendering")) {
152d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org                return NULL;
153d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org            }
154d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org        } else {
155d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org            glInterface.reset(GrGLInterfaceRemoveNVPR(glInterface));
156d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org            if (!glInterface) {
157d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org                return NULL;
158d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org            }
159d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org        }
160d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org
161d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org        glCtx->makeCurrent();
162d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org        GrBackendContext p3dctx = reinterpret_cast<GrBackendContext>(glInterface.get());
16316e3ddea6a80972aced04b21b1d66377fa95e7c7bsalomon@google.com        grCtx.reset(GrContext::Create(kOpenGL_GrBackend, p3dctx));
1647361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com        if (!grCtx.get()) {
1657361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com            return NULL;
1667361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com        }
1677361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com        GPUContext& ctx = fContexts.push_back();
1687361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com        ctx.fGLContext = glCtx.get();
1697361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com        ctx.fGLContext->ref();
1707361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com        ctx.fGrContext = grCtx.get();
1717361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com        ctx.fGrContext->ref();
1727361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com        ctx.fType = type;
1737361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com        return ctx.fGrContext;
1747361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com    }
1755bdef29ae0f5a495381cd2c9787ce7c112e58354keyar@chromium.org
1765bdef29ae0f5a495381cd2c9787ce7c112e58354keyar@chromium.org    // Returns the GLContext of the given type. If it has not been created yet,
1775bdef29ae0f5a495381cd2c9787ce7c112e58354keyar@chromium.org    // NULL is returned instead.
1786177e6999d23a4268ffd98dedfb1da00e272a89brobertphillips@google.com    SkGLContextHelper* getGLContext(GLContextType type) {
1795bdef29ae0f5a495381cd2c9787ce7c112e58354keyar@chromium.org        for (int i = 0; i < fContexts.count(); ++i) {
1805bdef29ae0f5a495381cd2c9787ce7c112e58354keyar@chromium.org            if (fContexts[i].fType == type) {
1815bdef29ae0f5a495381cd2c9787ce7c112e58354keyar@chromium.org                return fContexts[i].fGLContext;
1825bdef29ae0f5a495381cd2c9787ce7c112e58354keyar@chromium.org            }
1835bdef29ae0f5a495381cd2c9787ce7c112e58354keyar@chromium.org        }
1845bdef29ae0f5a495381cd2c9787ce7c112e58354keyar@chromium.org
1855bdef29ae0f5a495381cd2c9787ce7c112e58354keyar@chromium.org        return NULL;
1865bdef29ae0f5a495381cd2c9787ce7c112e58354keyar@chromium.org    }
1875bdef29ae0f5a495381cd2c9787ce7c112e58354keyar@chromium.org
1887361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.comprivate:
1897361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com    struct GPUContext {
1907361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com        GLContextType             fType;
1916177e6999d23a4268ffd98dedfb1da00e272a89brobertphillips@google.com        SkGLContextHelper*        fGLContext;
1927361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com        GrContext*                fGrContext;
1937361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com    };
1947361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com    SkTArray<GPUContext, true> fContexts;
1957361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com};
1967361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com
1977361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com#endif
198