1 /*
2 * Copyright © 2018 NVIDIA Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 */
22
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <unistd.h>
28
29 #include "tegra.h"
30
31 #include "host1x.h"
32 #include "vic.h"
33
34 /* clear output image to red */
clear(struct vic * vic,struct drm_tegra_channel * channel,struct vic_image * output)35 static int clear(struct vic *vic, struct drm_tegra_channel *channel,
36 struct vic_image *output)
37 {
38 struct drm_tegra_pushbuf *pushbuf;
39 struct drm_tegra_job *job;
40 uint32_t *ptr;
41 int err;
42
43 err = drm_tegra_job_new(channel, &job);
44 if (err < 0) {
45 fprintf(stderr, "failed to create job: %s\n", strerror(-err));
46 return 1;
47 }
48
49 err = drm_tegra_job_get_pushbuf(job, &pushbuf);
50 if (err < 0) {
51 fprintf(stderr, "failed to create push buffer: %s\n", strerror(-err));
52 return 1;
53 }
54
55 err = vic_clear(vic, output, 1023, 1023, 0, 0);
56 if (err < 0) {
57 fprintf(stderr, "failed to clear surface: %s\n", strerror(-err));
58 return err;
59 }
60
61 err = drm_tegra_pushbuf_begin(pushbuf, 32, &ptr);
62 if (err < 0) {
63 fprintf(stderr, "failed to prepare push buffer: %s\n", strerror(-err));
64 return err;
65 }
66
67 err = vic->ops->execute(vic, pushbuf, &ptr, output, NULL, 0);
68 if (err < 0) {
69 fprintf(stderr, "failed to execute operation: %s\n", strerror(-err));
70 return err;
71 }
72
73 err = drm_tegra_pushbuf_sync_cond(pushbuf, &ptr, vic->syncpt,
74 DRM_TEGRA_SYNC_COND_OP_DONE);
75 if (err < 0) {
76 fprintf(stderr, "failed to push syncpoint: %s\n", strerror(-err));
77 return err;
78 }
79
80 err = drm_tegra_pushbuf_end(pushbuf, ptr);
81 if (err < 0) {
82 fprintf(stderr, "failed to update push buffer: %s\n", strerror(-err));
83 return err;
84 }
85
86 err = drm_tegra_job_submit(job, NULL);
87 if (err < 0) {
88 fprintf(stderr, "failed to submit job: %s\n", strerror(-err));
89 return err;
90 }
91
92 err = drm_tegra_job_wait(job, 1000000000);
93 if (err < 0) {
94 fprintf(stderr, "failed to wait for job: %s\n", strerror(-err));
95 return err;
96 }
97
98 drm_tegra_job_free(job);
99
100 return 0;
101 }
102
103 /* fill bottom half of image to blue */
fill(struct vic * vic,struct drm_tegra_channel * channel,struct vic_image * output)104 static int fill(struct vic *vic, struct drm_tegra_channel *channel,
105 struct vic_image *output)
106 {
107 struct drm_tegra_pushbuf *pushbuf;
108 struct drm_tegra_job *job;
109 uint32_t *ptr;
110 int err;
111
112 err = drm_tegra_job_new(channel, &job);
113 if (err < 0) {
114 fprintf(stderr, "failed to create job: %s\n", strerror(-err));
115 return 1;
116 }
117
118 err = drm_tegra_job_get_pushbuf(job, &pushbuf);
119 if (err < 0) {
120 fprintf(stderr, "failed to create push buffer: %s\n", strerror(-err));
121 return 1;
122 }
123
124 err = drm_tegra_pushbuf_begin(pushbuf, 32, &ptr);
125 if (err < 0) {
126 fprintf(stderr, "failed to prepare push buffer: %s\n", strerror(-err));
127 return err;
128 }
129
130 err = vic->ops->fill(vic, output, 0, output->height / 2, output->width - 1,
131 output->height -1, 1023, 0, 0, 1023);
132 if (err < 0) {
133 fprintf(stderr, "failed to fill surface: %s\n", strerror(-err));
134 return err;
135 }
136
137 err = vic->ops->execute(vic, pushbuf, &ptr, output, NULL, 0);
138 if (err < 0) {
139 fprintf(stderr, "failed to execute operation: %s\n", strerror(-err));
140 return err;
141 }
142
143 err = drm_tegra_pushbuf_sync_cond(pushbuf, &ptr, vic->syncpt,
144 DRM_TEGRA_SYNC_COND_OP_DONE);
145 if (err < 0) {
146 fprintf(stderr, "failed to push syncpoint: %s\n", strerror(-err));
147 return err;
148 }
149
150 err = drm_tegra_pushbuf_end(pushbuf, ptr);
151 if (err < 0) {
152 fprintf(stderr, "failed to update push buffer: %s\n", strerror(-err));
153 return err;
154 }
155
156 err = drm_tegra_job_submit(job, NULL);
157 if (err < 0) {
158 fprintf(stderr, "failed to submit job: %s\n", strerror(-err));
159 return err;
160 }
161
162 err = drm_tegra_job_wait(job, 1000000000);
163 if (err < 0) {
164 fprintf(stderr, "failed to wait for job: %s\n", strerror(-err));
165 return err;
166 }
167
168 drm_tegra_job_free(job);
169
170 return 0;
171 }
172
173 /* blit image */
blit(struct vic * vic,struct drm_tegra_channel * channel,struct vic_image * output,struct vic_image * input)174 static int blit(struct vic *vic, struct drm_tegra_channel *channel,
175 struct vic_image *output, struct vic_image *input)
176 {
177 struct drm_tegra_pushbuf *pushbuf;
178 struct drm_tegra_job *job;
179 uint32_t *ptr;
180 int err;
181
182 err = drm_tegra_job_new(channel, &job);
183 if (err < 0) {
184 fprintf(stderr, "failed to create job: %s\n", strerror(-err));
185 return 1;
186 }
187
188 err = drm_tegra_job_get_pushbuf(job, &pushbuf);
189 if (err < 0) {
190 fprintf(stderr, "failed to create push buffer: %s\n", strerror(-err));
191 return 1;
192 }
193
194 err = drm_tegra_pushbuf_begin(pushbuf, 32, &ptr);
195 if (err < 0) {
196 fprintf(stderr, "failed to prepare push buffer: %s\n", strerror(-err));
197 return err;
198 }
199
200 err = vic->ops->blit(vic, output, input);
201 if (err < 0) {
202 fprintf(stderr, "failed to blit surface: %s\n", strerror(-err));
203 return err;
204 }
205
206 err = vic->ops->execute(vic, pushbuf, &ptr, output, &input, 1);
207 if (err < 0) {
208 fprintf(stderr, "failed to execute operation: %s\n", strerror(-err));
209 return err;
210 }
211
212 err = drm_tegra_pushbuf_sync_cond(pushbuf, &ptr, vic->syncpt,
213 DRM_TEGRA_SYNC_COND_OP_DONE);
214 if (err < 0) {
215 fprintf(stderr, "failed to push syncpoint: %s\n", strerror(-err));
216 return err;
217 }
218
219 err = drm_tegra_pushbuf_end(pushbuf, ptr);
220 if (err < 0) {
221 fprintf(stderr, "failed to update push buffer: %s\n", strerror(-err));
222 return err;
223 }
224
225 err = drm_tegra_job_submit(job, NULL);
226 if (err < 0) {
227 fprintf(stderr, "failed to submit job: %s\n", strerror(-err));
228 return err;
229 }
230
231 err = drm_tegra_job_wait(job, 1000000000);
232 if (err < 0) {
233 fprintf(stderr, "failed to wait for job: %s\n", strerror(-err));
234 return err;
235 }
236
237 drm_tegra_job_free(job);
238
239 return 0;
240 }
241
main(int argc,char * argv[])242 int main(int argc, char *argv[])
243 {
244 const unsigned int format = VIC_PIXEL_FORMAT_A8R8G8B8;
245 const unsigned int kind = VIC_BLK_KIND_PITCH;
246 const unsigned int width = 16, height = 16;
247 const char *device = "/dev/dri/renderD128";
248 struct drm_tegra_channel *channel;
249 struct vic_image *input, *output;
250 struct drm_tegra *drm;
251 unsigned int version;
252 struct vic *vic;
253 int fd, err;
254
255 if (argc > 1)
256 device = argv[1];
257
258 fd = open(device, O_RDWR);
259 if (fd < 0) {
260 fprintf(stderr, "open() failed: %s\n", strerror(errno));
261 return 1;
262 }
263
264 err = drm_tegra_new(fd, &drm);
265 if (err < 0) {
266 fprintf(stderr, "failed to open Tegra device: %s\n", strerror(-err));
267 close(fd);
268 return 1;
269 }
270
271 err = drm_tegra_channel_open(drm, DRM_TEGRA_VIC, &channel);
272 if (err < 0) {
273 fprintf(stderr, "failed to open channel to VIC: %s\n", strerror(-err));
274 return 1;
275 }
276
277 version = drm_tegra_channel_get_version(channel);
278 printf("version: %08x\n", version);
279
280 err = vic_new(drm, channel, &vic);
281 if (err < 0) {
282 fprintf(stderr, "failed to create VIC: %s\n", strerror(-err));
283 return 1;
284 }
285
286 err = vic_image_new(vic, width, height, format, kind, DRM_TEGRA_CHANNEL_MAP_READ_WRITE,
287 &input);
288 if (err < 0) {
289 fprintf(stderr, "failed to create input image: %d\n", err);
290 return 1;
291 }
292
293 err = vic_image_new(vic, width, height, format, kind, DRM_TEGRA_CHANNEL_MAP_READ_WRITE,
294 &output);
295 if (err < 0) {
296 fprintf(stderr, "failed to create output image: %d\n", err);
297 return 1;
298 }
299
300 err = clear(vic, channel, input);
301 if (err < 0) {
302 fprintf(stderr, "failed to clear image: %s\n", strerror(-err));
303 return 1;
304 }
305
306 err = fill(vic, channel, input);
307 if (err < 0) {
308 fprintf(stderr, "failed to fill rectangle: %s\n", strerror(-err));
309 return 1;
310 }
311
312 err = blit(vic, channel, output, input);
313 if (err < 0) {
314 fprintf(stderr, "failed to blit image: %s\n", strerror(-err));
315 return 1;
316 }
317
318 printf("input: %ux%u\n", input->width, input->height);
319 vic_image_dump(input, stdout);
320
321 printf("output: %ux%u\n", output->width, output->height);
322 vic_image_dump(output, stdout);
323
324 vic_image_free(output);
325 vic_image_free(input);
326
327 vic_free(vic);
328 drm_tegra_channel_close(channel);
329 drm_tegra_close(drm);
330 close(fd);
331
332 return 0;
333 }
334