1 /*
2 * Copyright 2010 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
9 #include "GrGpu.h"
10
11 #include "GrBuffer.h"
12 #include "GrCaps.h"
13 #include "GrContext.h"
14 #include "GrGpuResourcePriv.h"
15 #include "GrMesh.h"
16 #include "GrPathRendering.h"
17 #include "GrPipeline.h"
18 #include "GrResourceCache.h"
19 #include "GrResourceProvider.h"
20 #include "GrRenderTargetPriv.h"
21 #include "GrStencilAttachment.h"
22 #include "GrStencilSettings.h"
23 #include "GrSurfacePriv.h"
24 #include "GrTexturePriv.h"
25 #include "SkMathPriv.h"
26
operator =(const GrMesh & di)27 GrMesh& GrMesh::operator =(const GrMesh& di) {
28 fPrimitiveType = di.fPrimitiveType;
29 fStartVertex = di.fStartVertex;
30 fStartIndex = di.fStartIndex;
31 fVertexCount = di.fVertexCount;
32 fIndexCount = di.fIndexCount;
33
34 fInstanceCount = di.fInstanceCount;
35 fVerticesPerInstance = di.fVerticesPerInstance;
36 fIndicesPerInstance = di.fIndicesPerInstance;
37 fMaxInstancesPerDraw = di.fMaxInstancesPerDraw;
38
39 fVertexBuffer.reset(di.vertexBuffer());
40 fIndexBuffer.reset(di.indexBuffer());
41
42 return *this;
43 }
44
45 ////////////////////////////////////////////////////////////////////////////////
46
GrGpu(GrContext * context)47 GrGpu::GrGpu(GrContext* context)
48 : fResetTimestamp(kExpiredTimestamp+1)
49 , fResetBits(kAll_GrBackendState)
50 , fContext(context) {
51 fMultisampleSpecs.emplace_back(0, 0, nullptr); // Index 0 is an invalid unique id.
52 }
53
~GrGpu()54 GrGpu::~GrGpu() {}
55
disconnect(DisconnectType)56 void GrGpu::disconnect(DisconnectType) {}
57
58 ////////////////////////////////////////////////////////////////////////////////
59
isACopyNeededForTextureParams(int width,int height,const GrSamplerParams & textureParams,GrTextureProducer::CopyParams * copyParams,SkScalar scaleAdjust[2]) const60 bool GrGpu::isACopyNeededForTextureParams(int width, int height,
61 const GrSamplerParams& textureParams,
62 GrTextureProducer::CopyParams* copyParams,
63 SkScalar scaleAdjust[2]) const {
64 const GrCaps& caps = *this->caps();
65 if (textureParams.isTiled() && !caps.npotTextureTileSupport() &&
66 (!SkIsPow2(width) || !SkIsPow2(height))) {
67 SkASSERT(scaleAdjust);
68 copyParams->fWidth = GrNextPow2(width);
69 copyParams->fHeight = GrNextPow2(height);
70 scaleAdjust[0] = ((SkScalar) copyParams->fWidth) / width;
71 scaleAdjust[1] = ((SkScalar) copyParams->fHeight) / height;
72 switch (textureParams.filterMode()) {
73 case GrSamplerParams::kNone_FilterMode:
74 copyParams->fFilter = GrSamplerParams::kNone_FilterMode;
75 break;
76 case GrSamplerParams::kBilerp_FilterMode:
77 case GrSamplerParams::kMipMap_FilterMode:
78 // We are only ever scaling up so no reason to ever indicate kMipMap.
79 copyParams->fFilter = GrSamplerParams::kBilerp_FilterMode;
80 break;
81 }
82 return true;
83 }
84 return false;
85 }
86
resolve_origin(GrSurfaceOrigin origin,bool renderTarget)87 static GrSurfaceOrigin resolve_origin(GrSurfaceOrigin origin, bool renderTarget) {
88 // By default, GrRenderTargets are GL's normal orientation so that they
89 // can be drawn to by the outside world without the client having
90 // to render upside down.
91 if (kDefault_GrSurfaceOrigin == origin) {
92 return renderTarget ? kBottomLeft_GrSurfaceOrigin : kTopLeft_GrSurfaceOrigin;
93 } else {
94 return origin;
95 }
96 }
97
98 /**
99 * Prior to creating a texture, make sure the type of texture being created is
100 * supported by calling check_texture_creation_params.
101 *
102 * @param caps The capabilities of the GL device.
103 * @param desc The descriptor of the texture to create.
104 * @param isRT Indicates if the texture can be a render target.
105 */
check_texture_creation_params(const GrCaps & caps,const GrSurfaceDesc & desc,bool * isRT,const SkTArray<GrMipLevel> & texels)106 static bool check_texture_creation_params(const GrCaps& caps, const GrSurfaceDesc& desc,
107 bool* isRT, const SkTArray<GrMipLevel>& texels) {
108 if (!caps.isConfigTexturable(desc.fConfig)) {
109 return false;
110 }
111
112 if (GrPixelConfigIsSint(desc.fConfig) && texels.count() > 1) {
113 return false;
114 }
115
116 *isRT = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag);
117 if (*isRT && !caps.isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) {
118 return false;
119 }
120
121 // We currently do not support multisampled textures
122 if (!*isRT && desc.fSampleCnt > 0) {
123 return false;
124 }
125
126 if (*isRT) {
127 int maxRTSize = caps.maxRenderTargetSize();
128 if (desc.fWidth > maxRTSize || desc.fHeight > maxRTSize) {
129 return false;
130 }
131 } else {
132 int maxSize = caps.maxTextureSize();
133 if (desc.fWidth > maxSize || desc.fHeight > maxSize) {
134 return false;
135 }
136 }
137
138 for (int i = 0; i < texels.count(); ++i) {
139 if (!texels[i].fPixels) {
140 return false;
141 }
142 }
143 return true;
144 }
145
createTexture(const GrSurfaceDesc & origDesc,SkBudgeted budgeted,const SkTArray<GrMipLevel> & texels)146 GrTexture* GrGpu::createTexture(const GrSurfaceDesc& origDesc, SkBudgeted budgeted,
147 const SkTArray<GrMipLevel>& texels) {
148 GrSurfaceDesc desc = origDesc;
149
150 const GrCaps* caps = this->caps();
151 bool isRT = false;
152 bool textureCreationParamsValid = check_texture_creation_params(*caps, desc, &isRT, texels);
153 if (!textureCreationParamsValid) {
154 return nullptr;
155 }
156
157 desc.fSampleCnt = SkTMin(desc.fSampleCnt, caps->maxSampleCount());
158 // Attempt to catch un- or wrongly intialized sample counts;
159 SkASSERT(desc.fSampleCnt >= 0 && desc.fSampleCnt <= 64);
160
161 desc.fOrigin = resolve_origin(desc.fOrigin, isRT);
162
163 GrTexture* tex = nullptr;
164
165 if (GrPixelConfigIsCompressed(desc.fConfig)) {
166 // We shouldn't be rendering into this
167 SkASSERT(!isRT);
168 SkASSERT(0 == desc.fSampleCnt);
169
170 if (!caps->npotTextureTileSupport() &&
171 (!SkIsPow2(desc.fWidth) || !SkIsPow2(desc.fHeight))) {
172 return nullptr;
173 }
174
175 this->handleDirtyContext();
176 tex = this->onCreateCompressedTexture(desc, budgeted, texels);
177 } else {
178 this->handleDirtyContext();
179 tex = this->onCreateTexture(desc, budgeted, texels);
180 }
181 if (tex) {
182 if (!caps->reuseScratchTextures() && !isRT) {
183 tex->resourcePriv().removeScratchKey();
184 }
185 fStats.incTextureCreates();
186 if (!texels.empty()) {
187 if (texels[0].fPixels) {
188 fStats.incTextureUploads();
189 }
190 }
191 // This is a current work around to get discards into newly created textures. Once we are in
192 // MDB world, we should remove this code a rely on the draw target having specified load
193 // operations.
194 if (isRT && texels.empty()) {
195 GrRenderTarget* rt = tex->asRenderTarget();
196 SkASSERT(rt);
197 rt->discard();
198 }
199 }
200 return tex;
201 }
202
wrapBackendTexture(const GrBackendTextureDesc & desc,GrWrapOwnership ownership)203 sk_sp<GrTexture> GrGpu::wrapBackendTexture(const GrBackendTextureDesc& desc,
204 GrWrapOwnership ownership) {
205 this->handleDirtyContext();
206 if (!this->caps()->isConfigTexturable(desc.fConfig)) {
207 return nullptr;
208 }
209 if ((desc.fFlags & kRenderTarget_GrBackendTextureFlag) &&
210 !this->caps()->isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) {
211 return nullptr;
212 }
213 int maxSize = this->caps()->maxTextureSize();
214 if (desc.fWidth > maxSize || desc.fHeight > maxSize) {
215 return nullptr;
216 }
217 sk_sp<GrTexture> tex = this->onWrapBackendTexture(desc, ownership);
218 if (!tex) {
219 return nullptr;
220 }
221 // TODO: defer this and attach dynamically
222 GrRenderTarget* tgt = tex->asRenderTarget();
223 if (tgt && !fContext->resourceProvider()->attachStencilAttachment(tgt)) {
224 return nullptr;
225 }
226 return tex;
227 }
228
wrapBackendRenderTarget(const GrBackendRenderTargetDesc & desc)229 sk_sp<GrRenderTarget> GrGpu::wrapBackendRenderTarget(const GrBackendRenderTargetDesc& desc) {
230 if (!this->caps()->isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) {
231 return nullptr;
232 }
233 this->handleDirtyContext();
234 return this->onWrapBackendRenderTarget(desc);
235 }
236
wrapBackendTextureAsRenderTarget(const GrBackendTextureDesc & desc)237 sk_sp<GrRenderTarget> GrGpu::wrapBackendTextureAsRenderTarget(const GrBackendTextureDesc& desc) {
238 this->handleDirtyContext();
239 if (!(desc.fFlags & kRenderTarget_GrBackendTextureFlag)) {
240 return nullptr;
241 }
242 if (!this->caps()->isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) {
243 return nullptr;
244 }
245 int maxSize = this->caps()->maxTextureSize();
246 if (desc.fWidth > maxSize || desc.fHeight > maxSize) {
247 return nullptr;
248 }
249 return this->onWrapBackendTextureAsRenderTarget(desc);
250 }
251
createBuffer(size_t size,GrBufferType intendedType,GrAccessPattern accessPattern,const void * data)252 GrBuffer* GrGpu::createBuffer(size_t size, GrBufferType intendedType,
253 GrAccessPattern accessPattern, const void* data) {
254 this->handleDirtyContext();
255 GrBuffer* buffer = this->onCreateBuffer(size, intendedType, accessPattern, data);
256 if (!this->caps()->reuseScratchBuffers()) {
257 buffer->resourcePriv().removeScratchKey();
258 }
259 return buffer;
260 }
261
createInstancedRendering()262 gr_instanced::InstancedRendering* GrGpu::createInstancedRendering() {
263 SkASSERT(GrCaps::InstancedSupport::kNone != this->caps()->instancedSupport());
264 return this->onCreateInstancedRendering();
265 }
266
copySurface(GrSurface * dst,GrSurface * src,const SkIRect & srcRect,const SkIPoint & dstPoint)267 bool GrGpu::copySurface(GrSurface* dst,
268 GrSurface* src,
269 const SkIRect& srcRect,
270 const SkIPoint& dstPoint) {
271 SkASSERT(dst && src);
272 this->handleDirtyContext();
273 // We don't allow conversion between integer configs and float/fixed configs.
274 if (GrPixelConfigIsSint(dst->config()) != GrPixelConfigIsSint(src->config())) {
275 return false;
276 }
277 if (GrPixelConfigIsCompressed(dst->config())) {
278 return false;
279 }
280 return this->onCopySurface(dst, src, srcRect, dstPoint);
281 }
282
getReadPixelsInfo(GrSurface * srcSurface,int width,int height,size_t rowBytes,GrPixelConfig readConfig,DrawPreference * drawPreference,ReadPixelTempDrawInfo * tempDrawInfo)283 bool GrGpu::getReadPixelsInfo(GrSurface* srcSurface, int width, int height, size_t rowBytes,
284 GrPixelConfig readConfig, DrawPreference* drawPreference,
285 ReadPixelTempDrawInfo* tempDrawInfo) {
286 SkASSERT(drawPreference);
287 SkASSERT(tempDrawInfo);
288 SkASSERT(srcSurface);
289 SkASSERT(kGpuPrefersDraw_DrawPreference != *drawPreference);
290
291 // We don't allow conversion between integer configs and float/fixed configs.
292 if (GrPixelConfigIsSint(srcSurface->config()) != GrPixelConfigIsSint(readConfig)) {
293 return false;
294 }
295
296 // We currently do not support reading into a compressed buffer
297 if (GrPixelConfigIsCompressed(readConfig)) {
298 return false;
299 }
300
301 // We currently do not support reading into the packed formats 565 or 4444 as they are not
302 // required to have read back support on all devices and backends.
303 if (kRGB_565_GrPixelConfig == readConfig || kRGBA_4444_GrPixelConfig == readConfig) {
304 return false;
305 }
306
307 if (!this->onGetReadPixelsInfo(srcSurface, width, height, rowBytes, readConfig, drawPreference,
308 tempDrawInfo)) {
309 return false;
310 }
311
312 // Check to see if we're going to request that the caller draw when drawing is not possible.
313 if (!srcSurface->asTexture() ||
314 !this->caps()->isConfigRenderable(tempDrawInfo->fTempSurfaceDesc.fConfig, false)) {
315 // If we don't have a fallback to a straight read then fail.
316 if (kRequireDraw_DrawPreference == *drawPreference) {
317 return false;
318 }
319 *drawPreference = kNoDraw_DrawPreference;
320 }
321
322 return true;
323 }
getWritePixelsInfo(GrSurface * dstSurface,int width,int height,GrPixelConfig srcConfig,DrawPreference * drawPreference,WritePixelTempDrawInfo * tempDrawInfo)324 bool GrGpu::getWritePixelsInfo(GrSurface* dstSurface, int width, int height,
325 GrPixelConfig srcConfig, DrawPreference* drawPreference,
326 WritePixelTempDrawInfo* tempDrawInfo) {
327 SkASSERT(drawPreference);
328 SkASSERT(tempDrawInfo);
329 SkASSERT(dstSurface);
330 SkASSERT(kGpuPrefersDraw_DrawPreference != *drawPreference);
331
332 if (GrPixelConfigIsCompressed(dstSurface->desc().fConfig) &&
333 dstSurface->desc().fConfig != srcConfig) {
334 return false;
335 }
336
337 // We don't allow conversion between integer configs and float/fixed configs.
338 if (GrPixelConfigIsSint(dstSurface->config()) != GrPixelConfigIsSint(srcConfig)) {
339 return false;
340 }
341
342 if (SkToBool(dstSurface->asRenderTarget())) {
343 if (this->caps()->useDrawInsteadOfAllRenderTargetWrites()) {
344 ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
345 } else if (this->caps()->useDrawInsteadOfPartialRenderTargetWrite() &&
346 (width < dstSurface->width() || height < dstSurface->height())) {
347 ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
348 }
349 }
350
351 if (!this->onGetWritePixelsInfo(dstSurface, width, height, srcConfig, drawPreference,
352 tempDrawInfo)) {
353 return false;
354 }
355
356 // Check to see if we're going to request that the caller draw when drawing is not possible.
357 if (!dstSurface->asRenderTarget() ||
358 !this->caps()->isConfigTexturable(tempDrawInfo->fTempSurfaceDesc.fConfig)) {
359 // If we don't have a fallback to a straight upload then fail.
360 if (kRequireDraw_DrawPreference == *drawPreference ||
361 !this->caps()->isConfigTexturable(srcConfig)) {
362 return false;
363 }
364 *drawPreference = kNoDraw_DrawPreference;
365 }
366 return true;
367 }
368
readPixels(GrSurface * surface,int left,int top,int width,int height,GrPixelConfig config,void * buffer,size_t rowBytes)369 bool GrGpu::readPixels(GrSurface* surface,
370 int left, int top, int width, int height,
371 GrPixelConfig config, void* buffer,
372 size_t rowBytes) {
373 SkASSERT(surface);
374
375 // We don't allow conversion between integer configs and float/fixed configs.
376 if (GrPixelConfigIsSint(surface->config()) != GrPixelConfigIsSint(config)) {
377 return false;
378 }
379
380 // We cannot read pixels into a compressed buffer
381 if (GrPixelConfigIsCompressed(config)) {
382 return false;
383 }
384
385 size_t bpp = GrBytesPerPixel(config);
386 if (!GrSurfacePriv::AdjustReadPixelParams(surface->width(), surface->height(), bpp,
387 &left, &top, &width, &height,
388 &buffer,
389 &rowBytes)) {
390 return false;
391 }
392
393 this->handleDirtyContext();
394
395 return this->onReadPixels(surface,
396 left, top, width, height,
397 config, buffer,
398 rowBytes);
399 }
400
writePixels(GrSurface * surface,int left,int top,int width,int height,GrPixelConfig config,const SkTArray<GrMipLevel> & texels)401 bool GrGpu::writePixels(GrSurface* surface,
402 int left, int top, int width, int height,
403 GrPixelConfig config, const SkTArray<GrMipLevel>& texels) {
404 SkASSERT(surface);
405 for (int currentMipLevel = 0; currentMipLevel < texels.count(); currentMipLevel++) {
406 if (!texels[currentMipLevel].fPixels ) {
407 return false;
408 }
409 }
410
411 // We don't allow conversion between integer configs and float/fixed configs.
412 if (GrPixelConfigIsSint(surface->config()) != GrPixelConfigIsSint(config)) {
413 return false;
414 }
415
416 this->handleDirtyContext();
417 if (this->onWritePixels(surface, left, top, width, height, config, texels)) {
418 SkIRect rect = SkIRect::MakeXYWH(left, top, width, height);
419 this->didWriteToSurface(surface, &rect, texels.count());
420 fStats.incTextureUploads();
421 return true;
422 }
423 return false;
424 }
425
writePixels(GrSurface * surface,int left,int top,int width,int height,GrPixelConfig config,const void * buffer,size_t rowBytes)426 bool GrGpu::writePixels(GrSurface* surface,
427 int left, int top, int width, int height,
428 GrPixelConfig config, const void* buffer,
429 size_t rowBytes) {
430 GrMipLevel mipLevel;
431 mipLevel.fPixels = buffer;
432 mipLevel.fRowBytes = rowBytes;
433 SkSTArray<1, GrMipLevel> texels;
434 texels.push_back(mipLevel);
435
436 return this->writePixels(surface, left, top, width, height, config, texels);
437 }
438
transferPixels(GrSurface * surface,int left,int top,int width,int height,GrPixelConfig config,GrBuffer * transferBuffer,size_t offset,size_t rowBytes,GrFence * fence)439 bool GrGpu::transferPixels(GrSurface* surface,
440 int left, int top, int width, int height,
441 GrPixelConfig config, GrBuffer* transferBuffer,
442 size_t offset, size_t rowBytes, GrFence* fence) {
443 SkASSERT(transferBuffer);
444 SkASSERT(fence);
445
446 // We don't allow conversion between integer configs and float/fixed configs.
447 if (GrPixelConfigIsSint(surface->config()) != GrPixelConfigIsSint(config)) {
448 return false;
449 }
450
451 this->handleDirtyContext();
452 if (this->onTransferPixels(surface, left, top, width, height, config,
453 transferBuffer, offset, rowBytes)) {
454 SkIRect rect = SkIRect::MakeXYWH(left, top, width, height);
455 this->didWriteToSurface(surface, &rect);
456 fStats.incTransfersToTexture();
457
458 if (*fence) {
459 this->deleteFence(*fence);
460 }
461 *fence = this->insertFence();
462
463 return true;
464 }
465 return false;
466 }
467
resolveRenderTarget(GrRenderTarget * target)468 void GrGpu::resolveRenderTarget(GrRenderTarget* target) {
469 SkASSERT(target);
470 this->handleDirtyContext();
471 this->onResolveRenderTarget(target);
472 }
473
didWriteToSurface(GrSurface * surface,const SkIRect * bounds,uint32_t mipLevels) const474 void GrGpu::didWriteToSurface(GrSurface* surface, const SkIRect* bounds, uint32_t mipLevels) const {
475 SkASSERT(surface);
476 // Mark any MIP chain and resolve buffer as dirty if and only if there is a non-empty bounds.
477 if (nullptr == bounds || !bounds->isEmpty()) {
478 if (GrRenderTarget* target = surface->asRenderTarget()) {
479 target->flagAsNeedingResolve(bounds);
480 }
481 GrTexture* texture = surface->asTexture();
482 if (texture && 1 == mipLevels) {
483 texture->texturePriv().dirtyMipMaps(true);
484 }
485 }
486 }
487
queryMultisampleSpecs(const GrPipeline & pipeline)488 const GrGpu::MultisampleSpecs& GrGpu::queryMultisampleSpecs(const GrPipeline& pipeline) {
489 GrRenderTarget* rt = pipeline.getRenderTarget();
490 SkASSERT(rt->desc().fSampleCnt > 1);
491
492 GrStencilSettings stencil;
493 if (pipeline.isStencilEnabled()) {
494 // TODO: attach stencil and create settings during render target flush.
495 SkASSERT(rt->renderTargetPriv().getStencilAttachment());
496 stencil.reset(*pipeline.getUserStencil(), pipeline.hasStencilClip(),
497 rt->renderTargetPriv().numStencilBits());
498 }
499
500 int effectiveSampleCnt;
501 SkSTArray<16, SkPoint, true> pattern;
502 this->onQueryMultisampleSpecs(rt, stencil, &effectiveSampleCnt, &pattern);
503 SkASSERT(effectiveSampleCnt >= rt->desc().fSampleCnt);
504
505 uint8_t id;
506 if (this->caps()->sampleLocationsSupport()) {
507 SkASSERT(pattern.count() == effectiveSampleCnt);
508 const auto& insertResult = fMultisampleSpecsIdMap.insert(
509 MultisampleSpecsIdMap::value_type(pattern, SkTMin(fMultisampleSpecs.count(), 255)));
510 id = insertResult.first->second;
511 if (insertResult.second) {
512 // This means the insert did not find the pattern in the map already, and therefore an
513 // actual insertion took place. (We don't expect to see many unique sample patterns.)
514 const SkPoint* sampleLocations = insertResult.first->first.begin();
515 SkASSERT(id == fMultisampleSpecs.count());
516 fMultisampleSpecs.emplace_back(id, effectiveSampleCnt, sampleLocations);
517 }
518 } else {
519 id = effectiveSampleCnt;
520 for (int i = fMultisampleSpecs.count(); i <= id; ++i) {
521 fMultisampleSpecs.emplace_back(i, i, nullptr);
522 }
523 }
524 SkASSERT(id > 0);
525
526 return fMultisampleSpecs[id];
527 }
528
operator ()(const SamplePattern & a,const SamplePattern & b) const529 bool GrGpu::SamplePatternComparator::operator()(const SamplePattern& a,
530 const SamplePattern& b) const {
531 if (a.count() != b.count()) {
532 return a.count() < b.count();
533 }
534 for (int i = 0; i < a.count(); ++i) {
535 // This doesn't have geometric meaning. We just need to define an ordering for std::map.
536 if (a[i].x() != b[i].x()) {
537 return a[i].x() < b[i].x();
538 }
539 if (a[i].y() != b[i].y()) {
540 return a[i].y() < b[i].y();
541 }
542 }
543 return false; // Equal.
544 }
545