1 /*
2  * Copyright (C) 2016 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 #include <atomic>
17 #include <limits.h>
18 #include <unistd.h>
19 #include <fcntl.h>
20 #include <errno.h>
21 #include <pthread.h>
22 #include <stdlib.h>
23 #include <string.h>
24 
25 #include <sys/mman.h>
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 #include <sys/ioctl.h>
29 
30 #include <cutils/ashmem.h>
31 #include <log/log.h>
32 #include <cutils/atomic.h>
33 #include <utils/String8.h>
34 
35 #include <hardware/hardware.h>
36 #include <hardware/gralloc.h>
37 
38 #include "gralloc_vsoc_priv.h"
39 #include "region_registry.h"
40 
41 using cuttlefish::screen::ScreenRegionView;
42 
43 /*****************************************************************************/
44 
roundUpToPageSize(size_t x)45 static inline size_t roundUpToPageSize(size_t x) {
46   return (x + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1);
47 }
48 
gralloc_alloc_buffer(alloc_device_t *,int format,int w,int h,buffer_handle_t * pHandle,int * pStrideInPixels)49 static int gralloc_alloc_buffer(
50     alloc_device_t* /*dev*/, int format, int w, int h,
51     buffer_handle_t* pHandle, int* pStrideInPixels) {
52   int err = 0;
53   int fd = -1;
54   static std::atomic<int> sequence;
55 
56   int bytes_per_pixel = formatToBytesPerPixel(format);
57   int bytes_per_line;
58   int stride_in_pixels;
59   int size = 0;
60   // SwiftShader can't handle RGB_888, so fail fast and hard if we try to create
61   // a gralloc buffer in this format.
62   ALOG_ASSERT(format != HAL_PIXEL_FORMAT_RGB_888);
63   if (format == HAL_PIXEL_FORMAT_YV12) {
64     bytes_per_line = ScreenRegionView::align(bytes_per_pixel * w);
65   } else {
66     bytes_per_line = ScreenRegionView::align(bytes_per_pixel * w);
67   }
68   size = roundUpToPageSize(size + formatToBytesPerFrame(format, w, h));
69   size += PAGE_SIZE;
70   fd = ashmem_create_region(
71       android::String8::format(
72           "gralloc-%d.%d", getpid(), sequence++).string(),
73       size);
74   if (fd < 0) {
75     ALOGE("couldn't create ashmem (%s)", strerror(-errno));
76     err = -errno;
77   }
78 
79   if (err == 0) {
80     stride_in_pixels = bytes_per_line / bytes_per_pixel;
81     private_handle_t* hnd =
82         new private_handle_t(fd, size, format, w, h, stride_in_pixels, 0);
83     void* base = reference_region(__FUNCTION__, hnd);
84     if (base) {
85       *pHandle = hnd;
86       *pStrideInPixels = stride_in_pixels;
87     } else {
88       err = -EIO;
89     }
90   }
91 
92   ALOGE_IF(err, "gralloc failed err=%s", strerror(-err));
93 
94   return err;
95 }
96 
97 /*****************************************************************************/
98 
gralloc_alloc(alloc_device_t * dev,int w,int h,int format,int,buffer_handle_t * pHandle,int * pStrideInPixels)99 static int gralloc_alloc(alloc_device_t* dev, int w, int h, int format,
100                          int /*usage*/, buffer_handle_t* pHandle,
101                          int* pStrideInPixels) {
102   if (!pHandle || !pStrideInPixels)
103     return -EINVAL;
104 
105   int err = gralloc_alloc_buffer(dev, format, w, h, pHandle, pStrideInPixels);
106 
107   if (err < 0) {
108     return err;
109   }
110   return 0;
111 }
112 
gralloc_free(alloc_device_t *,buffer_handle_t handle)113 static int gralloc_free(alloc_device_t* /*dev*/, buffer_handle_t handle) {
114   if (private_handle_t::validate(handle) < 0) {
115     return -EINVAL;
116   }
117 
118   private_handle_t const* hnd = reinterpret_cast<private_handle_t const*>(
119     handle);
120   int retval = unreference_region(__FUNCTION__, hnd);
121 
122   close(hnd->fd);
123   delete hnd;
124   return retval;
125 }
126 
127 /*****************************************************************************/
128 
gralloc_close(struct hw_device_t * dev)129 static int gralloc_close(struct hw_device_t *dev) {
130   priv_alloc_device_t* ctx = reinterpret_cast<priv_alloc_device_t*>(dev);
131   if (ctx) {
132     /* TODO: keep a list of all buffer_handle_t created, and free them
133      * all here.
134      */
135     free(ctx);
136   }
137   return 0;
138 }
139 
gralloc_device_open(const hw_module_t * module,const char * name,hw_device_t ** device)140 static int gralloc_device_open(
141     const hw_module_t* module, const char* name, hw_device_t** device) {
142   int status = -EINVAL;
143   if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) {
144     priv_alloc_device_t *dev;
145     dev = (priv_alloc_device_t*) malloc(sizeof(*dev));
146     LOG_FATAL_IF(!dev, "%s: malloc returned NULL.", __FUNCTION__);
147 
148     /* initialize our state here */
149     memset(dev, 0, sizeof(*dev));
150 
151     /* initialize the procs */
152     dev->device.common.tag = HARDWARE_DEVICE_TAG;
153     dev->device.common.version = 0;
154     dev->device.common.module = const_cast<hw_module_t*>(module);
155     dev->device.common.close = gralloc_close;
156 
157     dev->device.alloc   = gralloc_alloc;
158     dev->device.free    = gralloc_free;
159 
160     *device = &dev->device.common;
161     status = 0;
162   } else {
163     ALOGE("Need to create framebuffer, but it is unsupported");
164   }
165   return status;
166 }
167 
168 /*****************************************************************************/
169 
170 static struct hw_module_methods_t gralloc_module_methods = {
171   .open = gralloc_device_open
172 };
173 
174 struct private_module_t HAL_MODULE_INFO_SYM = {
175   .base = {
176     .common = {
177       .tag = HARDWARE_MODULE_TAG,
178 #ifdef GRALLOC_MODULE_API_VERSION_0_2
179       .version_major = GRALLOC_MODULE_API_VERSION_0_2,
180 #else
181       .version_major = 1,
182 #endif
183       .version_minor = 0,
184       .id = GRALLOC_HARDWARE_MODULE_ID,
185       .name = "VSOC X86 Graphics Memory Allocator Module",
186       .author = "The Android Open Source Project",
187       .methods = &gralloc_module_methods,
188       .dso = NULL,
189       .reserved = {0},
190     },
191     .registerBuffer = gralloc_register_buffer,
192     .unregisterBuffer = gralloc_unregister_buffer,
193     .lock = gralloc_lock,
194     .unlock = gralloc_unlock,
195 #ifdef GRALLOC_MODULE_API_VERSION_0_2
196     .perform = NULL,
197     .lock_ycbcr = gralloc_lock_ycbcr,
198 #endif
199     .getTransportSize = gralloc_get_transport_size,
200     .validateBufferSize = gralloc_validate_buffer_size,
201   },
202 };
203