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