blob: 7b37271ec97cb310e9e91546ab9d36327d54289a [file] [log] [blame]
Ethan Yonkerfbb43532015-12-28 21:54:50 +01001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <errno.h>
18#include <fcntl.h>
19#include <stdbool.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <unistd.h>
24
25#include <sys/cdefs.h>
26#include <sys/mman.h>
27
28#include <adf/adf.h>
29
30#include "graphics.h"
31#include <pixelflinger/pixelflinger.h>
32
33struct adf_surface_pdata {
34 GRSurface base;
35 int fd;
36 __u32 offset;
37 __u32 pitch;
38 unsigned char* adf_data;
39};
40
41struct adf_pdata {
42 minui_backend base;
43 int intf_fd;
44 adf_id_t eng_id;
45 __u32 format;
46
47 unsigned int current_surface;
48 unsigned int n_surfaces;
49 adf_surface_pdata surfaces[2];
50};
51
52static GRSurface* adf_flip(minui_backend *backend);
53static void adf_blank(minui_backend *backend, bool blank);
54
55static int adf_surface_init(adf_pdata *pdata, drm_mode_modeinfo *mode, adf_surface_pdata *surf) {
56 memset(surf, 0, sizeof(*surf));
57
58 surf->fd = adf_interface_simple_buffer_alloc(pdata->intf_fd, mode->hdisplay,
59 mode->vdisplay, pdata->format, &surf->offset, &surf->pitch);
60 if (surf->fd < 0)
61 return surf->fd;
62
63 surf->base.width = mode->hdisplay;
64 surf->base.height = mode->vdisplay;
65 surf->base.row_bytes = surf->pitch;
66 surf->base.pixel_bytes = (pdata->format == DRM_FORMAT_RGB565) ? 2 : 4;
67 if (pdata->format == DRM_FORMAT_ABGR8888)
68 surf->base.format = GGL_PIXEL_FORMAT_BGRA_8888;
69 else if (pdata->format == DRM_FORMAT_BGRA8888)
70 surf->base.format = GGL_PIXEL_FORMAT_BGRA_8888;
71 else if (pdata->format == DRM_FORMAT_RGBA8888)
72 surf->base.format = GGL_PIXEL_FORMAT_RGBA_8888;
73 else if (pdata->format == DRM_FORMAT_RGBX8888)
74 surf->base.format = GGL_PIXEL_FORMAT_RGBX_8888;
75 else
76 surf->base.format = GGL_PIXEL_FORMAT_RGB_565;
77
78 surf->adf_data = reinterpret_cast<uint8_t*>(mmap(NULL,
79 surf->pitch * surf->base.height, PROT_WRITE,
80 MAP_SHARED, surf->fd, surf->offset));
81 if (surf->adf_data == MAP_FAILED) {
82 close(surf->fd);
83 return -errno;
84 }
85
86 return 0;
87}
88
89static int adf_interface_init(adf_pdata *pdata)
90{
91 adf_interface_data intf_data;
92 int ret = 0;
93 int err;
94 unsigned char* framebuffer_data = NULL;
95
96 err = adf_get_interface_data(pdata->intf_fd, &intf_data);
97 if (err < 0)
98 return err;
99
100 err = adf_surface_init(pdata, &intf_data.current_mode, &pdata->surfaces[0]);
101 if (err < 0) {
102 fprintf(stderr, "allocating surface 0 failed: %s\n", strerror(-err));
103 ret = err;
104 goto done;
105 }
106
107 /* Allocate a single buffer for drawing. graphics.cpp will draw to
108 * this buffer which will later be copied to the mmapped adf buffer.
109 * Using a regular memory buffer improves performance by about 10x. */
110 framebuffer_data = (unsigned char*)calloc(pdata->surfaces[0].pitch * pdata->surfaces[0].base.height, 1);
111 if (framebuffer_data == NULL) {
112 printf("failed to calloc surface data\n");
113 close(pdata->surfaces[0].fd);
114 munmap(pdata->surfaces[0].adf_data, pdata->surfaces[0].pitch * pdata->surfaces[0].base.height);
115 ret = -1;
116 goto done;
117 }
118 pdata->surfaces[0].base.data = framebuffer_data;
119
120 err = adf_surface_init(pdata, &intf_data.current_mode,
121 &pdata->surfaces[1]);
122 if (err < 0) {
123 fprintf(stderr, "allocating surface 1 failed: %s\n", strerror(-err));
124 memset(&pdata->surfaces[1], 0, sizeof(pdata->surfaces[1]));
125 pdata->n_surfaces = 1;
126 } else {
127 pdata->n_surfaces = 2;
128 pdata->surfaces[1].base.data = framebuffer_data;
129 }
130
131done:
132 adf_free_interface_data(&intf_data);
133 return ret;
134}
135
136static int adf_device_init(adf_pdata *pdata, adf_device *dev)
137{
138 adf_id_t intf_id;
Ethan Yonkerfbb43532015-12-28 21:54:50 +0100139 int err;
140
141 err = adf_find_simple_post_configuration(dev, &pdata->format, 1, &intf_id,
142 &pdata->eng_id);
143 if (err < 0)
144 return err;
145
146 err = adf_device_attach(dev, pdata->eng_id, intf_id);
147 if (err < 0 && err != -EALREADY)
148 return err;
149
150 pdata->intf_fd = adf_interface_open(dev, intf_id, O_RDWR);
151 if (pdata->intf_fd < 0)
152 return pdata->intf_fd;
153
154 err = adf_interface_init(pdata);
155 if (err < 0) {
156 close(pdata->intf_fd);
157 pdata->intf_fd = -1;
158 }
159
160 return err;
161}
162
163static GRSurface* adf_init(minui_backend *backend)
164{
165 adf_pdata *pdata = (adf_pdata *)backend;
166 adf_id_t *dev_ids = NULL;
167 ssize_t n_dev_ids, i;
168 GRSurface* ret;
169
170#if defined(RECOVERY_ABGR)
171 pdata->format = DRM_FORMAT_ABGR8888;
172 printf("setting DRM_FORMAT_ABGR8888 and GGL_PIXEL_FORMAT_BGRA_8888, GGL_PIXEL_FORMAT may not match!\n");
173#elif defined(RECOVERY_BGRA)
174 pdata->format = DRM_FORMAT_BGRA8888;
175 printf("setting DRM_FORMAT_BGRA8888 and GGL_PIXEL_FORMAT_BGRA_8888\n");
176#elif defined(RECOVERY_RGBA)
177 pdata->format = DRM_FORMAT_RGBA8888;
178 printf("setting DRM_FORMAT_RGBA8888 and GGL_PIXEL_FORMAT_RGBA_8888\n");
179#elif defined(RECOVERY_RGBX)
180 pdata->format = DRM_FORMAT_RGBX8888;
181 printf("setting DRM_FORMAT_RGBX8888 and GGL_PIXEL_FORMAT_RGBX_8888\n");
182#else
183 pdata->format = DRM_FORMAT_RGB565;
184 printf("setting DRM_FORMAT_RGB565 and GGL_PIXEL_FORMAT_RGB_565\n");
185#endif
186
187 n_dev_ids = adf_devices(&dev_ids);
188 if (n_dev_ids == 0) {
189 return NULL;
190 } else if (n_dev_ids < 0) {
191 fprintf(stderr, "enumerating adf devices failed: %s\n",
192 strerror(-n_dev_ids));
193 return NULL;
194 }
195
196 pdata->intf_fd = -1;
197
198 for (i = 0; i < n_dev_ids && pdata->intf_fd < 0; i++) {
199 adf_device dev;
200
201 int err = adf_device_open(dev_ids[i], O_RDWR, &dev);
202 if (err < 0) {
203 fprintf(stderr, "opening adf device %u failed: %s\n", dev_ids[i],
204 strerror(-err));
205 continue;
206 }
207
208 err = adf_device_init(pdata, &dev);
209 if (err < 0)
210 fprintf(stderr, "initializing adf device %u failed: %s\n",
211 dev_ids[i], strerror(-err));
212
213 adf_device_close(&dev);
214 }
215
216 free(dev_ids);
217
218 if (pdata->intf_fd < 0)
219 return NULL;
220
221 ret = adf_flip(backend);
222
223 adf_blank(backend, true);
224 adf_blank(backend, false);
225
226 return ret;
227}
228
229static GRSurface* adf_flip(minui_backend *backend)
230{
231 adf_pdata *pdata = (adf_pdata *)backend;
232 adf_surface_pdata *surf = &pdata->surfaces[pdata->current_surface];
233
234 memcpy(surf->adf_data, surf->base.data, surf->pitch * surf->base.height);
235 int fence_fd = adf_interface_simple_post(pdata->intf_fd, pdata->eng_id,
236 surf->base.width, surf->base.height, pdata->format, surf->fd,
237 surf->offset, surf->pitch, -1);
238 if (fence_fd >= 0)
239 close(fence_fd);
240
241 pdata->current_surface = (pdata->current_surface + 1) % pdata->n_surfaces;
242 return &pdata->surfaces[pdata->current_surface].base;
243}
244
245static void adf_blank(minui_backend *backend, bool blank)
246{
247 adf_pdata *pdata = (adf_pdata *)backend;
248 adf_interface_blank(pdata->intf_fd,
249 blank ? DRM_MODE_DPMS_OFF : DRM_MODE_DPMS_ON);
250}
251
252static void adf_surface_destroy(adf_surface_pdata *surf)
253{
254 munmap(surf->adf_data, surf->pitch * surf->base.height);
255 close(surf->fd);
256}
257
258static void adf_exit(minui_backend *backend)
259{
260 adf_pdata *pdata = (adf_pdata *)backend;
261 unsigned int i;
262
263 free(pdata->surfaces[0].base.data);
264 for (i = 0; i < pdata->n_surfaces; i++)
265 adf_surface_destroy(&pdata->surfaces[i]);
266 if (pdata->intf_fd >= 0)
267 close(pdata->intf_fd);
268 free(pdata);
269}
270
271minui_backend *open_adf()
272{
273 adf_pdata* pdata = reinterpret_cast<adf_pdata*>(calloc(1, sizeof(*pdata)));
274 if (!pdata) {
275 perror("allocating adf backend failed");
276 return NULL;
277 }
278
279 pdata->base.init = adf_init;
280 pdata->base.flip = adf_flip;
281 pdata->base.blank = adf_blank;
282 pdata->base.exit = adf_exit;
283 return &pdata->base;
284}