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