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