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