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/GrMockGpuCommandBuffer.h"
12 #include "src/gpu/mock/GrMockStencilAttachment.h"
13 #include "src/gpu/mock/GrMockTexture.h"
14 #include <atomic>
15
NextInternalTextureID()16 int 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
NextExternalTextureID()25 int 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
NextInternalRenderTargetID()32 int 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
NextExternalRenderTargetID()39 int 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
Make(const GrMockOptions * mockOptions,const GrContextOptions & contextOptions,GrContext * context)46 sk_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
getCommandBuffer(GrRenderTarget * rt,GrSurfaceOrigin origin,const SkRect & bounds,const GrGpuRTCommandBuffer::LoadAndStoreInfo &,const GrGpuRTCommandBuffer::StencilLoadAndStoreInfo &)55 GrGpuRTCommandBuffer* GrMockGpu::getCommandBuffer(
56 GrRenderTarget* rt, GrSurfaceOrigin origin, const SkRect& bounds,
57 const GrGpuRTCommandBuffer::LoadAndStoreInfo&,
58 const GrGpuRTCommandBuffer::StencilLoadAndStoreInfo&) {
59 return new GrMockGpuRTCommandBuffer(this, rt, origin);
60 }
61
getCommandBuffer(GrTexture * texture,GrSurfaceOrigin origin)62 GrGpuTextureCommandBuffer* GrMockGpu::getCommandBuffer(GrTexture* texture, GrSurfaceOrigin origin) {
63 return new GrMockGpuTextureCommandBuffer(texture, origin);
64 }
65
submit(GrGpuCommandBuffer * buffer)66 void GrMockGpu::submit(GrGpuCommandBuffer* buffer) {
67 if (buffer->asRTCommandBuffer()) {
68 this->submitCommandBuffer(
69 static_cast<GrMockGpuRTCommandBuffer*>(buffer->asRTCommandBuffer()));
70 }
71
72 delete buffer;
73 }
74
submitCommandBuffer(const GrMockGpuRTCommandBuffer * cmdBuffer)75 void GrMockGpu::submitCommandBuffer(const GrMockGpuRTCommandBuffer* cmdBuffer) {
76 for (int i = 0; i < cmdBuffer->numDraws(); ++i) {
77 fStats.incNumDraws();
78 }
79 }
80
GrMockGpu(GrContext * context,const GrMockOptions & options,const GrContextOptions & contextOptions)81 GrMockGpu::GrMockGpu(GrContext* context, const GrMockOptions& options,
82 const GrContextOptions& contextOptions)
83 : INHERITED(context)
84 , fMockOptions(options) {
85 fCaps.reset(new GrMockCaps(contextOptions, options));
86 }
87
querySampleLocations(GrRenderTarget * rt,SkTArray<SkPoint> * sampleLocations)88 void GrMockGpu::querySampleLocations(GrRenderTarget* rt, SkTArray<SkPoint>* sampleLocations) {
89 sampleLocations->reset();
90 int numRemainingSamples = rt->numSamples();
91 while (numRemainingSamples > 0) {
92 // Use standard D3D sample locations.
93 switch (numRemainingSamples) {
94 case 0:
95 case 1:
96 sampleLocations->push_back().set(.5, .5);
97 break;
98 case 2:
99 sampleLocations->push_back().set(.75, .75);
100 sampleLocations->push_back().set(.25, .25);
101 break;
102 case 3:
103 case 4:
104 sampleLocations->push_back().set(.375, .125);
105 sampleLocations->push_back().set(.875, .375);
106 sampleLocations->push_back().set(.125, .625);
107 sampleLocations->push_back().set(.625, .875);
108 break;
109 case 5:
110 case 6:
111 case 7:
112 case 8:
113 sampleLocations->push_back().set(.5625, .3125);
114 sampleLocations->push_back().set(.4375, .6875);
115 sampleLocations->push_back().set(.8125, .5625);
116 sampleLocations->push_back().set(.3125, .1875);
117 sampleLocations->push_back().set(.1875, .8125);
118 sampleLocations->push_back().set(.0625, .4375);
119 sampleLocations->push_back().set(.6875, .4375);
120 sampleLocations->push_back().set(.4375, .0625);
121 break;
122 default:
123 sampleLocations->push_back().set(.5625, .5625);
124 sampleLocations->push_back().set(.4375, .3125);
125 sampleLocations->push_back().set(.3125, .6250);
126 sampleLocations->push_back().set(.2500, .4375);
127 sampleLocations->push_back().set(.1875, .3750);
128 sampleLocations->push_back().set(.6250, .8125);
129 sampleLocations->push_back().set(.8125, .6875);
130 sampleLocations->push_back().set(.6875, .1875);
131 sampleLocations->push_back().set(.3750, .8750);
132 sampleLocations->push_back().set(.5000, .0625);
133 sampleLocations->push_back().set(.2500, .1250);
134 sampleLocations->push_back().set(.1250, .2500);
135 sampleLocations->push_back().set(.0000, .5000);
136 sampleLocations->push_back().set(.4375, .2500);
137 sampleLocations->push_back().set(.8750, .4375);
138 sampleLocations->push_back().set(.0625, .0000);
139 break;
140 }
141 numRemainingSamples = rt->numSamples() - sampleLocations->count();
142 }
143 }
144
onCreateTexture(const GrSurfaceDesc & desc,const GrBackendFormat & format,GrRenderable renderable,int renderTargetSampleCnt,SkBudgeted budgeted,GrProtected isProtected,const GrMipLevel texels[],int mipLevelCount)145 sk_sp<GrTexture> GrMockGpu::onCreateTexture(const GrSurfaceDesc& desc,
146 const GrBackendFormat& format,
147 GrRenderable renderable,
148 int renderTargetSampleCnt,
149 SkBudgeted budgeted,
150 GrProtected isProtected,
151 const GrMipLevel texels[],
152 int mipLevelCount) {
153 if (fMockOptions.fFailTextureAllocations) {
154 return nullptr;
155 }
156
157 GrColorType ct = format.asMockColorType();
158 SkASSERT(ct != GrColorType::kUnknown);
159
160 GrMipMapsStatus mipMapsStatus = mipLevelCount > 1 ? GrMipMapsStatus::kValid
161 : GrMipMapsStatus::kNotAllocated;
162 GrMockTextureInfo texInfo(ct, NextInternalTextureID());
163 if (renderable == GrRenderable::kYes) {
164 GrMockRenderTargetInfo rtInfo(ct, NextInternalRenderTargetID());
165 return sk_sp<GrTexture>(new GrMockTextureRenderTarget(this, budgeted, desc,
166 renderTargetSampleCnt, isProtected,
167 mipMapsStatus, texInfo, rtInfo));
168 }
169 return sk_sp<GrTexture>(
170 new GrMockTexture(this, budgeted, desc, isProtected, mipMapsStatus, texInfo));
171 }
172
onCreateCompressedTexture(int width,int height,const GrBackendFormat &,SkImage::CompressionType compressionType,SkBudgeted budgeted,const void * data)173 sk_sp<GrTexture> GrMockGpu::onCreateCompressedTexture(int width, int height, const GrBackendFormat&,
174 SkImage::CompressionType compressionType,
175 SkBudgeted budgeted, const void* data) {
176 return nullptr;
177 }
178
onWrapBackendTexture(const GrBackendTexture & tex,GrColorType colorType,GrWrapOwnership ownership,GrWrapCacheable wrapType,GrIOType ioType)179 sk_sp<GrTexture> GrMockGpu::onWrapBackendTexture(const GrBackendTexture& tex, GrColorType colorType,
180 GrWrapOwnership ownership,
181 GrWrapCacheable wrapType, GrIOType ioType) {
182 GrMockTextureInfo texInfo;
183 SkAssertResult(tex.getMockTextureInfo(&texInfo));
184
185 SkASSERT(colorType == texInfo.fColorType);
186 GrSurfaceDesc desc;
187 desc.fWidth = tex.width();
188 desc.fHeight = tex.height();
189 desc.fConfig = texInfo.pixelConfig();
190
191 GrMipMapsStatus mipMapsStatus = tex.hasMipMaps() ? GrMipMapsStatus::kValid
192 : GrMipMapsStatus::kNotAllocated;
193 auto isProtected = GrProtected(tex.isProtected());
194 return sk_sp<GrTexture>(
195 new GrMockTexture(this, desc, isProtected, mipMapsStatus, texInfo, wrapType, ioType));
196 }
197
onWrapRenderableBackendTexture(const GrBackendTexture & tex,int sampleCnt,GrColorType colorType,GrWrapOwnership ownership,GrWrapCacheable cacheable)198 sk_sp<GrTexture> GrMockGpu::onWrapRenderableBackendTexture(const GrBackendTexture& tex,
199 int sampleCnt,
200 GrColorType colorType,
201 GrWrapOwnership ownership,
202 GrWrapCacheable cacheable) {
203 GrMockTextureInfo texInfo;
204 SkAssertResult(tex.getMockTextureInfo(&texInfo));
205
206 SkASSERT(colorType == texInfo.fColorType);
207 GrSurfaceDesc desc;
208 desc.fWidth = tex.width();
209 desc.fHeight = tex.height();
210 desc.fConfig = texInfo.pixelConfig();
211
212 GrMipMapsStatus mipMapsStatus =
213 tex.hasMipMaps() ? GrMipMapsStatus::kValid : GrMipMapsStatus::kNotAllocated;
214
215 // The client gave us the texture ID but we supply the render target ID.
216 GrMockRenderTargetInfo rtInfo(texInfo.fColorType, NextInternalRenderTargetID());
217
218 auto isProtected = GrProtected(tex.isProtected());
219 return sk_sp<GrTexture>(new GrMockTextureRenderTarget(
220 this, desc, sampleCnt, isProtected, mipMapsStatus, texInfo, rtInfo, cacheable));
221 }
222
onWrapBackendRenderTarget(const GrBackendRenderTarget & rt,GrColorType colorType)223 sk_sp<GrRenderTarget> GrMockGpu::onWrapBackendRenderTarget(const GrBackendRenderTarget& rt,
224 GrColorType colorType) {
225 GrMockRenderTargetInfo info;
226 SkAssertResult(rt.getMockRenderTargetInfo(&info));
227
228 SkASSERT(colorType == info.colorType());
229 GrSurfaceDesc desc;
230 desc.fWidth = rt.width();
231 desc.fHeight = rt.height();
232 desc.fConfig = info.pixelConfig();
233
234 auto isProtected = GrProtected(rt.isProtected());
235 return sk_sp<GrRenderTarget>(new GrMockRenderTarget(this, GrMockRenderTarget::kWrapped, desc,
236 rt.sampleCnt(), isProtected, info));
237 }
238
onWrapBackendTextureAsRenderTarget(const GrBackendTexture & tex,int sampleCnt,GrColorType colorType)239 sk_sp<GrRenderTarget> GrMockGpu::onWrapBackendTextureAsRenderTarget(const GrBackendTexture& tex,
240 int sampleCnt,
241 GrColorType colorType) {
242 GrMockTextureInfo texInfo;
243 SkAssertResult(tex.getMockTextureInfo(&texInfo));
244
245 SkASSERT(colorType == texInfo.fColorType);
246 GrSurfaceDesc desc;
247 desc.fWidth = tex.width();
248 desc.fHeight = tex.height();
249 desc.fConfig = texInfo.pixelConfig();
250
251 // The client gave us the texture ID but we supply the render target ID.
252 GrMockRenderTargetInfo rtInfo(texInfo.fColorType, NextInternalRenderTargetID());
253
254 auto isProtected = GrProtected(tex.isProtected());
255 return sk_sp<GrRenderTarget>(new GrMockRenderTarget(this, GrMockRenderTarget::kWrapped, desc,
256 sampleCnt, isProtected, rtInfo));
257 }
258
onCreateBuffer(size_t sizeInBytes,GrGpuBufferType type,GrAccessPattern accessPattern,const void *)259 sk_sp<GrGpuBuffer> GrMockGpu::onCreateBuffer(size_t sizeInBytes, GrGpuBufferType type,
260 GrAccessPattern accessPattern, const void*) {
261 return sk_sp<GrGpuBuffer>(new GrMockBuffer(this, sizeInBytes, type, accessPattern));
262 }
263
createStencilAttachmentForRenderTarget(const GrRenderTarget * rt,int width,int height,int numStencilSamples)264 GrStencilAttachment* GrMockGpu::createStencilAttachmentForRenderTarget(
265 const GrRenderTarget* rt, int width, int height, int numStencilSamples) {
266 SkASSERT(numStencilSamples == rt->numSamples());
267 static constexpr int kBits = 8;
268 fStats.incStencilAttachmentCreates();
269 return new GrMockStencilAttachment(this, width, height, kBits, rt->numSamples());
270 }
271
createBackendTexture(int w,int h,const GrBackendFormat & format,GrMipMapped mipMapped,GrRenderable,const void *,size_t,const SkColor4f *,GrProtected)272 GrBackendTexture GrMockGpu::createBackendTexture(int w, int h,
273 const GrBackendFormat& format,
274 GrMipMapped mipMapped,
275 GrRenderable /* renderable */,
276 const void* /* pixels */,
277 size_t /* rowBytes */,
278 const SkColor4f* /* color */,
279 GrProtected /* isProtected */) {
280 auto colorType = format.asMockColorType();
281 if (!this->caps()->isFormatTexturable(format)) {
282 return GrBackendTexture(); // invalid
283 }
284
285 GrMockTextureInfo info(colorType, NextExternalTextureID());
286
287 fOutstandingTestingOnlyTextureIDs.add(info.fID);
288 return GrBackendTexture(w, h, mipMapped, info);
289 }
290
deleteBackendTexture(const GrBackendTexture & tex)291 void GrMockGpu::deleteBackendTexture(const GrBackendTexture& tex) {
292 SkASSERT(GrBackendApi::kMock == tex.backend());
293
294 GrMockTextureInfo info;
295 if (tex.getMockTextureInfo(&info)) {
296 fOutstandingTestingOnlyTextureIDs.remove(info.fID);
297 }
298 }
299
300 #if GR_TEST_UTILS
isTestingOnlyBackendTexture(const GrBackendTexture & tex) const301 bool GrMockGpu::isTestingOnlyBackendTexture(const GrBackendTexture& tex) const {
302 SkASSERT(GrBackendApi::kMock == tex.backend());
303
304 GrMockTextureInfo info;
305 if (!tex.getMockTextureInfo(&info)) {
306 return false;
307 }
308
309 return fOutstandingTestingOnlyTextureIDs.contains(info.fID);
310 }
311
createTestingOnlyBackendRenderTarget(int w,int h,GrColorType colorType)312 GrBackendRenderTarget GrMockGpu::createTestingOnlyBackendRenderTarget(int w, int h,
313 GrColorType colorType) {
314 GrMockRenderTargetInfo info(colorType, NextExternalRenderTargetID());
315 static constexpr int kSampleCnt = 1;
316 static constexpr int kStencilBits = 8;
317 return GrBackendRenderTarget(w, h, kSampleCnt, kStencilBits, info);
318 }
319
deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget &)320 void GrMockGpu::deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget&) {}
321 #endif
322