1 /*
2 * Copyright 2017 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 #include "src/gpu/ganesh/mock/GrMockGpu.h"
8
9 #include "include/gpu/GpuTypes.h"
10 #include "include/private/base/SkDebug.h"
11 #include "include/private/base/SkMath.h"
12 #include "src/gpu/ganesh/GrCaps.h"
13 #include "src/gpu/ganesh/GrGpuBuffer.h"
14 #include "src/gpu/ganesh/GrRenderTarget.h"
15 #include "src/gpu/ganesh/GrTexture.h"
16 #include "src/gpu/ganesh/GrThreadSafePipelineBuilder.h" // IWYU pragma: keep
17 #include "src/gpu/ganesh/mock/GrMockAttachment.h"
18 #include "src/gpu/ganesh/mock/GrMockBuffer.h"
19 #include "src/gpu/ganesh/mock/GrMockCaps.h"
20 #include "src/gpu/ganesh/mock/GrMockOpsRenderPass.h"
21 #include "src/gpu/ganesh/mock/GrMockTexture.h"
22
23 #include <atomic>
24
25 using namespace skia_private;
26
NextInternalTextureID()27 int GrMockGpu::NextInternalTextureID() {
28 static std::atomic<int> nextID{1};
29 int id;
30 do {
31 id = nextID.fetch_add(1, std::memory_order_relaxed);
32 } while (0 == id); // Reserve 0 for an invalid ID.
33 return id;
34 }
35
NextExternalTextureID()36 int GrMockGpu::NextExternalTextureID() {
37 // We use negative ints for the "testing only external textures" so they can easily be
38 // identified when debugging.
39 static std::atomic<int> nextID{-1};
40 return nextID.fetch_add(-1, std::memory_order_relaxed);
41 }
42
NextInternalRenderTargetID()43 int GrMockGpu::NextInternalRenderTargetID() {
44 // We start off with large numbers to differentiate from texture IDs, even though they're
45 // technically in a different space.
46 static std::atomic<int> nextID{SK_MaxS32};
47 return nextID.fetch_add(-1, std::memory_order_relaxed);
48 }
49
NextExternalRenderTargetID()50 int GrMockGpu::NextExternalRenderTargetID() {
51 // We use large negative ints for the "testing only external render targets" so they can easily
52 // be identified when debugging.
53 static std::atomic<int> nextID{SK_MinS32};
54 return nextID.fetch_add(1, std::memory_order_relaxed);
55 }
56
Make(const GrMockOptions * mockOptions,const GrContextOptions & contextOptions,GrDirectContext * direct)57 std::unique_ptr<GrGpu> GrMockGpu::Make(const GrMockOptions* mockOptions,
58 const GrContextOptions& contextOptions,
59 GrDirectContext* direct) {
60 static const GrMockOptions kDefaultOptions = GrMockOptions();
61 if (!mockOptions) {
62 mockOptions = &kDefaultOptions;
63 }
64 return std::unique_ptr<GrGpu>(new GrMockGpu(direct, *mockOptions, contextOptions));
65 }
66
onGetOpsRenderPass(GrRenderTarget * rt,bool,GrAttachment *,GrSurfaceOrigin origin,const SkIRect & bounds,const GrOpsRenderPass::LoadAndStoreInfo & colorInfo,const GrOpsRenderPass::StencilLoadAndStoreInfo &,const TArray<GrSurfaceProxy *,true> & sampledProxies,GrXferBarrierFlags renderPassXferBarriers)67 GrOpsRenderPass* GrMockGpu::onGetOpsRenderPass(GrRenderTarget* rt,
68 bool /*useMSAASurface*/,
69 GrAttachment*,
70 GrSurfaceOrigin origin,
71 const SkIRect& bounds,
72 const GrOpsRenderPass::LoadAndStoreInfo& colorInfo,
73 const GrOpsRenderPass::StencilLoadAndStoreInfo&,
74 const TArray<GrSurfaceProxy*,true>& sampledProxies,
75 GrXferBarrierFlags renderPassXferBarriers) {
76 return new GrMockOpsRenderPass(this, rt, origin, colorInfo);
77 }
78
submit(GrOpsRenderPass * renderPass)79 void GrMockGpu::submit(GrOpsRenderPass* renderPass) {
80 for (int i = 0; i < static_cast<GrMockOpsRenderPass*>(renderPass)->numDraws(); ++i) {
81 fStats.incNumDraws();
82 }
83 delete renderPass;
84 }
85
GrMockGpu(GrDirectContext * direct,const GrMockOptions & options,const GrContextOptions & contextOptions)86 GrMockGpu::GrMockGpu(GrDirectContext* direct, const GrMockOptions& options,
87 const GrContextOptions& contextOptions)
88 : INHERITED(direct)
89 , fMockOptions(options) {
90 this->initCaps(sk_make_sp<GrMockCaps>(contextOptions, options));
91 }
92
~GrMockGpu()93 GrMockGpu::~GrMockGpu() {}
94
pipelineBuilder()95 GrThreadSafePipelineBuilder* GrMockGpu::pipelineBuilder() {
96 return nullptr;
97 }
98
refPipelineBuilder()99 sk_sp<GrThreadSafePipelineBuilder> GrMockGpu::refPipelineBuilder() {
100 return nullptr;
101 }
102
onCreateTexture(SkISize dimensions,const GrBackendFormat & format,GrRenderable renderable,int renderTargetSampleCnt,skgpu::Budgeted budgeted,GrProtected isProtected,int mipLevelCount,uint32_t levelClearMask,std::string_view label)103 sk_sp<GrTexture> GrMockGpu::onCreateTexture(SkISize dimensions,
104 const GrBackendFormat& format,
105 GrRenderable renderable,
106 int renderTargetSampleCnt,
107 skgpu::Budgeted budgeted,
108 GrProtected isProtected,
109 int mipLevelCount,
110 uint32_t levelClearMask,
111 std::string_view label) {
112 if (fMockOptions.fFailTextureAllocations) {
113 return nullptr;
114 }
115
116 // Compressed formats should go through onCreateCompressedTexture
117 SkASSERT(format.asMockCompressionType() == SkTextureCompressionType::kNone);
118
119 GrColorType ct = format.asMockColorType();
120 SkASSERT(ct != GrColorType::kUnknown);
121
122 GrMipmapStatus mipmapStatus =
123 mipLevelCount > 1 ? GrMipmapStatus::kDirty : GrMipmapStatus::kNotAllocated;
124 GrMockTextureInfo texInfo(ct, SkTextureCompressionType::kNone, NextInternalTextureID(),
125 isProtected);
126 if (renderable == GrRenderable::kYes) {
127 GrMockRenderTargetInfo rtInfo(ct, NextInternalRenderTargetID(), isProtected);
128 return sk_sp<GrTexture>(new GrMockTextureRenderTarget(this, budgeted, dimensions,
129 renderTargetSampleCnt,
130 mipmapStatus,
131 texInfo,
132 rtInfo,
133 label));
134 }
135 return sk_sp<GrTexture>(new GrMockTexture(
136 this, budgeted, dimensions, mipmapStatus, texInfo, label));
137 }
138
139 // TODO: why no 'isProtected' ?!
onCreateCompressedTexture(SkISize dimensions,const GrBackendFormat & format,skgpu::Budgeted budgeted,skgpu::Mipmapped mipmapped,GrProtected isProtected,const void * data,size_t dataSize)140 sk_sp<GrTexture> GrMockGpu::onCreateCompressedTexture(SkISize dimensions,
141 const GrBackendFormat& format,
142 skgpu::Budgeted budgeted,
143 skgpu::Mipmapped mipmapped,
144 GrProtected isProtected,
145 const void* data,
146 size_t dataSize) {
147 if (fMockOptions.fFailTextureAllocations) {
148 return nullptr;
149 }
150
151 #ifdef SK_DEBUG
152 // Uncompressed formats should go through onCreateTexture
153 SkTextureCompressionType compression = format.asMockCompressionType();
154 SkASSERT(compression != SkTextureCompressionType::kNone);
155 #endif
156
157 GrMipmapStatus mipmapStatus = (mipmapped == skgpu::Mipmapped::kYes)
158 ? GrMipmapStatus::kValid
159 : GrMipmapStatus::kNotAllocated;
160 GrMockTextureInfo texInfo(GrColorType::kUnknown,
161 format.asMockCompressionType(),
162 NextInternalTextureID(),
163 isProtected);
164
165 return sk_sp<GrTexture>(new GrMockTexture(
166 this, budgeted, dimensions, mipmapStatus, texInfo,
167 /*label=*/"MockGpu_CreateCompressedTexture"));
168 }
169
onWrapBackendTexture(const GrBackendTexture & tex,GrWrapOwnership ownership,GrWrapCacheable wrapType,GrIOType ioType)170 sk_sp<GrTexture> GrMockGpu::onWrapBackendTexture(const GrBackendTexture& tex,
171 GrWrapOwnership ownership,
172 GrWrapCacheable wrapType,
173 GrIOType ioType) {
174 GrMockTextureInfo texInfo;
175 SkAssertResult(tex.getMockTextureInfo(&texInfo));
176
177 SkTextureCompressionType compression = texInfo.compressionType();
178 if (compression != SkTextureCompressionType::kNone) {
179 return nullptr;
180 }
181
182 GrMipmapStatus mipmapStatus = tex.hasMipmaps() ? GrMipmapStatus::kValid
183 : GrMipmapStatus::kNotAllocated;
184 return sk_sp<GrTexture>(new GrMockTexture(this,
185 tex.dimensions(),
186 mipmapStatus,
187 texInfo,
188 wrapType,
189 ioType,
190 /*label=*/"MockGpu_WrapBackendTexture"));
191 }
192
onWrapCompressedBackendTexture(const GrBackendTexture & tex,GrWrapOwnership ownership,GrWrapCacheable wrapType)193 sk_sp<GrTexture> GrMockGpu::onWrapCompressedBackendTexture(const GrBackendTexture& tex,
194 GrWrapOwnership ownership,
195 GrWrapCacheable wrapType) {
196 return nullptr;
197 }
198
onWrapRenderableBackendTexture(const GrBackendTexture & tex,int sampleCnt,GrWrapOwnership ownership,GrWrapCacheable cacheable)199 sk_sp<GrTexture> GrMockGpu::onWrapRenderableBackendTexture(const GrBackendTexture& tex,
200 int sampleCnt,
201 GrWrapOwnership ownership,
202 GrWrapCacheable cacheable) {
203 GrMockTextureInfo texInfo;
204 SkAssertResult(tex.getMockTextureInfo(&texInfo));
205 SkASSERT(texInfo.compressionType() == SkTextureCompressionType::kNone);
206
207 GrMipmapStatus mipmapStatus =
208 tex.hasMipmaps() ? GrMipmapStatus::kValid : GrMipmapStatus::kNotAllocated;
209
210 // The client gave us the texture ID but we supply the render target ID.
211 GrMockRenderTargetInfo rtInfo(texInfo.colorType(), NextInternalRenderTargetID(),
212 texInfo.getProtected());
213
214 return sk_sp<GrTexture>(
215 new GrMockTextureRenderTarget(this,
216 tex.dimensions(),
217 sampleCnt,
218 mipmapStatus,
219 texInfo,
220 rtInfo,
221 cacheable,
222 /*label=*/"MockGpu_WrapRenderableBackendTexture"));
223 }
224
onWrapBackendRenderTarget(const GrBackendRenderTarget & rt)225 sk_sp<GrRenderTarget> GrMockGpu::onWrapBackendRenderTarget(const GrBackendRenderTarget& rt) {
226 GrMockRenderTargetInfo info;
227 SkAssertResult(rt.getMockRenderTargetInfo(&info));
228
229 return sk_sp<GrRenderTarget>(
230 new GrMockRenderTarget(this,
231 GrMockRenderTarget::kWrapped,
232 rt.dimensions(),
233 rt.sampleCnt(),
234 info,
235 /*label=*/"MockGpu_WrapBackendRenderTarget"));
236 }
237
onCreateBuffer(size_t sizeInBytes,GrGpuBufferType type,GrAccessPattern accessPattern)238 sk_sp<GrGpuBuffer> GrMockGpu::onCreateBuffer(size_t sizeInBytes,
239 GrGpuBufferType type,
240 GrAccessPattern accessPattern) {
241 return sk_sp<GrGpuBuffer>(
242 new GrMockBuffer(this, sizeInBytes, type, accessPattern,
243 /*label=*/"MockGpu_CreateBuffer"));
244 }
245
makeStencilAttachment(const GrBackendFormat &,SkISize dimensions,int numStencilSamples)246 sk_sp<GrAttachment> GrMockGpu::makeStencilAttachment(const GrBackendFormat& /*colorFormat*/,
247 SkISize dimensions, int numStencilSamples) {
248 fStats.incStencilAttachmentCreates();
249 return sk_sp<GrAttachment>(new GrMockAttachment(this,
250 dimensions,
251 GrAttachment::UsageFlags::kStencilAttachment,
252 numStencilSamples,
253 /*label=*/"MockGpu_MakeStencilAttachment"));
254 }
255
onCreateBackendTexture(SkISize dimensions,const GrBackendFormat & format,GrRenderable,skgpu::Mipmapped mipmapped,GrProtected isProtected,std::string_view label)256 GrBackendTexture GrMockGpu::onCreateBackendTexture(SkISize dimensions,
257 const GrBackendFormat& format,
258 GrRenderable,
259 skgpu::Mipmapped mipmapped,
260 GrProtected isProtected,
261 std::string_view label) {
262 SkTextureCompressionType compression = format.asMockCompressionType();
263 if (compression != SkTextureCompressionType::kNone) {
264 return {}; // should go through onCreateCompressedBackendTexture
265 }
266
267 auto colorType = format.asMockColorType();
268 if (!this->caps()->isFormatTexturable(format, GrTextureType::k2D)) {
269 return GrBackendTexture(); // invalid
270 }
271
272 GrMockTextureInfo info(colorType, SkTextureCompressionType::kNone, NextExternalTextureID(),
273 isProtected);
274
275 fOutstandingTestingOnlyTextureIDs.add(info.id());
276 return GrBackendTexture(dimensions.width(), dimensions.height(), mipmapped, info);
277 }
278
onCreateCompressedBackendTexture(SkISize dimensions,const GrBackendFormat & format,skgpu::Mipmapped mipmapped,GrProtected isProtected)279 GrBackendTexture GrMockGpu::onCreateCompressedBackendTexture(SkISize dimensions,
280 const GrBackendFormat& format,
281 skgpu::Mipmapped mipmapped,
282 GrProtected isProtected) {
283 SkTextureCompressionType compression = format.asMockCompressionType();
284 if (compression == SkTextureCompressionType::kNone) {
285 return {}; // should go through onCreateBackendTexture
286 }
287
288 if (!this->caps()->isFormatTexturable(format, GrTextureType::k2D)) {
289 return {};
290 }
291
292 GrMockTextureInfo info(GrColorType::kUnknown, compression, NextExternalTextureID(),
293 isProtected);
294
295 fOutstandingTestingOnlyTextureIDs.add(info.id());
296 return GrBackendTexture(dimensions.width(), dimensions.height(), mipmapped, info);
297 }
298
deleteBackendTexture(const GrBackendTexture & tex)299 void GrMockGpu::deleteBackendTexture(const GrBackendTexture& tex) {
300 SkASSERT(GrBackendApi::kMock == tex.backend());
301
302 GrMockTextureInfo info;
303 if (tex.getMockTextureInfo(&info)) {
304 fOutstandingTestingOnlyTextureIDs.remove(info.id());
305 }
306 }
307
308 #if defined(GPU_TEST_UTILS)
isTestingOnlyBackendTexture(const GrBackendTexture & tex) const309 bool GrMockGpu::isTestingOnlyBackendTexture(const GrBackendTexture& tex) const {
310 SkASSERT(GrBackendApi::kMock == tex.backend());
311
312 GrMockTextureInfo info;
313 if (!tex.getMockTextureInfo(&info)) {
314 return false;
315 }
316
317 return fOutstandingTestingOnlyTextureIDs.contains(info.id());
318 }
319
createTestingOnlyBackendRenderTarget(SkISize dimensions,GrColorType colorType,int sampleCnt,GrProtected isProtected)320 GrBackendRenderTarget GrMockGpu::createTestingOnlyBackendRenderTarget(SkISize dimensions,
321 GrColorType colorType,
322 int sampleCnt,
323 GrProtected isProtected) {
324 GrMockRenderTargetInfo info(colorType, NextExternalRenderTargetID(), isProtected);
325 static constexpr int kStencilBits = 8;
326 return GrBackendRenderTarget(dimensions.width(), dimensions.height(), sampleCnt, kStencilBits,
327 info);
328 }
329
deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget &)330 void GrMockGpu::deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget&) {}
331 #endif
332