1/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "GrProcessor.h"
9#include "GrContext.h"
10#include "GrContextPriv.h"
11#include "GrGeometryProcessor.h"
12#include "GrMemoryPool.h"
13#include "GrSamplerState.h"
14#include "GrTextureProxy.h"
15#include "GrXferProcessor.h"
16#include "SkSpinlock.h"
17
18#if GR_TEST_UTILS
19
20GrResourceProvider* GrProcessorTestData::resourceProvider() {
21    return fContext->contextPriv().resourceProvider();
22}
23
24GrProxyProvider* GrProcessorTestData::proxyProvider() {
25    return fContext->contextPriv().proxyProvider();
26}
27
28const GrCaps* GrProcessorTestData::caps() {
29    return fContext->caps();
30}
31
32#if SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
33class GrFragmentProcessor;
34class GrGeometryProcessor;
35
36/*
37 * Originally these were both in the processor unit test header, but then it seemed to cause linker
38 * problems on android.
39 */
40template <>
41SkTArray<GrFragmentProcessorTestFactory*, true>* GrFragmentProcessorTestFactory::GetFactories() {
42    static SkTArray<GrFragmentProcessorTestFactory*, true> gFactories;
43    return &gFactories;
44}
45
46template <>
47SkTArray<GrGeometryProcessorTestFactory*, true>* GrGeometryProcessorTestFactory::GetFactories() {
48    static SkTArray<GrGeometryProcessorTestFactory*, true> gFactories;
49    return &gFactories;
50}
51
52SkTArray<GrXPFactoryTestFactory*, true>* GrXPFactoryTestFactory::GetFactories() {
53    static SkTArray<GrXPFactoryTestFactory*, true> gFactories;
54    return &gFactories;
55}
56
57/*
58 * To ensure we always have successful static initialization, before creating from the factories
59 * we verify the count is as expected.  If a new factory is added, then these numbers must be
60 * manually adjusted.
61 */
62static const int kFPFactoryCount = 38;
63static const int kGPFactoryCount = 14;
64static const int kXPFactoryCount = 4;
65
66template <>
67void GrFragmentProcessorTestFactory::VerifyFactoryCount() {
68    if (kFPFactoryCount != GetFactories()->count()) {
69        SkDebugf("\nExpected %d fragment processor factories, found %d.\n",
70                 kFPFactoryCount, GetFactories()->count());
71        SK_ABORT("Wrong number of fragment processor factories!");
72    }
73}
74
75template <>
76void GrGeometryProcessorTestFactory::VerifyFactoryCount() {
77    if (kGPFactoryCount != GetFactories()->count()) {
78        SkDebugf("\nExpected %d geometry processor factories, found %d.\n",
79                 kGPFactoryCount, GetFactories()->count());
80        SK_ABORT("Wrong number of geometry processor factories!");
81    }
82}
83
84void GrXPFactoryTestFactory::VerifyFactoryCount() {
85    if (kXPFactoryCount != GetFactories()->count()) {
86        SkDebugf("\nExpected %d xp factory factories, found %d.\n",
87                 kXPFactoryCount, GetFactories()->count());
88        SK_ABORT("Wrong number of xp factory factories!");
89    }
90}
91
92#endif
93#endif
94
95
96// We use a global pool protected by a mutex(spinlock). Chrome may use the same GrContext on
97// different threads. The GrContext is not used concurrently on different threads and there is a
98// memory barrier between accesses of a context on different threads. Also, there may be multiple
99// GrContexts and those contexts may be in use concurrently on different threads.
100namespace {
101#if !defined(SK_BUILD_FOR_ANDROID_FRAMEWORK)
102static SkSpinlock gProcessorSpinlock;
103#endif
104class MemoryPoolAccessor {
105public:
106
107// We know in the Android framework there is only one GrContext.
108#if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK)
109    MemoryPoolAccessor() {}
110    ~MemoryPoolAccessor() {}
111#else
112    MemoryPoolAccessor() { gProcessorSpinlock.acquire(); }
113    ~MemoryPoolAccessor() { gProcessorSpinlock.release(); }
114#endif
115
116    GrMemoryPool* pool() const {
117        static GrMemoryPool gPool(4096, 4096);
118        return &gPool;
119    }
120};
121}
122
123///////////////////////////////////////////////////////////////////////////////
124
125void* GrProcessor::operator new(size_t size) { return MemoryPoolAccessor().pool()->allocate(size); }
126
127void GrProcessor::operator delete(void* target) {
128    return MemoryPoolAccessor().pool()->release(target);
129}
130
131///////////////////////////////////////////////////////////////////////////////
132
133void GrResourceIOProcessor::addTextureSampler(const TextureSampler* access) {
134    fTextureSamplers.push_back(access);
135}
136
137void GrResourceIOProcessor::addBufferAccess(const BufferAccess* access) {
138    fBufferAccesses.push_back(access);
139}
140
141void GrResourceIOProcessor::addPendingIOs() const {
142    for (const auto& sampler : fTextureSamplers) {
143        sampler->programProxy()->markPendingIO();
144    }
145    for (const auto& buffer : fBufferAccesses) {
146        buffer->programBuffer()->markPendingIO();
147    }
148}
149
150void GrResourceIOProcessor::removeRefs() const {
151    for (const auto& sampler : fTextureSamplers) {
152        sampler->programProxy()->removeRef();
153    }
154    for (const auto& buffer : fBufferAccesses) {
155        buffer->programBuffer()->removeRef();
156    }
157}
158
159void GrResourceIOProcessor::pendingIOComplete() const {
160    for (const auto& sampler : fTextureSamplers) {
161        sampler->programProxy()->pendingIOComplete();
162    }
163    for (const auto& buffer : fBufferAccesses) {
164        buffer->programBuffer()->pendingIOComplete();
165    }
166}
167
168bool GrResourceIOProcessor::instantiate(GrResourceProvider* resourceProvider) const {
169    for (const auto& sampler : fTextureSamplers) {
170        if (!sampler->instantiate(resourceProvider)) {
171            return false;
172        }
173    }
174
175    // MDB TODO: instantiate 'fBufferAccesses' here as well
176
177    return true;
178}
179
180bool GrResourceIOProcessor::hasSameSamplersAndAccesses(const GrResourceIOProcessor& that) const {
181    if (this->numTextureSamplers() != that.numTextureSamplers() ||
182        this->numBuffers() != that.numBuffers()) {
183        return false;
184    }
185    for (int i = 0; i < this->numTextureSamplers(); ++i) {
186        if (this->textureSampler(i) != that.textureSampler(i)) {
187            return false;
188        }
189    }
190    for (int i = 0; i < this->numBuffers(); ++i) {
191        if (this->bufferAccess(i) != that.bufferAccess(i)) {
192            return false;
193        }
194    }
195    return true;
196}
197
198///////////////////////////////////////////////////////////////////////////////////////////////////
199
200GrResourceIOProcessor::TextureSampler::TextureSampler() {}
201
202GrResourceIOProcessor::TextureSampler::TextureSampler(sk_sp<GrTextureProxy> proxy,
203                                                      const GrSamplerState& samplerState) {
204    this->reset(std::move(proxy), samplerState);
205}
206
207GrResourceIOProcessor::TextureSampler::TextureSampler(sk_sp<GrTextureProxy> proxy,
208                                                      GrSamplerState::Filter filterMode,
209                                                      GrSamplerState::WrapMode wrapXAndY,
210                                                      GrShaderFlags visibility) {
211    this->reset(std::move(proxy), filterMode, wrapXAndY, visibility);
212}
213
214void GrResourceIOProcessor::TextureSampler::reset(sk_sp<GrTextureProxy> proxy,
215                                                  const GrSamplerState& samplerState,
216                                                  GrShaderFlags visibility) {
217    fSamplerState = samplerState;
218    fProxyRef.setProxy(std::move(proxy), kRead_GrIOType);
219    fSamplerState.setFilterMode(SkTMin(samplerState.filter(), this->proxy()->highestFilterMode()));
220    fVisibility = visibility;
221}
222
223void GrResourceIOProcessor::TextureSampler::reset(sk_sp<GrTextureProxy> proxy,
224                                                  GrSamplerState::Filter filterMode,
225                                                  GrSamplerState::WrapMode wrapXAndY,
226                                                  GrShaderFlags visibility) {
227    fProxyRef.setProxy(std::move(proxy), kRead_GrIOType);
228    filterMode = SkTMin(filterMode, this->proxy()->highestFilterMode());
229    fSamplerState = GrSamplerState(wrapXAndY, filterMode);
230    fVisibility = visibility;
231}
232