blob: 95c0828c26db6fbfc758de8b2cfe4d7a25e6aeba [file] [log] [blame]
joshualitt04d52f32015-11-13 11:22:19 -08001/*
2 * Copyright 2015 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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05009#include "include/gpu/GrBackendSurface.h"
Robert Phillips4e105e22020-07-16 09:18:50 -040010#include "include/gpu/GrDirectContext.h"
joshualitt04d52f32015-11-13 11:22:19 -080011#include "SDL.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050012#include "include/core/SkCanvas.h"
13#include "include/core/SkFont.h"
14#include "include/core/SkSurface.h"
15#include "include/utils/SkRandom.h"
joshualitt04d52f32015-11-13 11:22:19 -080016
Mike Kleinc0bd9f92019-04-23 12:05:21 -050017#include "include/gpu/gl/GrGLInterface.h"
18#include "src/gpu/gl/GrGLUtil.h"
joshualitt04d52f32015-11-13 11:22:19 -080019
20#if defined(SK_BUILD_FOR_ANDROID)
21#include <GLES/gl.h>
22#elif defined(SK_BUILD_FOR_UNIX)
23#include <GL/gl.h>
24#elif defined(SK_BUILD_FOR_MAC)
jvanverth1ba1d372016-08-04 12:30:31 -070025#include <OpenGL/gl.h>
Jim Van Verthecfed2b2017-08-30 14:02:50 -040026#elif defined(SK_BUILD_FOR_IOS)
27#include <OpenGLES/ES2/gl.h>
joshualitt04d52f32015-11-13 11:22:19 -080028#endif
29
30/*
31 * This application is a simple example of how to combine SDL and Skia it demonstrates:
32 * how to setup gpu rendering to the main window
33 * how to perform cpu-side rendering and draw the result to the gpu-backed screen
34 * draw simple primitives (rectangles)
35 * draw more complex primitives (star)
36 */
37
38struct ApplicationState {
39 ApplicationState() : fQuit(false) {}
40 // Storage for the user created rectangles. The last one may still be being edited.
41 SkTArray<SkRect> fRects;
42 bool fQuit;
43};
44
45static void handle_error() {
46 const char* error = SDL_GetError();
47 SkDebugf("SDL Error: %s\n", error);
48 SDL_ClearError();
49}
50
51static void handle_events(ApplicationState* state, SkCanvas* canvas) {
52 SDL_Event event;
53 while(SDL_PollEvent(&event)) {
54 switch (event.type) {
55 case SDL_MOUSEMOTION:
56 if (event.motion.state == SDL_PRESSED) {
57 SkRect& rect = state->fRects.back();
58 rect.fRight = event.motion.x;
59 rect.fBottom = event.motion.y;
60 }
61 break;
62 case SDL_MOUSEBUTTONDOWN:
63 if (event.button.state == SDL_PRESSED) {
64 state->fRects.push_back() = SkRect::MakeLTRB(SkIntToScalar(event.button.x),
65 SkIntToScalar(event.button.y),
66 SkIntToScalar(event.button.x),
67 SkIntToScalar(event.button.y));
68 }
69 break;
70 case SDL_KEYDOWN: {
71 SDL_Keycode key = event.key.keysym.sym;
72 if (key == SDLK_ESCAPE) {
73 state->fQuit = true;
74 }
75 break;
76 }
77 case SDL_QUIT:
78 state->fQuit = true;
79 break;
80 default:
81 break;
82 }
83 }
84}
85
86// Creates a star type shape using a SkPath
87static SkPath create_star() {
88 static const int kNumPoints = 5;
89 SkPath concavePath;
90 SkPoint points[kNumPoints] = {{0, SkIntToScalar(-50)} };
91 SkMatrix rot;
92 rot.setRotate(SkIntToScalar(360) / kNumPoints);
93 for (int i = 1; i < kNumPoints; ++i) {
94 rot.mapPoints(points + i, points + i - 1, 1);
95 }
96 concavePath.moveTo(points[0]);
97 for (int i = 0; i < kNumPoints; ++i) {
98 concavePath.lineTo(points[(2 * i) % kNumPoints]);
99 }
Mike Reed7d34dc72019-11-26 12:17:17 -0500100 concavePath.setFillType(SkPathFillType::kEvenOdd);
joshualitt04d52f32015-11-13 11:22:19 -0800101 SkASSERT(!concavePath.isConvex());
102 concavePath.close();
103 return concavePath;
104}
105
106#if defined(SK_BUILD_FOR_ANDROID)
107int SDL_main(int argc, char** argv) {
108#else
109int main(int argc, char** argv) {
110#endif
111 uint32_t windowFlags = 0;
112
113 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
114 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
115
116 SDL_GLContext glContext = nullptr;
Jim Van Verth2259bd42017-09-01 14:49:09 -0400117#if defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_IOS)
118 // For Android/iOS we need to set up for OpenGL ES and we make the window hi res & full screen
joshualitt04d52f32015-11-13 11:22:19 -0800119 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
120 windowFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE |
121 SDL_WINDOW_BORDERLESS | SDL_WINDOW_FULLSCREEN_DESKTOP |
122 SDL_WINDOW_ALLOW_HIGHDPI;
123#else
124 // For all other clients we use the core profile and operate in a window
125 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
126
127 windowFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE;
128#endif
129 static const int kStencilBits = 8; // Skia needs 8 stencil bits
130 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
131 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
132 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
133 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
134 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0);
135 SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, kStencilBits);
136
137 SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
138
139 // If you want multisampling, uncomment the below lines and set a sample count
140 static const int kMsaaSampleCount = 0; //4;
141 // SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
142 // SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, kMsaaSampleCount);
143
144 /*
145 * In a real application you might want to initialize more subsystems
146 */
147 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) != 0) {
148 handle_error();
149 return 1;
150 }
151
152 // Setup window
153 // This code will create a window with the same resolution as the user's desktop.
154 SDL_DisplayMode dm;
155 if (SDL_GetDesktopDisplayMode(0, &dm) != 0) {
156 handle_error();
157 return 1;
158 }
159
160 SDL_Window* window = SDL_CreateWindow("SDL Window", SDL_WINDOWPOS_CENTERED,
161 SDL_WINDOWPOS_CENTERED, dm.w, dm.h, windowFlags);
162
163 if (!window) {
164 handle_error();
165 return 1;
166 }
167
168 // To go fullscreen
169 // SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN);
170
171 // try and setup a GL context
172 glContext = SDL_GL_CreateContext(window);
173 if (!glContext) {
174 handle_error();
175 return 1;
176 }
177
178 int success = SDL_GL_MakeCurrent(window, glContext);
179 if (success != 0) {
180 handle_error();
181 return success;
182 }
183
Greg Danielfaa095e2017-12-19 13:15:02 -0500184 uint32_t windowFormat = SDL_GetWindowPixelFormat(window);
185 int contextType;
186 SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &contextType);
187
188
Jim Van Verth2259bd42017-09-01 14:49:09 -0400189 int dw, dh;
190 SDL_GL_GetDrawableSize(window, &dw, &dh);
191
192 glViewport(0, 0, dw, dh);
joshualitt04d52f32015-11-13 11:22:19 -0800193 glClearColor(1, 1, 1, 1);
194 glClearStencil(0);
195 glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
196
197 // setup GrContext
Brian Salomon3d6801e2017-12-11 10:06:31 -0500198 auto interface = GrGLMakeNativeInterface();
joshualitt04d52f32015-11-13 11:22:19 -0800199
joshualitt04d52f32015-11-13 11:22:19 -0800200 // setup contexts
Robert Phillips4e105e22020-07-16 09:18:50 -0400201 sk_sp<GrDirectContext> grContext(GrDirectContext::MakeGL(interface));
joshualitt04d52f32015-11-13 11:22:19 -0800202 SkASSERT(grContext);
203
204 // Wrap the frame buffer object attached to the screen in a Skia render target so Skia can
205 // render to it
joshualitt04d52f32015-11-13 11:22:19 -0800206 GrGLint buffer;
Jim Van Verth4c70c752017-07-11 12:03:01 -0400207 GR_GL_GetIntegerv(interface.get(), GR_GL_FRAMEBUFFER_BINDING, &buffer);
208 GrGLFramebufferInfo info;
209 info.fFBOID = (GrGLuint) buffer;
Greg Danielfaa095e2017-12-19 13:15:02 -0500210 SkColorType colorType;
211
Ben Wagnerf8a131d2018-03-13 16:56:43 -0400212 //SkDebugf("%s", SDL_GetPixelFormatName(windowFormat));
213 // TODO: the windowFormat is never any of these?
Greg Danielfaa095e2017-12-19 13:15:02 -0500214 if (SDL_PIXELFORMAT_RGBA8888 == windowFormat) {
215 info.fFormat = GR_GL_RGBA8;
216 colorType = kRGBA_8888_SkColorType;
217 } else {
Greg Danielfaa095e2017-12-19 13:15:02 -0500218 colorType = kBGRA_8888_SkColorType;
219 if (SDL_GL_CONTEXT_PROFILE_ES == contextType) {
220 info.fFormat = GR_GL_BGRA8;
221 } else {
222 // We assume the internal format is RGBA8 on desktop GL
223 info.fFormat = GR_GL_RGBA8;
224 }
225 }
226
227 GrBackendRenderTarget target(dw, dh, kMsaaSampleCount, kStencilBits, info);
joshualitt04d52f32015-11-13 11:22:19 -0800228
229 // setup SkSurface
230 // To use distance field text, use commented out SkSurfaceProps instead
231 // SkSurfaceProps props(SkSurfaceProps::kUseDeviceIndependentFonts_Flag,
232 // SkSurfaceProps::kLegacyFontHost_InitType);
233 SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
robertphillips12e96622016-08-01 05:53:23 -0700234
Jim Van Verth4c70c752017-07-11 12:03:01 -0400235 sk_sp<SkSurface> surface(SkSurface::MakeFromBackendRenderTarget(grContext.get(), target,
Greg Danielbcf612b2017-05-01 13:50:58 +0000236 kBottomLeft_GrSurfaceOrigin,
Greg Danielfaa095e2017-12-19 13:15:02 -0500237 colorType, nullptr, &props));
joshualitt04d52f32015-11-13 11:22:19 -0800238
239 SkCanvas* canvas = surface->getCanvas();
Jim Van Verth2259bd42017-09-01 14:49:09 -0400240 canvas->scale((float)dw/dm.w, (float)dh/dm.h);
joshualitt04d52f32015-11-13 11:22:19 -0800241
242 ApplicationState state;
243
244 const char* helpMessage = "Click and drag to create rects. Press esc to quit.";
245
246 SkPaint paint;
247
248 // create a surface for CPU rasterization
jvanverth1ba1d372016-08-04 12:30:31 -0700249 sk_sp<SkSurface> cpuSurface(SkSurface::MakeRaster(canvas->imageInfo()));
joshualitt04d52f32015-11-13 11:22:19 -0800250
251 SkCanvas* offscreen = cpuSurface->getCanvas();
252 offscreen->save();
253 offscreen->translate(50.0f, 50.0f);
254 offscreen->drawPath(create_star(), paint);
255 offscreen->restore();
256
jvanverth1ba1d372016-08-04 12:30:31 -0700257 sk_sp<SkImage> image = cpuSurface->makeImageSnapshot();
joshualitt04d52f32015-11-13 11:22:19 -0800258
259 int rotation = 0;
Hal Canarya70ae1a2019-01-08 15:04:23 -0500260 SkFont font;
joshualitt04d52f32015-11-13 11:22:19 -0800261 while (!state.fQuit) { // Our application loop
262 SkRandom rand;
263 canvas->clear(SK_ColorWHITE);
264 handle_events(&state, canvas);
265
266 paint.setColor(SK_ColorBLACK);
Hal Canarya70ae1a2019-01-08 15:04:23 -0500267 canvas->drawString(helpMessage, 100.0f, 100.0f, font, paint);
joshualitt04d52f32015-11-13 11:22:19 -0800268 for (int i = 0; i < state.fRects.count(); i++) {
269 paint.setColor(rand.nextU() | 0x44808080);
270 canvas->drawRect(state.fRects[i], paint);
271 }
272
273 // draw offscreen canvas
274 canvas->save();
275 canvas->translate(dm.w / 2.0, dm.h / 2.0);
276 canvas->rotate(rotation++);
277 canvas->drawImage(image, -50.0f, -50.0f);
278 canvas->restore();
279
280 canvas->flush();
281 SDL_GL_SwapWindow(window);
282 }
283
284 if (glContext) {
285 SDL_GL_DeleteContext(glContext);
286 }
287
288 //Destroy window
289 SDL_DestroyWindow(window);
290
291 //Quit SDL subsystems
292 SDL_Quit();
293 return 0;
294}