blob: b71bed2a88dae4bb7180e98e863389f4e639698c [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;
139 int intf_fd;
140 int err;
141
142 err = adf_find_simple_post_configuration(dev, &pdata->format, 1, &intf_id,
143 &pdata->eng_id);
144 if (err < 0)
145 return err;
146
147 err = adf_device_attach(dev, pdata->eng_id, intf_id);
148 if (err < 0 && err != -EALREADY)
149 return err;
150
151 pdata->intf_fd = adf_interface_open(dev, intf_id, O_RDWR);
152 if (pdata->intf_fd < 0)
153 return pdata->intf_fd;
154
155 err = adf_interface_init(pdata);
156 if (err < 0) {
157 close(pdata->intf_fd);
158 pdata->intf_fd = -1;
159 }
160
161 return err;
162}
163
164static GRSurface* adf_init(minui_backend *backend)
165{
166 adf_pdata *pdata = (adf_pdata *)backend;
167 adf_id_t *dev_ids = NULL;
168 ssize_t n_dev_ids, i;
169 GRSurface* ret;
170
171#if defined(RECOVERY_ABGR)
172 pdata->format = DRM_FORMAT_ABGR8888;
173 printf("setting DRM_FORMAT_ABGR8888 and GGL_PIXEL_FORMAT_BGRA_8888, GGL_PIXEL_FORMAT may not match!\n");
174#elif defined(RECOVERY_BGRA)
175 pdata->format = DRM_FORMAT_BGRA8888;
176 printf("setting DRM_FORMAT_BGRA8888 and GGL_PIXEL_FORMAT_BGRA_8888\n");
177#elif defined(RECOVERY_RGBA)
178 pdata->format = DRM_FORMAT_RGBA8888;
179 printf("setting DRM_FORMAT_RGBA8888 and GGL_PIXEL_FORMAT_RGBA_8888\n");
180#elif defined(RECOVERY_RGBX)
181 pdata->format = DRM_FORMAT_RGBX8888;
182 printf("setting DRM_FORMAT_RGBX8888 and GGL_PIXEL_FORMAT_RGBX_8888\n");
183#else
184 pdata->format = DRM_FORMAT_RGB565;
185 printf("setting DRM_FORMAT_RGB565 and GGL_PIXEL_FORMAT_RGB_565\n");
186#endif
187
188 n_dev_ids = adf_devices(&dev_ids);
189 if (n_dev_ids == 0) {
190 return NULL;
191 } else if (n_dev_ids < 0) {
192 fprintf(stderr, "enumerating adf devices failed: %s\n",
193 strerror(-n_dev_ids));
194 return NULL;
195 }
196
197 pdata->intf_fd = -1;
198
199 for (i = 0; i < n_dev_ids && pdata->intf_fd < 0; i++) {
200 adf_device dev;
201
202 int err = adf_device_open(dev_ids[i], O_RDWR, &dev);
203 if (err < 0) {
204 fprintf(stderr, "opening adf device %u failed: %s\n", dev_ids[i],
205 strerror(-err));
206 continue;
207 }
208
209 err = adf_device_init(pdata, &dev);
210 if (err < 0)
211 fprintf(stderr, "initializing adf device %u failed: %s\n",
212 dev_ids[i], strerror(-err));
213
214 adf_device_close(&dev);
215 }
216
217 free(dev_ids);
218
219 if (pdata->intf_fd < 0)
220 return NULL;
221
222 ret = adf_flip(backend);
223
224 adf_blank(backend, true);
225 adf_blank(backend, false);
226
227 return ret;
228}
229
230static GRSurface* adf_flip(minui_backend *backend)
231{
232 adf_pdata *pdata = (adf_pdata *)backend;
233 adf_surface_pdata *surf = &pdata->surfaces[pdata->current_surface];
234
235 memcpy(surf->adf_data, surf->base.data, surf->pitch * surf->base.height);
236 int fence_fd = adf_interface_simple_post(pdata->intf_fd, pdata->eng_id,
237 surf->base.width, surf->base.height, pdata->format, surf->fd,
238 surf->offset, surf->pitch, -1);
239 if (fence_fd >= 0)
240 close(fence_fd);
241
242 pdata->current_surface = (pdata->current_surface + 1) % pdata->n_surfaces;
243 return &pdata->surfaces[pdata->current_surface].base;
244}
245
246static void adf_blank(minui_backend *backend, bool blank)
247{
248 adf_pdata *pdata = (adf_pdata *)backend;
249 adf_interface_blank(pdata->intf_fd,
250 blank ? DRM_MODE_DPMS_OFF : DRM_MODE_DPMS_ON);
251}
252
253static void adf_surface_destroy(adf_surface_pdata *surf)
254{
255 munmap(surf->adf_data, surf->pitch * surf->base.height);
256 close(surf->fd);
257}
258
259static void adf_exit(minui_backend *backend)
260{
261 adf_pdata *pdata = (adf_pdata *)backend;
262 unsigned int i;
263
264 free(pdata->surfaces[0].base.data);
265 for (i = 0; i < pdata->n_surfaces; i++)
266 adf_surface_destroy(&pdata->surfaces[i]);
267 if (pdata->intf_fd >= 0)
268 close(pdata->intf_fd);
269 free(pdata);
270}
271
272minui_backend *open_adf()
273{
274 adf_pdata* pdata = reinterpret_cast<adf_pdata*>(calloc(1, sizeof(*pdata)));
275 if (!pdata) {
276 perror("allocating adf backend failed");
277 return NULL;
278 }
279
280 pdata->base.init = adf_init;
281 pdata->base.flip = adf_flip;
282 pdata->base.blank = adf_blank;
283 pdata->base.exit = adf_exit;
284 return &pdata->base;
285}