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/SkCanvas.h"
9 #include "include/core/SkRRect.h"
10 #include "include/core/SkRect.h"
11 #include "include/core/SkStream.h"
12 #include "include/core/SkSurface.h"
13 #include "include/gpu/GrDirectContext.h"
14 #include "include/gpu/ganesh/SkSurfaceGanesh.h"
15 #include "include/gpu/ganesh/gl/GrGLDirectContext.h"
16 #include "include/gpu/gl/GrGLInterface.h"
17 #include "include/encode/SkWebpEncoder.h"
18
19 #if defined(__linux__)
20 #include "include/gpu/ganesh/gl/glx/GrGLMakeGLXInterface.h"
21
22 #include <X11/Xlib.h>
23 #include <GL/glx.h>
24 #include <GL/gl.h>
25 #endif
26
27 #if defined(__APPLE__) && TARGET_OS_MAC == 1
28 #include "include/gpu/ganesh/gl/mac/GrGLMakeMacInterface.h"
29
30 #include "gl_context_helper.h"
31 #endif
32
33 #include <cstdio>
34
35 #if defined(__linux__)
36
37 // Set up an X Display that can be rendered to GL. This will not be visible while
38 // the program runs. It is cribbed from how Skia's tooling sets itself up (e.g. viewer).
initialize_gl_linux()39 bool initialize_gl_linux() {
40 Display* display = XOpenDisplay(nullptr);
41 if (!display) {
42 printf("Could not open an X display\n");
43 return false;
44 }
45 static int constexpr kChooseFBConfigAtt[] = {
46 GLX_RENDER_TYPE, GLX_RGBA_BIT,
47 GLX_DOUBLEBUFFER, True,
48 GLX_STENCIL_SIZE, 8,
49 None
50 };
51 int n;
52 GLXFBConfig* fbConfig = glXChooseFBConfig(display, DefaultScreen(display), kChooseFBConfigAtt, &n);
53 XVisualInfo* visualInfo;
54 if (n > 0) {
55 visualInfo = glXGetVisualFromFBConfig(display, *fbConfig);
56 } else {
57 // For some reason glXChooseVisual takes a non-const pointer to the attributes.
58 int chooseVisualAtt[] = {
59 GLX_RGBA,
60 GLX_DOUBLEBUFFER,
61 GLX_STENCIL_SIZE, 8,
62 None
63 };
64 visualInfo = glXChooseVisual(display, DefaultScreen(display), chooseVisualAtt);
65 }
66 if (!visualInfo) {
67 printf("Could not get X visualInfo\n");
68 return false;
69 }
70 GLXContext glContext = glXCreateContext(display, visualInfo, nullptr, GL_TRUE);
71 if (!glContext) {
72 printf("Could not make GL X context\n");
73 return false;
74 }
75 Colormap colorMap = XCreateColormap(display,
76 RootWindow(display, visualInfo->screen),
77 visualInfo->visual,
78 AllocNone);
79 XSetWindowAttributes swa;
80 swa.colormap = colorMap;
81 swa.event_mask = 0;
82 Window window = XCreateWindow(display,
83 RootWindow(display, visualInfo->screen),
84 0, 0, // x, y
85 1280, 960, // width, height
86 0, // border width
87 visualInfo->depth,
88 InputOutput,
89 visualInfo->visual,
90 CWEventMask | CWColormap,
91 &swa);
92
93 if (!glXMakeCurrent(display, window, glContext)) {
94 printf("Could not set GL X context to be the created one\n");
95 return false;
96 }
97 return true;
98 }
99 #endif // defined(__linux__)
100
main(int argc,char ** argv)101 int main(int argc, char** argv) {
102 if (argc != 2) {
103 printf("Usage: %s <name.webp>\n", argv[0]);
104 return 1;
105 }
106
107 SkFILEWStream output(argv[1]);
108 if (!output.isValid()) {
109 printf("Cannot open output file %s\n", argv[1]);
110 return 1;
111 }
112
113 GrContextOptions opts;
114 opts.fSuppressPrints = true;
115 #if defined(__linux__)
116 if (!initialize_gl_linux()) {
117 return 1;
118 }
119 sk_sp<const GrGLInterface> interface = GrGLInterfaces::MakeGLX();
120 #elif defined(__APPLE__) && TARGET_OS_MAC == 1
121 if (!initialize_gl_mac()) {
122 return 1;
123 }
124 sk_sp<const GrGLInterface> interface = GrGLInterfaces::MakeMac();
125 #endif
126 if (!interface) {
127 printf("Could not make GL interface\n");
128 return 1;
129 }
130
131 sk_sp<GrDirectContext> ctx = GrDirectContexts::MakeGL(interface, opts);
132 if (!ctx) {
133 printf("Could not make GrDirectContext\n");
134 return 1;
135 }
136 printf("Context made, now to make the surface\n");
137
138 SkImageInfo imageInfo =
139 SkImageInfo::Make(200, 400, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
140
141 sk_sp<SkSurface> surface =
142 SkSurfaces::RenderTarget(ctx.get(), skgpu::Budgeted::kYes, imageInfo);
143 if (!surface) {
144 printf("Could not make surface from GL DirectContext\n");
145 return 1;
146 }
147
148 SkCanvas* canvas = surface->getCanvas();
149 canvas->clear(SK_ColorRED);
150 SkRRect rrect = SkRRect::MakeRectXY(SkRect::MakeLTRB(10, 20, 50, 70), 10, 10);
151
152 SkPaint paint;
153 paint.setColor(SK_ColorBLUE);
154 paint.setAntiAlias(true);
155
156 canvas->drawRRect(rrect, paint);
157
158 ctx->flush();
159
160 printf("Drew to surface, now doing readback\n");
161 sk_sp<SkImage> img = surface->makeImageSnapshot();
162 sk_sp<SkData> webp = SkWebpEncoder::Encode(ctx.get(), img.get(), {});
163 if (!webp) {
164 printf("Readback of pixels (or encoding) failed\n");
165 return 1;
166 }
167 output.write(webp->data(), webp->size());
168 output.fsync();
169
170 return 0;
171 }
172