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