Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Context.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2021 Google LLC
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
9
23#include "src/core/SkYUVMath.h"
53
55
56#if defined(GRAPHITE_TEST_UTILS)
58#if defined(SK_DAWN)
60#include "webgpu/webgpu_cpp.h" // NO_G3_REWRITE
61#endif
62#endif
63
64namespace skgpu::graphite {
65
66#define ASSERT_SINGLE_OWNER SKGPU_ASSERT_SINGLE_OWNER(this->singleOwner())
67
69 static std::atomic<uint32_t> nextID{1};
70 uint32_t id;
71 do {
72 id = nextID.fetch_add(1, std::memory_order_relaxed);
73 } while (id == SK_InvalidUniqueID);
74 return ContextID(id);
75}
76
77//--------------------------------------------------------------------------------------------------
79 std::unique_ptr<QueueManager> queueManager,
81 : fSharedContext(std::move(sharedContext))
82 , fQueueManager(std::move(queueManager))
83 , fContextID(ContextID::Next()) {
84 // We have to create this outside the initializer list because we need to pass in the Context's
85 // SingleOwner object and it is declared last
86 fResourceProvider = fSharedContext->makeResourceProvider(&fSingleOwner,
88 options.fGpuBudgetInBytes);
89 fMappedBufferManager = std::make_unique<ClientMappedBufferManager>(this->contextID());
90#if defined(GRAPHITE_TEST_UTILS)
91 if (options.fOptionsPriv) {
92 fStoreContextRefInRecorder = options.fOptionsPriv->fStoreContextRefInRecorder;
93 }
94#endif
95}
96
98#if defined(GRAPHITE_TEST_UTILS)
100 for (auto& recorder : fTrackedRecorders) {
101 recorder->priv().setContext(nullptr);
102 }
103#endif
104}
105
106bool Context::finishInitialization() {
107 SkASSERT(!fSharedContext->rendererProvider()); // Can only initialize once
108
109 StaticBufferManager bufferManager{fResourceProvider.get(), fSharedContext->caps()};
110 std::unique_ptr<RendererProvider> renderers{
111 new RendererProvider(fSharedContext->caps(), &bufferManager)};
112
113 auto result = bufferManager.finalize(this, fQueueManager.get(), fSharedContext->globalCache());
115 // If something went wrong filling out the static vertex buffers, any Renderer that would
116 // use it will draw incorrectly, so it's better to fail the Context creation.
117 return false;
118 }
120 !fQueueManager->submitToGpu()) {
121 SKGPU_LOG_W("Failed to submit initial command buffer for Context creation.\n");
122 return false;
123 } // else result was kNoWork so skip submitting to the GPU
124 fSharedContext->setRendererProvider(std::move(renderers));
125 return true;
126}
127
128BackendApi Context::backend() const { return fSharedContext->backend(); }
129
130std::unique_ptr<Recorder> Context::makeRecorder(const RecorderOptions& options) {
132
133 auto recorder = std::unique_ptr<Recorder>(new Recorder(fSharedContext, options));
134#if defined(GRAPHITE_TEST_UTILS)
135 if (fStoreContextRefInRecorder) {
136 recorder->priv().setContext(this);
137 }
138#endif
139 return recorder;
140}
141
144
145 return fQueueManager->addRecording(info, this);
146}
147
148bool Context::submit(SyncToCpu syncToCpu) {
150
151 if (syncToCpu == SyncToCpu::kYes && !fSharedContext->caps()->allowCpuSync()) {
152 SKGPU_LOG_E("SyncToCpu::kYes not supported with ContextOptions::fNeverYieldToWebGPU. "
153 "The parameter is ignored and no synchronization will occur.");
154 syncToCpu = SyncToCpu::kNo;
155 }
156 bool success = fQueueManager->submitToGpu();
157 this->checkForFinishedWork(syncToCpu);
158 return success;
159}
160
161bool Context::hasUnfinishedGpuWork() const { return fQueueManager->hasUnfinishedGpuWork(); }
162
164 const SkImageInfo& dstImageInfo,
165 const SkIRect& srcRect,
166 SkImage::RescaleGamma rescaleGamma,
167 SkImage::RescaleMode rescaleMode,
169 SkImage::ReadPixelsContext callbackContext) {
170 if (!image || !as_IB(image)->isGraphiteBacked()) {
171 callback(callbackContext, nullptr);
172 return;
173 }
174 // TODO(b/238756380): YUVA read not supported right now
175 if (as_IB(image)->isYUVA()) {
176 callback(callbackContext, nullptr);
177 return;
178 }
179
181 callback(callbackContext, nullptr);
182 return;
183 }
184
185 if (srcRect.size() == dstImageInfo.bounds().size()) {
186 // No need for rescale
187 auto graphiteImage = reinterpret_cast<const skgpu::graphite::Image*>(image);
188 const TextureProxyView& proxyView = graphiteImage->textureProxyView();
189 return this->asyncReadPixels(proxyView.proxy(),
190 image->imageInfo(),
191 dstImageInfo.colorInfo(),
192 srcRect,
193 callback,
194 callbackContext);
195 }
196
197 // Make a recorder to record drawing commands into
198 std::unique_ptr<Recorder> recorder = this->makeRecorder();
199
200 sk_sp<SkImage> scaledImage = RescaleImage(recorder.get(),
201 image,
202 srcRect,
203 dstImageInfo,
204 rescaleGamma,
205 rescaleMode);
206 if (!scaledImage) {
207 callback(callbackContext, nullptr);
208 return;
209 }
210
211 // Add draw commands to queue before starting the transfer
212 std::unique_ptr<Recording> recording = recorder->snap();
213 if (!recording) {
214 callback(callbackContext, nullptr);
215 return;
216 }
217 InsertRecordingInfo recordingInfo;
218 recordingInfo.fRecording = recording.get();
219 if (!this->insertRecording(recordingInfo)) {
220 callback(callbackContext, nullptr);
221 return;
222 }
223
224 SkASSERT(scaledImage->imageInfo() == dstImageInfo);
225
226 auto scaledGraphiteImage = reinterpret_cast<const skgpu::graphite::Image*>(scaledImage.get());
227 const TextureProxyView& scaledProxyView = scaledGraphiteImage->textureProxyView();
228
229 this->asyncReadPixels(scaledProxyView.proxy(),
230 dstImageInfo,
231 dstImageInfo.colorInfo(),
232 dstImageInfo.bounds(),
233 callback,
234 callbackContext);
235}
236
238 const SkImageInfo& dstImageInfo,
239 const SkIRect& srcRect,
240 SkImage::RescaleGamma rescaleGamma,
241 SkImage::RescaleMode rescaleMode,
243 SkImage::ReadPixelsContext callbackContext) {
244 if (!static_cast<const SkSurface_Base*>(surface)->isGraphiteBacked()) {
245 callback(callbackContext, nullptr);
246 return;
247 }
248
250 this->asyncRescaleAndReadPixels(surfaceImage.get(),
251 dstImageInfo,
252 srcRect,
253 rescaleGamma,
254 rescaleMode,
255 callback,
256 callbackContext);
257}
258
259void Context::asyncReadPixels(const TextureProxy* proxy,
260 const SkImageInfo& srcImageInfo,
261 const SkColorInfo& dstColorInfo,
262 const SkIRect& srcRect,
264 SkImage::ReadPixelsContext callbackContext) {
265 TRACE_EVENT2("skia.gpu", TRACE_FUNC, "width", srcRect.width(), "height", srcRect.height());
266
267 if (!proxy || proxy->textureInfo().isProtected() == Protected::kYes) {
268 callback(callbackContext, nullptr);
269 return;
270 }
271
272 if (!SkImageInfoIsValid(srcImageInfo) || !SkColorInfoIsValid(dstColorInfo)) {
273 callback(callbackContext, nullptr);
274 return;
275 }
276
277 if (!SkIRect::MakeSize(srcImageInfo.dimensions()).contains(srcRect)) {
278 callback(callbackContext, nullptr);
279 return;
280 }
281
282 const Caps* caps = fSharedContext->caps();
283 if (!caps->supportsReadPixels(proxy->textureInfo())) {
284 if (!caps->isTexturable(proxy->textureInfo())) {
285 callback(callbackContext, nullptr);
286 return;
287 }
288
289 auto recorder = this->makeRecorder();
290
291 auto surface = SkSurfaces::RenderTarget(recorder.get(),
292 srcImageInfo.makeDimensions(srcRect.size()));
293 if (!surface) {
294 surface = SkSurfaces::RenderTarget(recorder.get(),
295 SkImageInfo::Make(srcRect.size(), dstColorInfo));
296 if (!surface) {
297 callback(callbackContext, nullptr);
298 return;
299 }
300 }
301
302 auto swizzle = caps->getReadSwizzle(srcImageInfo.colorType(), proxy->textureInfo());
303 TextureProxyView view(sk_ref_sp(proxy), swizzle);
304 auto srcImage = sk_make_sp<Image>(view, srcImageInfo.colorInfo());
305
307 paint.setBlendMode(SkBlendMode::kSrc);
308 surface->getCanvas()->drawImage(srcImage,
309 -srcRect.x(), -srcRect.y(),
311 &paint);
312
313 auto recording = recorder->snap();
314 InsertRecordingInfo recordingInfo;
315 recordingInfo.fRecording = recording.get();
316 this->insertRecording(recordingInfo);
317
318 this->asyncReadPixels(static_cast<Surface*>(surface.get())->readSurfaceView().proxy(),
319 surface->imageInfo(),
320 dstColorInfo,
321 SkIRect::MakeSize(srcRect.size()),
322 callback,
323 callbackContext);
324
325 return;
326 }
327
328 PixelTransferResult transferResult = this->transferPixels(proxy, srcImageInfo,
329 dstColorInfo, srcRect);
330
331 if (!transferResult.fTransferBuffer) {
332 // TODO: try to do a synchronous readPixels instead
333 callback(callbackContext, nullptr);
334 return;
335 }
336
337 this->finalizeAsyncReadPixels({&transferResult, 1}, callback, callbackContext);
338}
339
341 SkYUVColorSpace yuvColorSpace,
342 sk_sp<SkColorSpace> dstColorSpace,
343 const SkIRect& srcRect,
344 const SkISize& dstSize,
345 SkImage::RescaleGamma rescaleGamma,
346 SkImage::RescaleMode rescaleMode,
348 SkImage::ReadPixelsContext callbackContext) {
349 this->asyncRescaleAndReadPixelsYUV420Impl(image,
350 yuvColorSpace,
351 /*readAlpha=*/false,
352 dstColorSpace,
353 srcRect,
354 dstSize,
355 rescaleGamma,
356 rescaleMode,
357 callback,
358 callbackContext);
359}
360
362 SkYUVColorSpace yuvColorSpace,
363 sk_sp<SkColorSpace> dstColorSpace,
364 const SkIRect& srcRect,
365 const SkISize& dstSize,
366 SkImage::RescaleGamma rescaleGamma,
367 SkImage::RescaleMode rescaleMode,
369 SkImage::ReadPixelsContext callbackContext) {
370 if (!static_cast<const SkSurface_Base*>(surface)->isGraphiteBacked()) {
371 callback(callbackContext, nullptr);
372 return;
373 }
374
376 this->asyncRescaleAndReadPixelsYUV420(surfaceImage.get(),
377 yuvColorSpace,
378 dstColorSpace,
379 srcRect,
380 dstSize,
381 rescaleGamma,
382 rescaleMode,
383 callback,
384 callbackContext);
385}
386
388 SkYUVColorSpace yuvColorSpace,
389 sk_sp<SkColorSpace> dstColorSpace,
390 const SkIRect& srcRect,
391 const SkISize& dstSize,
392 SkImage::RescaleGamma rescaleGamma,
393 SkImage::RescaleMode rescaleMode,
395 SkImage::ReadPixelsContext callbackContext) {
396 this->asyncRescaleAndReadPixelsYUV420Impl(image,
397 yuvColorSpace,
398 /*readAlpha=*/true,
399 dstColorSpace,
400 srcRect,
401 dstSize,
402 rescaleGamma,
403 rescaleMode,
404 callback,
405 callbackContext);
406}
407
409 SkYUVColorSpace yuvColorSpace,
410 sk_sp<SkColorSpace> dstColorSpace,
411 const SkIRect& srcRect,
412 const SkISize& dstSize,
413 SkImage::RescaleGamma rescaleGamma,
414 SkImage::RescaleMode rescaleMode,
416 SkImage::ReadPixelsContext callbackContext) {
417 if (!static_cast<const SkSurface_Base*>(surface)->isGraphiteBacked()) {
418 callback(callbackContext, nullptr);
419 return;
420 }
421
423 this->asyncRescaleAndReadPixelsYUVA420(surfaceImage.get(),
424 yuvColorSpace,
425 dstColorSpace,
426 srcRect,
427 dstSize,
428 rescaleGamma,
429 rescaleMode,
430 callback,
431 callbackContext);
432}
433
434void Context::asyncRescaleAndReadPixelsYUV420Impl(const SkImage* image,
435 SkYUVColorSpace yuvColorSpace,
436 bool readAlpha,
437 sk_sp<SkColorSpace> dstColorSpace,
438 const SkIRect& srcRect,
439 const SkISize& dstSize,
440 SkImage::RescaleGamma rescaleGamma,
441 SkImage::RescaleMode rescaleMode,
443 SkImage::ReadPixelsContext callbackContext) {
444 if (!image || !as_IB(image)->isGraphiteBacked()) {
445 callback(callbackContext, nullptr);
446 return;
447 }
448
449 const SkImageInfo& srcImageInfo = image->imageInfo();
450 if (!SkIRect::MakeSize(srcImageInfo.dimensions()).contains(srcRect)) {
451 callback(callbackContext, nullptr);
452 return;
453 }
454
455 // Make a recorder to record drawing commands into
456 std::unique_ptr<Recorder> recorder = this->makeRecorder();
457
458 if (srcRect.size() == dstSize &&
460 dstColorSpace.get())) {
461 // No need for rescale
462 return this->asyncReadPixelsYUV420(recorder.get(),
463 image,
464 yuvColorSpace,
465 readAlpha,
466 srcRect,
467 callback,
468 callbackContext);
469 }
470
471 SkImageInfo dstImageInfo = SkImageInfo::Make(dstSize,
473 srcImageInfo.colorInfo().alphaType(),
474 dstColorSpace);
475 sk_sp<SkImage> scaledImage = RescaleImage(recorder.get(),
476 image,
477 srcRect,
478 dstImageInfo,
479 rescaleGamma,
480 rescaleMode);
481 if (!scaledImage) {
482 callback(callbackContext, nullptr);
483 return;
484 }
485
486 this->asyncReadPixelsYUV420(recorder.get(),
487 scaledImage.get(),
488 yuvColorSpace,
489 readAlpha,
490 SkIRect::MakeSize(dstSize),
491 callback,
492 callbackContext);
493}
494
495void Context::asyncReadPixelsYUV420(Recorder* recorder,
496 const SkImage* srcImage,
497 SkYUVColorSpace yuvColorSpace,
498 bool readAlpha,
499 const SkIRect& srcRect,
501 SkImage::ReadPixelsContext callbackContext) {
502 TRACE_EVENT2("skia.gpu", TRACE_FUNC, "width", srcRect.width(), "height", srcRect.height());
503
504 // Make three or four Surfaces to draw the YUV[A] planes into
505 SkImageInfo yaInfo = SkImageInfo::MakeA8(srcRect.size());
506 sk_sp<SkSurface> ySurface = Surface::Make(recorder, yaInfo, Budgeted::kNo);
507 sk_sp<SkSurface> aSurface;
508 if (readAlpha) {
509 aSurface = Surface::Make(recorder, yaInfo, Budgeted::kNo);
510 }
511
512 SkImageInfo uvInfo = yaInfo.makeWH(yaInfo.width()/2, yaInfo.height()/2);
513 sk_sp<SkSurface> uSurface = Surface::Make(recorder, uvInfo, Budgeted::kNo);
514 sk_sp<SkSurface> vSurface = Surface::Make(recorder, uvInfo, Budgeted::kNo);
515
516 if (!ySurface || !uSurface || !vSurface || (readAlpha && !aSurface)) {
517 callback(callbackContext, nullptr);
518 return;
519 }
520
521 // Set up draws and transfers
522 // TODO: Use one transfer buffer for all three planes to reduce map/unmap cost?
523 auto drawPlane = [](SkSurface* dstSurface,
524 const SkImage* srcImage,
525 float rgb2yuv[20],
526 const SkMatrix& texMatrix) {
527 // Render the plane defined by rgb2yuv from srcImage into dstSurface
530 sk_sp<SkShader> imgShader = srcImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp,
531 sampling, texMatrix);
532 paint.setShader(std::move(imgShader));
533
534 if (rgb2yuv) {
535 sk_sp<SkColorFilter> matrixFilter = SkColorFilters::Matrix(rgb2yuv);
536 paint.setColorFilter(std::move(matrixFilter));
537 }
538
539 SkCanvas* canvas = dstSurface->getCanvas();
540 canvas->drawPaint(paint);
541 };
542
543 auto copyPlane = [this](SkSurface* surface) {
544 // Transfer result from dstSurface
545 auto graphiteSurface = reinterpret_cast<const skgpu::graphite::Surface*>(surface);
546 TextureProxyView proxyView = graphiteSurface->readSurfaceView();
547
548 auto srcImageInfo = surface->imageInfo();
549 auto dstColorInfo = srcImageInfo.colorInfo().makeColorType(kAlpha_8_SkColorType);
550 return this->transferPixels(proxyView.proxy(),
551 srcImageInfo,
552 dstColorInfo,
553 SkIRect::MakeWH(surface->width(), surface->height()));
554 };
555
556 float baseM[20];
557 SkColorMatrix_RGB2YUV(yuvColorSpace, baseM);
558 SkMatrix texMatrix = SkMatrix::Translate(srcRect.fLeft, srcRect.fTop);
559
560 // This matrix generates (r,g,b,a) = (0, 0, 0, y)
561 float yM[20];
562 std::fill_n(yM, 15, 0.f);
563 std::copy_n(baseM + 0, 5, yM + 15);
564 drawPlane(ySurface.get(), srcImage, yM, texMatrix);
565 if (readAlpha) {
566 // No matrix, straight copy of alpha channel
567 SkASSERT(baseM[15] == 0 &&
568 baseM[16] == 0 &&
569 baseM[17] == 0 &&
570 baseM[18] == 1 &&
571 baseM[19] == 0);
572 drawPlane(aSurface.get(), srcImage, nullptr, texMatrix);
573 }
574
575 texMatrix.preScale(0.5f, 0.5f);
576 // This matrix generates (r,g,b,a) = (0, 0, 0, u)
577 float uM[20];
578 std::fill_n(uM, 15, 0.f);
579 std::copy_n(baseM + 5, 5, uM + 15);
580 drawPlane(uSurface.get(), srcImage, uM, texMatrix);
581
582 // This matrix generates (r,g,b,a) = (0, 0, 0, v)
583 float vM[20];
584 std::fill_n(vM, 15, 0.f);
585 std::copy_n(baseM + 10, 5, vM + 15);
586 drawPlane(vSurface.get(), srcImage, vM, texMatrix);
587
588 // Add draw commands to queue
589 std::unique_ptr<Recording> recording = recorder->snap();
590 if (!recording) {
591 callback(callbackContext, nullptr);
592 return;
593 }
594 InsertRecordingInfo recordingInfo;
595 recordingInfo.fRecording = recording.get();
596 if (!this->insertRecording(recordingInfo)) {
597 callback(callbackContext, nullptr);
598 return;
599 }
600
601 // Now set up transfers
602 PixelTransferResult transfers[4];
603 transfers[0] = copyPlane(ySurface.get());
604 if (!transfers[0].fTransferBuffer) {
605 callback(callbackContext, nullptr);
606 return;
607 }
608 transfers[1] = copyPlane(uSurface.get());
609 if (!transfers[1].fTransferBuffer) {
610 callback(callbackContext, nullptr);
611 return;
612 }
613 transfers[2] = copyPlane(vSurface.get());
614 if (!transfers[2].fTransferBuffer) {
615 callback(callbackContext, nullptr);
616 return;
617 }
618 if (readAlpha) {
619 transfers[3] = copyPlane(aSurface.get());
620 if (!transfers[3].fTransferBuffer) {
621 callback(callbackContext, nullptr);
622 return;
623 }
624 }
625
626 this->finalizeAsyncReadPixels({transfers, readAlpha ? 4 : 3}, callback, callbackContext);
627}
628
629void Context::finalizeAsyncReadPixels(SkSpan<PixelTransferResult> transferResults,
631 SkImage::ReadPixelsContext callbackContext) {
632 // Set up FinishContext and add transfer commands to queue
633 struct AsyncReadFinishContext {
634 SkImage::ReadPixelsCallback* fClientCallback;
635 SkImage::ReadPixelsContext fClientContext;
636 ClientMappedBufferManager* fMappedBufferManager;
637 std::array<PixelTransferResult, 4> fTransferResults;
638 };
639
640 auto finishContext = std::make_unique<AsyncReadFinishContext>();
641 finishContext->fClientCallback = callback;
642 finishContext->fClientContext = callbackContext;
643 finishContext->fMappedBufferManager = fMappedBufferManager.get();
644
645 SkASSERT(transferResults.size() <= std::size(finishContext->fTransferResults));
647 for (size_t i = 0; i < transferResults.size(); ++i) {
648 finishContext->fTransferResults[i] = std::move(transferResults[i]);
649 if (fSharedContext->caps()->bufferMapsAreAsync()) {
650 buffersToAsyncMap.push_back(finishContext->fTransferResults[i].fTransferBuffer);
651 }
652 }
653
654 InsertFinishInfo info;
655 info.fFinishedContext = finishContext.release();
656 info.fFinishedProc = [](GpuFinishedContext c, CallbackResult status) {
657 std::unique_ptr<const AsyncReadFinishContext> context(
658 reinterpret_cast<const AsyncReadFinishContext*>(c));
660
661 ClientMappedBufferManager* manager = context->fMappedBufferManager;
662 std::unique_ptr<AsyncReadResult> result;
663 if (status == CallbackResult::kSuccess) {
664 result = std::make_unique<AsyncReadResult>(manager->ownerID());
665 }
666 for (const auto& r : context->fTransferResults) {
667 if (!r.fTransferBuffer) {
668 break;
669 }
670 if (result && !result->addTransferResult(r, r.fSize, r.fRowBytes, manager)) {
671 result.reset();
672 }
673 // If we didn't get this buffer into the mapped buffer manager then make sure it gets
674 // unmapped if it has a pending or completed async map.
675 if (!result && r.fTransferBuffer->isUnmappable()) {
676 r.fTransferBuffer->unmap();
677 }
678 }
679 (*context->fClientCallback)(context->fClientContext, std::move(result));
680 };
681
682 // If addFinishInfo() fails, it invokes the finish callback automatically, which handles all the
683 // required clean up for us, just log an error message. The buffers will never be mapped and
684 // thus don't need an unmap.
685 if (!fQueueManager->addFinishInfo(info, fResourceProvider.get(), buffersToAsyncMap)) {
686 SKGPU_LOG_E("Failed to register finish callbacks for asyncReadPixels.");
687 return;
688 }
689}
690
691Context::PixelTransferResult Context::transferPixels(const TextureProxy* proxy,
692 const SkImageInfo& srcImageInfo,
693 const SkColorInfo& dstColorInfo,
694 const SkIRect& srcRect) {
695 SkASSERT(srcImageInfo.bounds().contains(srcRect));
696
697 const Caps* caps = fSharedContext->caps();
698 SkColorType supportedColorType;
699 bool isRGB888Format;
700 std::tie(supportedColorType, isRGB888Format) =
701 caps->supportedReadPixelsColorType(srcImageInfo.colorType(),
702 proxy->textureInfo(),
703 dstColorInfo.colorType());
704 if (supportedColorType == kUnknown_SkColorType) {
705 return {};
706 }
707
708 // Fail if read color type does not have all of dstCT's color channels and those missing color
709 // channels are in the src.
710 uint32_t dstChannels = SkColorTypeChannelFlags(dstColorInfo.colorType());
711 uint32_t legalReadChannels = SkColorTypeChannelFlags(supportedColorType);
712 uint32_t srcChannels = SkColorTypeChannelFlags(srcImageInfo.colorType());
713 if ((~legalReadChannels & dstChannels) & srcChannels) {
714 return {};
715 }
716
717 int bpp = isRGB888Format ? 3 : SkColorTypeBytesPerPixel(supportedColorType);
718 size_t rowBytes = caps->getAlignedTextureDataRowBytes(bpp * srcRect.width());
719 size_t size = SkAlignTo(rowBytes * srcRect.height(), caps->requiredTransferBufferAlignment());
720 sk_sp<Buffer> buffer = fResourceProvider->findOrCreateBuffer(
722 if (!buffer) {
723 return {};
724 }
725
726 // Set up copy task. Since we always use a new buffer the offset can be 0 and we don't need to
727 // worry about aligning it to the required transfer buffer alignment.
729 srcRect,
730 buffer,
731 /*bufferOffset=*/0,
732 rowBytes);
733 if (!copyTask || !fQueueManager->addTask(copyTask.get(), this)) {
734 return {};
735 }
737 if (!syncTask || !fQueueManager->addTask(syncTask.get(), this)) {
738 return {};
739 }
740
741 PixelTransferResult result;
742 result.fTransferBuffer = std::move(buffer);
743 result.fSize = srcRect.size();
744 if (srcImageInfo.colorInfo() != dstColorInfo || isRGB888Format) {
745 SkISize dims = srcRect.size();
746 SkImageInfo srcInfo = SkImageInfo::Make(dims, srcImageInfo.colorInfo());
747 SkImageInfo dstInfo = SkImageInfo::Make(dims, dstColorInfo);
748 result.fRowBytes = dstInfo.minRowBytes();
749 result.fPixelConverter = [dstInfo, srcInfo, rowBytes, isRGB888Format](
750 void* dst, const void* src) {
752 size_t srcRowBytes = rowBytes;
753 if (isRGB888Format) {
754 temp.alloc(srcInfo);
755 size_t tRowBytes = temp.rowBytes();
756 auto* sRow = reinterpret_cast<const char*>(src);
757 auto* tRow = reinterpret_cast<char*>(temp.writable_addr());
758 for (int y = 0; y < srcInfo.height(); ++y, sRow += srcRowBytes, tRow += tRowBytes) {
759 for (int x = 0; x < srcInfo.width(); ++x) {
760 auto s = sRow + x*3;
761 auto t = tRow + x*sizeof(uint32_t);
762 memcpy(t, s, 3);
763 t[3] = static_cast<char>(0xFF);
764 }
765 }
766 src = temp.addr();
767 srcRowBytes = tRowBytes;
768 }
769 SkAssertResult(SkConvertPixels(dstInfo, dst, dstInfo.minRowBytes(),
770 srcInfo, src, srcRowBytes));
771 };
772 } else {
773 result.fRowBytes = rowBytes;
774 }
775
776 return result;
777}
778
779void Context::checkForFinishedWork(SyncToCpu syncToCpu) {
781
782 fQueueManager->checkForFinishedWork(syncToCpu);
783 fMappedBufferManager->process();
784}
785
787 this->checkForFinishedWork(SyncToCpu::kNo);
788}
789
792
793 if (!texture.isValid() || texture.backend() != this->backend()) {
794 return;
795 }
796 fResourceProvider->deleteBackendTexture(texture);
797}
798
801
803
804 fResourceProvider->freeGpuResources();
805}
806
807void Context::performDeferredCleanup(std::chrono::milliseconds msNotUsed) {
809
811
812 auto purgeTime = skgpu::StdSteadyClock::now() - msNotUsed;
813 fResourceProvider->purgeResourcesNotUsedSince(purgeTime);
814}
815
818 return fResourceProvider->getResourceCacheCurrentBudgetedBytes();
819}
820
823 return fResourceProvider->getResourceCacheLimit();
824}
825
828 fResourceProvider->dumpMemoryStatistics(traceMemoryDump);
829 // TODO: What is the graphite equivalent for the text blob cache and how do we print out its
830 // used bytes here (see Ganesh implementation).
831}
832
834 return fSharedContext->isDeviceLost();
835}
836
838 return fSharedContext->caps()->maxTextureSize();
839}
840
842 return fSharedContext->isProtected() == Protected::kYes;
843}
844
845///////////////////////////////////////////////////////////////////////////////////
846
847#if defined(GRAPHITE_TEST_UTILS)
848bool ContextPriv::readPixels(const SkPixmap& pm,
849 const TextureProxy* textureProxy,
850 const SkImageInfo& srcImageInfo,
851 int srcX, int srcY) {
852 auto rect = SkIRect::MakeXYWH(srcX, srcY, pm.width(), pm.height());
853 struct AsyncContext {
854 bool fCalled = false;
855 std::unique_ptr<const SkImage::AsyncReadResult> fResult;
856 } asyncContext;
857 fContext->asyncReadPixels(textureProxy, srcImageInfo, pm.info().colorInfo(), rect,
858 [](void* c, std::unique_ptr<const SkImage::AsyncReadResult> result) {
859 auto context = static_cast<AsyncContext*>(c);
860 context->fResult = std::move(result);
861 context->fCalled = true;
862 },
863 &asyncContext);
864
865 if (fContext->fSharedContext->caps()->allowCpuSync()) {
866 fContext->submit(SyncToCpu::kYes);
867 } else {
868 fContext->submit(SyncToCpu::kNo);
869 if (fContext->fSharedContext->backend() == BackendApi::kDawn) {
870 while (!asyncContext.fCalled) {
871#if defined(SK_DAWN)
872 auto dawnContext = static_cast<DawnSharedContext*>(fContext->fSharedContext.get());
873 dawnContext->device().Tick();
874 fContext->checkAsyncWorkCompletion();
875#endif
876 }
877 } else {
878 SK_ABORT("Only Dawn supports non-synching contexts.");
879 }
880 }
881 SkASSERT(asyncContext.fCalled);
882 if (!asyncContext.fResult) {
883 return false;
884 }
885 SkRectMemcpy(pm.writable_addr(), pm.rowBytes(), asyncContext.fResult->data(0),
886 asyncContext.fResult->rowBytes(0), pm.info().minRowBytes(),
887 pm.height());
888 return true;
889}
890
891void ContextPriv::deregisterRecorder(const Recorder* recorder) {
892 SKGPU_ASSERT_SINGLE_OWNER(fContext->singleOwner())
893 for (auto it = fContext->fTrackedRecorders.begin();
894 it != fContext->fTrackedRecorders.end();
895 it++) {
896 if (*it == recorder) {
897 fContext->fTrackedRecorders.erase(it);
898 return;
899 }
900 }
901}
902
903bool ContextPriv::supportsPathRendererStrategy(PathRendererStrategy strategy) {
906 switch (strategy) {
908 return true;
912 return SkToBool(pathAtlasFlags & AtlasProvider::PathAtlasFlags::kCompute);
914 return SkToBool(pathAtlasFlags & AtlasProvider::PathAtlasFlags::kRaster);
916 return true;
917 }
918
919 return false;
920}
921
922#endif
923
924///////////////////////////////////////////////////////////////////////////////////
925
926std::unique_ptr<Context> ContextCtorAccessor::MakeContext(
927 sk_sp<SharedContext> sharedContext,
928 std::unique_ptr<QueueManager> queueManager,
929 const ContextOptions& options) {
930 auto context = std::unique_ptr<Context>(new Context(std::move(sharedContext),
931 std::move(queueManager),
932 options));
933 if (context && context->finishInitialization()) {
934 return context;
935 } else {
936 return nullptr;
937 }
938}
939
940} // namespace skgpu::graphite
const char * options
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
#define SKGPU_LOG_E(fmt,...)
Definition Log.h:38
#define SKGPU_LOG_W(fmt,...)
Definition Log.h:40
#define SKGPU_ASSERT_SINGLE_OWNER(obj)
Definition SingleOwner.h:69
static constexpr size_t SkAlignTo(size_t x, size_t alignment)
Definition SkAlign.h:33
#define SkAssertResult(cond)
Definition SkAssert.h:123
#define SK_ABORT(message,...)
Definition SkAssert.h:70
#define SkASSERT(cond)
Definition SkAssert.h:116
SkColorType
Definition SkColorType.h:19
@ kAlpha_8_SkColorType
pixel with alpha in 8-bit byte
Definition SkColorType.h:21
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
Definition SkColorType.h:24
@ kUnknown_SkColorType
uninitialized
Definition SkColorType.h:20
bool SkConvertPixels(const SkImageInfo &dstInfo, void *dstPixels, size_t dstRB, const SkImageInfo &srcInfo, const void *srcPixels, size_t srcRB)
static uint32_t SkColorTypeChannelFlags(SkColorType ct)
static bool SkColorInfoIsValid(const SkColorInfo &info)
static bool SkImageInfoIsValid(const SkImageInfo &info)
SK_API int SkColorTypeBytesPerPixel(SkColorType ct)
SkYUVColorSpace
Definition SkImageInfo.h:68
static SkImage_Base * as_IB(SkImage *image)
static void SkRectMemcpy(void *dst, size_t dstRB, const void *src, size_t srcRB, size_t trimRowBytes, int rowCount)
sk_sp< T > sk_ref_sp(T *obj)
Definition SkRefCnt.h:381
static constexpr bool SkToBool(const T &x)
Definition SkTo.h:35
#define TRACE_FUNC
static constexpr uint32_t SK_InvalidUniqueID
Definition SkTypes.h:196
static constexpr uint32_t SK_InvalidGenID
Definition SkTypes.h:192
void SkColorMatrix_RGB2YUV(SkYUVColorSpace cs, float m[20])
const sk_sp< Effect > & get() const
void alloc(const SkImageInfo &)
void drawPaint(const SkPaint &paint)
static sk_sp< SkColorFilter > Matrix(const SkColorMatrix &)
SkAlphaType alphaType() const
SkColorInfo makeColorType(SkColorType newColorType) const
SkColorSpace * colorSpace() const
SkColorType colorType() const
static bool Equals(const SkColorSpace *, const SkColorSpace *)
const SkImageInfo & imageInfo() const
Definition SkImage.h:279
void * ReadPixelsContext
Definition SkImage.h:578
RescaleMode
Definition SkImage.h:587
RescaleGamma
Definition SkImage.h:585
void(ReadPixelsContext, std::unique_ptr< const AsyncReadResult >) ReadPixelsCallback
Definition SkImage.h:583
static SkMatrix Translate(SkScalar dx, SkScalar dy)
Definition SkMatrix.h:91
SkMatrix & preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py)
Definition SkMatrix.cpp:315
size_t rowBytes() const
Definition SkPixmap.h:145
int width() const
Definition SkPixmap.h:160
const SkImageInfo & info() const
Definition SkPixmap.h:135
void * writable_addr() const
Definition SkPixmap.h:483
const void * addr() const
Definition SkPixmap.h:153
int height() const
Definition SkPixmap.h:166
constexpr size_t size() const
Definition SkSpan_impl.h:95
SkCanvas * getCanvas()
Definition SkSurface.cpp:82
T * get() const
Definition SkRefCnt.h:303
static PathAtlasFlagsBitMask QueryPathAtlasSupport(const Caps *)
SkEnumBitMask< PathAtlasFlags > PathAtlasFlagsBitMask
static std::unique_ptr< Context > MakeContext(sk_sp< SharedContext >, std::unique_ptr< QueueManager >, const ContextOptions &)
Definition Context.cpp:926
const Caps * caps() const
Definition ContextPriv.h:32
static Context::ContextID Next()
Definition Context.cpp:68
size_t maxBudgetedBytes() const
Definition Context.cpp:821
ContextID contextID() const
Definition Context.h:203
BackendApi backend() const
Definition Context.cpp:128
int maxTextureSize() const
Definition Context.cpp:837
void asyncRescaleAndReadPixelsYUV420(const SkImage *, SkYUVColorSpace yuvColorSpace, sk_sp< SkColorSpace > dstColorSpace, const SkIRect &srcRect, const SkISize &dstSize, SkImage::RescaleGamma rescaleGamma, SkImage::RescaleMode rescaleMode, SkImage::ReadPixelsCallback callback, SkImage::ReadPixelsContext context)
Definition Context.cpp:340
std::unique_ptr< Recorder > makeRecorder(const RecorderOptions &={})
Definition Context.cpp:130
void asyncRescaleAndReadPixelsYUVA420(const SkImage *, SkYUVColorSpace yuvColorSpace, sk_sp< SkColorSpace > dstColorSpace, const SkIRect &srcRect, const SkISize &dstSize, SkImage::RescaleGamma rescaleGamma, SkImage::RescaleMode rescaleMode, SkImage::ReadPixelsCallback callback, SkImage::ReadPixelsContext context)
Definition Context.cpp:387
void performDeferredCleanup(std::chrono::milliseconds msNotUsed)
Definition Context.cpp:807
bool submit(SyncToCpu=SyncToCpu::kNo)
Definition Context.cpp:148
void deleteBackendTexture(const BackendTexture &)
Definition Context.cpp:790
bool insertRecording(const InsertRecordingInfo &)
Definition Context.cpp:142
bool supportsProtectedContent() const
Definition Context.cpp:841
size_t currentBudgetedBytes() const
Definition Context.cpp:816
Context(const Context &)=delete
void dumpMemoryStatistics(SkTraceMemoryDump *traceMemoryDump) const
Definition Context.cpp:826
void asyncRescaleAndReadPixels(const SkImage *image, const SkImageInfo &dstImageInfo, const SkIRect &srcRect, SkImage::RescaleGamma rescaleGamma, SkImage::RescaleMode rescaleMode, SkImage::ReadPixelsCallback callback, SkImage::ReadPixelsContext context)
Definition Context.cpp:163
bool hasUnfinishedGpuWork() const
Definition Context.cpp:161
bool isDeviceLost() const
Definition Context.cpp:833
static sk_sp< CopyTextureToBufferTask > Make(sk_sp< TextureProxy >, SkIRect srcRect, sk_sp< Buffer >, size_t bufferOffset, size_t bufferRowBytes)
Definition CopyTask.cpp:62
std::unique_ptr< Recording > snap()
Definition Recorder.cpp:149
static sk_sp< Surface > Make(Recorder *recorder, const SkImageInfo &info, Budgeted budgeted, Mipmapped mipmapped=Mipmapped::kNo, SkBackingFit backingFit=SkBackingFit::kExact, const SkSurfaceProps *props=nullptr)
TextureProxyView readSurfaceView() const
static sk_sp< SynchronizeToCpuTask > Make(sk_sp< Buffer >)
Protected isProtected() const
Definition TextureInfo.h:80
const TextureInfo & textureInfo() const
const Paint & paint
static const char * begin(const StringSlice &s)
Definition editor.cpp:252
VkSurfaceKHR surface
Definition main.cc:49
sk_sp< SkImage > image
Definition examples.cpp:29
struct MyStruct s
glong glong end
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
static const uint8_t buffer[]
GAsyncResult * result
#define ASSERT_SINGLE_OWNER
Definition Device.cpp:120
FlTexture * texture
double y
double x
SkSamplingOptions sampling
Definition SkRecords.h:337
SK_API sk_sp< SkImage > AsImage(sk_sp< const SkSurface >)
SK_API sk_sp< SkSurface > RenderTarget(GrRecordingContext *context, skgpu::Budgeted budgeted, const SkImageInfo &imageInfo, int sampleCount, GrSurfaceOrigin surfaceOrigin, const SkSurfaceProps *surfaceProps, bool shouldCreateWithMips=false, bool isProtected=false)
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font manager
Definition switches.h:218
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition switches.h:259
dst
Definition cp.py:12
sk_sp< SkImage > RescaleImage(Recorder *recorder, const SkImage *srcImage, SkIRect srcIRect, const SkImageInfo &dstInfo, SkImage::RescaleGamma rescaleGamma, SkImage::RescaleMode rescaleMode)
void * GpuFinishedContext
BackendApi
Definition GpuTypes.h:22
CallbackResult
Definition GpuTypes.h:45
Definition ref_ptr.h:256
constexpr int32_t x() const
Definition SkRect.h:141
constexpr int32_t y() const
Definition SkRect.h:148
constexpr SkISize size() const
Definition SkRect.h:172
constexpr int32_t height() const
Definition SkRect.h:165
int32_t fTop
smaller y-axis bounds
Definition SkRect.h:34
static constexpr SkIRect MakeSize(const SkISize &size)
Definition SkRect.h:66
constexpr int32_t width() const
Definition SkRect.h:158
static constexpr SkIRect MakeWH(int32_t w, int32_t h)
Definition SkRect.h:56
static constexpr SkIRect MakeXYWH(int32_t x, int32_t y, int32_t w, int32_t h)
Definition SkRect.h:104
int32_t fLeft
smaller x-axis bounds
Definition SkRect.h:33
bool contains(int32_t x, int32_t y) const
Definition SkRect.h:463
SkImageInfo makeWH(int newWidth, int newHeight) const
const SkColorInfo & colorInfo() const
SkIRect bounds() const
size_t minRowBytes() const
SkImageInfo makeDimensions(SkISize newSize) const
SkISize dimensions() const
int width() const
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
SkColorType colorType() const
int height() const
static SkImageInfo MakeA8(int width, int height)
ContextOptionsPriv * fOptionsPriv
const uintptr_t id
#define TRACE_EVENT2(category_group, name, arg1_name, arg1_val, arg2_name, arg2_val)