1 /*
2 * Copyright 2024 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
8 #include "include/core/SkBitmap.h"
9 #include "include/core/SkCanvas.h"
10 #include "include/core/SkImage.h"
11 #include "include/core/SkRRect.h"
12 #include "include/core/SkRect.h"
13 #include "include/core/SkSize.h"
14 #include "include/core/SkStream.h"
15 #include "include/core/SkSurface.h"
16 #include "include/encode/SkJpegEncoder.h"
17 #include "include/gpu/graphite/Context.h"
18 #include "include/gpu/graphite/ContextOptions.h"
19 #include "include/gpu/graphite/GraphiteTypes.h"
20 #include "include/gpu/graphite/Recorder.h"
21 #include "include/gpu/graphite/Surface.h"
22 #include "include/gpu/graphite/mtl/MtlBackendContext.h"
23 #include "include/gpu/graphite/mtl/MtlGraphiteUtils.h"
24
25 #include "graphite_metal_context_helper.h"
26
27 #define WIDTH 200
28 #define HEIGHT 400
29
main(int argc,char * argv[])30 int main(int argc, char *argv[]) {
31 if (argc != 2) {
32 printf("Usage: %s <name.jpeg>\n", argv[0]);
33 return 1;
34 }
35
36 SkFILEWStream output(argv[1]);
37 if (!output.isValid()) {
38 printf("Cannot open output file %s\n", argv[1]);
39 return 1;
40 }
41
42 skgpu::graphite::MtlBackendContext backendContext = GetMetalContext();
43 skgpu::graphite::ContextOptions options;
44
45 std::unique_ptr<skgpu::graphite::Context> context =
46 skgpu::graphite::ContextFactory::MakeMetal(backendContext, options);
47 if (!context) {
48 printf("Could not make Graphite Native Metal context\n");
49 return 1;
50 }
51 printf("Context made, now to make the surface\n");
52
53 SkImageInfo imageInfo =
54 SkImageInfo::Make(WIDTH, HEIGHT, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
55
56 std::unique_ptr<skgpu::graphite::Recorder> recorder = context->makeRecorder();
57 if (!recorder) {
58 printf("Could not make recorder\n");
59 return 1;
60 }
61 sk_sp<SkSurface> surface =
62 SkSurfaces::RenderTarget(recorder.get(), imageInfo);
63 if (!surface) {
64 printf("Could not make surface from Metal Recorder\n");
65 return 1;
66 }
67
68 SkCanvas* canvas = surface->getCanvas();
69 canvas->clear(SK_ColorCYAN);
70 SkRRect rrect = SkRRect::MakeRectXY(SkRect::MakeLTRB(10, 20, 50, 70), 10, 10);
71
72 SkPaint paint;
73 paint.setColor(SK_ColorYELLOW);
74 paint.setAntiAlias(true);
75
76 canvas->drawRRect(rrect, paint);
77
78 printf("ready to snap the GPU calls\n");
79 // Now to send the draws to the GPU
80 std::unique_ptr<skgpu::graphite::Recording> recording = recorder->snap();
81 if (!recording) {
82 printf("Could not create a recording\n");
83 return 1;
84 }
85 skgpu::graphite::InsertRecordingInfo info;
86 info.fRecording = recording.get();
87 if (!context->insertRecording(info)) {
88 printf("Context::insertRecording failed\n");
89 return 1;
90 }
91
92 sk_sp<SkImage> img;
93 auto callback = [](SkImage::ReadPixelsContext ctx,
94 std::unique_ptr<const SkImage::AsyncReadResult> result) {
95 if (result->count() != 1) {
96 printf("Didn't load exactly one plane\n");
97 return;
98 }
99 auto ii = SkImageInfo::Make(WIDTH, HEIGHT, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
100 sk_sp<SkImage>* output = reinterpret_cast<sk_sp<SkImage>*>(ctx);
101
102 SkPixmap pm(ii, result->data(0), result->rowBytes(0));
103 *output = SkImages::RasterFromPixmapCopy(pm);
104 };
105 printf("GPU operations modifying surface have been inserted in the command buffer,"
106 "scheduling pixel readback\n");
107 context->asyncRescaleAndReadPixels(surface.get(), imageInfo, SkIRect::MakeSize({WIDTH, HEIGHT}),
108 SkImage::RescaleGamma::kSrc,
109 SkImage::RescaleMode::kRepeatedCubic,
110 callback, &img);
111
112 printf("Submitting work to GPU and waiting for it to be done\n");
113 // Note this doesn't work on all backend types, e.g. Dawn.
114 context->submit(skgpu::graphite::SyncToCpu::kYes);
115 if (context->hasUnfinishedGpuWork()) {
116 printf("Sync with GPU completion failed\n");
117 return 1;
118 }
119
120 sk_sp<SkData> jpeg = SkJpegEncoder::Encode(nullptr, img.get(), {});
121 if (!jpeg) {
122 printf("Encoding failed\n");
123 return 1;
124 }
125 output.write(jpeg->data(), jpeg->size());
126 output.fsync();
127 printf("done\n");
128 return 0;
129 }
130