1 /*
2  * Copyright 2016 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 // This is a GPU-backend specific test.
9 
10 #include "Test.h"
11 
12 #if SK_SUPPORT_GPU
13 #include "GrRenderTargetPriv.h"
14 #include "GrRenderTargetProxy.h"
15 #include "GrResourceProvider.h"
16 #include "GrSurfaceProxy.h"
17 #include "GrTextureProxy.h"
18 
getProxyRefCnt_TestOnly() const19 int32_t GrIORefProxy::getProxyRefCnt_TestOnly() const {
20     return fRefCnt;
21 }
22 
getBackingRefCnt_TestOnly() const23 int32_t GrIORefProxy::getBackingRefCnt_TestOnly() const {
24     if (fTarget) {
25         return fTarget->fRefCnt;
26     }
27 
28     return fRefCnt;
29 }
30 
getPendingReadCnt_TestOnly() const31 int32_t GrIORefProxy::getPendingReadCnt_TestOnly() const {
32     if (fTarget) {
33         SkASSERT(!fPendingReads);
34         return fTarget->fPendingReads;
35     }
36 
37     return fPendingReads;
38 }
39 
getPendingWriteCnt_TestOnly() const40 int32_t GrIORefProxy::getPendingWriteCnt_TestOnly() const {
41     if (fTarget) {
42         SkASSERT(!fPendingWrites);
43         return fTarget->fPendingWrites;
44     }
45 
46     return fPendingWrites;
47 }
48 
49 static const int kWidthHeight = 128;
50 
check_refs(skiatest::Reporter * reporter,GrSurfaceProxy * proxy,int32_t expectedProxyRefs,int32_t expectedBackingRefs,int32_t expectedNumReads,int32_t expectedNumWrites)51 static void check_refs(skiatest::Reporter* reporter,
52                        GrSurfaceProxy* proxy,
53                        int32_t expectedProxyRefs,
54                        int32_t expectedBackingRefs,
55                        int32_t expectedNumReads,
56                        int32_t expectedNumWrites) {
57     REPORTER_ASSERT(reporter, proxy->getProxyRefCnt_TestOnly() == expectedProxyRefs);
58     REPORTER_ASSERT(reporter, proxy->getBackingRefCnt_TestOnly() == expectedBackingRefs);
59     REPORTER_ASSERT(reporter, proxy->getPendingReadCnt_TestOnly() == expectedNumReads);
60     REPORTER_ASSERT(reporter, proxy->getPendingWriteCnt_TestOnly() == expectedNumWrites);
61 
62     SkASSERT(proxy->getProxyRefCnt_TestOnly() == expectedProxyRefs);
63     SkASSERT(proxy->getBackingRefCnt_TestOnly() == expectedBackingRefs);
64     SkASSERT(proxy->getPendingReadCnt_TestOnly() == expectedNumReads);
65     SkASSERT(proxy->getPendingWriteCnt_TestOnly() == expectedNumWrites);
66 }
67 
make_deferred(GrResourceProvider * provider)68 static sk_sp<GrSurfaceProxy> make_deferred(GrResourceProvider* provider) {
69     GrSurfaceDesc desc;
70     desc.fFlags = kRenderTarget_GrSurfaceFlag;
71     desc.fWidth = kWidthHeight;
72     desc.fHeight = kWidthHeight;
73     desc.fConfig = kRGBA_8888_GrPixelConfig;
74 
75     return GrSurfaceProxy::MakeDeferred(provider, desc,
76                                         SkBackingFit::kApprox, SkBudgeted::kYes);
77 }
78 
make_wrapped(GrResourceProvider * provider)79 static sk_sp<GrSurfaceProxy> make_wrapped(GrResourceProvider* provider) {
80     GrSurfaceDesc desc;
81     desc.fFlags = kRenderTarget_GrSurfaceFlag;
82     desc.fWidth = kWidthHeight;
83     desc.fHeight = kWidthHeight;
84     desc.fConfig = kRGBA_8888_GrPixelConfig;
85 
86     sk_sp<GrTexture> tex(provider->createTexture(desc, SkBudgeted::kNo));
87 
88     // Flush the IOWrite from the initial discard or it will confuse the later ref count checks
89     tex->flushWrites();
90 
91     return GrSurfaceProxy::MakeWrapped(std::move(tex));
92 }
93 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ProxyRefTest,reporter,ctxInfo)94 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ProxyRefTest, reporter, ctxInfo) {
95     GrResourceProvider* provider = ctxInfo.grContext()->resourceProvider();
96     const GrCaps& caps = *ctxInfo.grContext()->caps();
97 
98     // Currently the op itself takes a pending write and the render target op list does as well.
99     static const int kWritesForDiscard = 2;
100     for (auto make : { make_deferred, make_wrapped }) {
101         // A single write
102         {
103             sk_sp<GrSurfaceProxy> sProxy((*make)(provider));
104 
105             GrPendingIOResource<GrSurfaceProxy, kWrite_GrIOType> fWrite(sProxy.get());
106 
107             check_refs(reporter, sProxy.get(), 1, 1, 0, 1);
108 
109             // In the deferred case, the discard op created on instantiation adds an
110             // extra ref and write
111             bool proxyGetsDiscardRef = !sProxy->isWrapped_ForTesting() &&
112                                        caps.discardRenderTargetSupport();
113             int expectedWrites = 1 + (proxyGetsDiscardRef ? kWritesForDiscard : 0);
114 
115             sProxy->instantiate(provider);
116 
117             // In the deferred case, this checks that the refs transfered to the GrSurface
118             check_refs(reporter, sProxy.get(), 1, 1, 0, expectedWrites);
119         }
120 
121         // A single read
122         {
123             sk_sp<GrSurfaceProxy> sProxy((*make)(provider));
124 
125             GrPendingIOResource<GrSurfaceProxy, kRead_GrIOType> fRead(sProxy.get());
126 
127             check_refs(reporter, sProxy.get(), 1, 1, 1, 0);
128 
129             // In the deferred case, the discard op created on instantiation adds an
130             // extra ref and write
131             bool proxyGetsDiscardRef = !sProxy->isWrapped_ForTesting() &&
132                                        caps.discardRenderTargetSupport();
133             int expectedWrites = proxyGetsDiscardRef ? kWritesForDiscard : 0;
134 
135             sProxy->instantiate(provider);
136 
137             // In the deferred case, this checks that the refs transfered to the GrSurface
138             check_refs(reporter, sProxy.get(), 1, 1, 1, expectedWrites);
139         }
140 
141         // A single read/write pair
142         {
143             sk_sp<GrSurfaceProxy> sProxy((*make)(provider));
144 
145             GrPendingIOResource<GrSurfaceProxy, kRW_GrIOType> fRW(sProxy.get());
146 
147             check_refs(reporter, sProxy.get(), 1, 1, 1, 1);
148 
149             // In the deferred case, the discard op created on instantiation adds an
150             // extra ref and write
151             bool proxyGetsDiscardRef = !sProxy->isWrapped_ForTesting() &&
152                                        caps.discardRenderTargetSupport();
153             int expectedWrites = 1 + (proxyGetsDiscardRef ? kWritesForDiscard : 0);
154 
155             sProxy->instantiate(provider);
156 
157             // In the deferred case, this checks that the refs transferred to the GrSurface
158             check_refs(reporter, sProxy.get(), 1, 1, 1, expectedWrites);
159         }
160 
161         // Multiple normal refs
162         {
163             sk_sp<GrSurfaceProxy> sProxy((*make)(provider));
164             sProxy->ref();
165             sProxy->ref();
166 
167             check_refs(reporter, sProxy.get(), 3, 3, 0, 0);
168 
169             bool proxyGetsDiscardRef = !sProxy->isWrapped_ForTesting() &&
170                                        caps.discardRenderTargetSupport();
171             int expectedWrites = proxyGetsDiscardRef ? kWritesForDiscard : 0;
172 
173             sProxy->instantiate(provider);
174 
175             // In the deferred case, this checks that the refs transferred to the GrSurface
176             check_refs(reporter, sProxy.get(), 3, 3, 0, expectedWrites);
177 
178             sProxy->unref();
179             sProxy->unref();
180         }
181 
182         // Continue using (reffing) proxy after instantiation
183         {
184             sk_sp<GrSurfaceProxy> sProxy((*make)(provider));
185             sProxy->ref();
186 
187             GrPendingIOResource<GrSurfaceProxy, kWrite_GrIOType> fWrite(sProxy.get());
188 
189             check_refs(reporter, sProxy.get(), 2, 2, 0, 1);
190 
191             bool proxyGetsDiscardRef = !sProxy->isWrapped_ForTesting() &&
192                                        caps.discardRenderTargetSupport();
193             int expectedWrites = 1 + (proxyGetsDiscardRef ? kWritesForDiscard : 0);
194 
195             sProxy->instantiate(provider);
196 
197             // In the deferred case, this checks that the refs transfered to the GrSurface
198             check_refs(reporter, sProxy.get(), 2, 2, 0, expectedWrites);
199 
200             sProxy->unref();
201             check_refs(reporter, sProxy.get(), 1, 1, 0, expectedWrites);
202 
203             GrPendingIOResource<GrSurfaceProxy, kRead_GrIOType> fRead(sProxy.get());
204             check_refs(reporter, sProxy.get(), 1, 1, 1, expectedWrites);
205         }
206     }
207 }
208 #endif
209