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