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