blob: 1356b2fa2b2e80b5fec469155d3e620c9633bf07 [file] [log] [blame]
Iliyan Malchev202a77d2012-06-11 14:41:12 -07001/*
2 * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
3
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution.
13 * * Neither the name of Code Aurora Forum, Inc. nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <cutils/log.h>
31#include <utils/RefBase.h>
32#include <fcntl.h>
33#include "gralloc_priv.h"
34#include "alloc_controller.h"
35#include "memalloc.h"
36#include "ionalloc.h"
Naseer Ahmed29a26812012-06-14 00:56:20 -070037#include "pmemalloc.h"
Iliyan Malchev202a77d2012-06-11 14:41:12 -070038#include "ashmemalloc.h"
39#include "gr.h"
Naseer Ahmed29a26812012-06-14 00:56:20 -070040#include "qcomutils/comptype.h"
Iliyan Malchev202a77d2012-06-11 14:41:12 -070041
42using namespace gralloc;
43using android::sp;
44
Naseer Ahmed29a26812012-06-14 00:56:20 -070045const int GRALLOC_HEAP_MASK = GRALLOC_USAGE_PRIVATE_ADSP_HEAP |
46 GRALLOC_USAGE_PRIVATE_UI_CONTIG_HEAP |
47 GRALLOC_USAGE_PRIVATE_SMI_HEAP |
48 GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP |
49 GRALLOC_USAGE_PRIVATE_IOMMU_HEAP |
50 GRALLOC_USAGE_PRIVATE_MM_HEAP |
51 GRALLOC_USAGE_PRIVATE_WRITEBACK_HEAP |
52 GRALLOC_USAGE_PRIVATE_CAMERA_HEAP;
Iliyan Malchev202a77d2012-06-11 14:41:12 -070053
54
55//Common functions
Naseer Ahmed29a26812012-06-14 00:56:20 -070056static bool canFallback(int usage, bool triedSystem)
Iliyan Malchev202a77d2012-06-11 14:41:12 -070057{
58 // Fallback to system heap when alloc fails unless
59 // 1. Composition type is MDP
60 // 2. Alloc from system heap was already tried
61 // 3. The heap type is requsted explicitly
62 // 4. The heap type is protected
63 // 5. The buffer is meant for external display only
64
Naseer Ahmed29a26812012-06-14 00:56:20 -070065 if(QCCompositionType::getInstance().getCompositionType() & COMPOSITION_TYPE_MDP)
Iliyan Malchev202a77d2012-06-11 14:41:12 -070066 return false;
67 if(triedSystem)
68 return false;
Naseer Ahmed29a26812012-06-14 00:56:20 -070069 if(usage & (GRALLOC_HEAP_MASK | GRALLOC_USAGE_PROTECTED |
70 GRALLOC_USAGE_PRIVATE_CP_BUFFER))
Iliyan Malchev202a77d2012-06-11 14:41:12 -070071 return false;
72 if(usage & (GRALLOC_HEAP_MASK | GRALLOC_USAGE_EXTERNAL_ONLY))
73 return false;
74 //Return true by default
75 return true;
76}
77
78static bool useUncached(int usage)
79{
80 // System heaps cannot be uncached
81 if(usage & (GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP |
82 GRALLOC_USAGE_PRIVATE_IOMMU_HEAP))
83 return false;
84 if (usage & GRALLOC_USAGE_PRIVATE_UNCACHED)
85 return true;
86 return false;
87}
88
89sp<IAllocController> IAllocController::sController = NULL;
90sp<IAllocController> IAllocController::getInstance(bool useMasterHeap)
91{
92 if(sController == NULL) {
93#ifdef USE_ION
94 sController = new IonController();
95#else
96 if(useMasterHeap)
97 sController = new PmemAshmemController();
98 else
99 sController = new PmemKernelController();
100#endif
101 }
102 return sController;
103}
104
105
106//-------------- IonController-----------------------//
107IonController::IonController()
108{
109 mIonAlloc = new IonAlloc();
110}
111
112int IonController::allocate(alloc_data& data, int usage,
Naseer Ahmed29a26812012-06-14 00:56:20 -0700113 int compositionType)
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700114{
115 int ionFlags = 0;
116 int ret;
117 bool noncontig = false;
118
119 data.uncached = useUncached(usage);
Naseer Ahmed29a26812012-06-14 00:56:20 -0700120 data.allocType = 0;
121
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700122 if(usage & GRALLOC_USAGE_PRIVATE_UI_CONTIG_HEAP)
123 ionFlags |= ION_HEAP(ION_SF_HEAP_ID);
124
125 if(usage & GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP) {
126 ionFlags |= ION_HEAP(ION_SYSTEM_HEAP_ID);
127 noncontig = true;
128 }
129
130 if(usage & GRALLOC_USAGE_PRIVATE_IOMMU_HEAP)
131 ionFlags |= ION_HEAP(ION_IOMMU_HEAP_ID);
132
133 if(usage & GRALLOC_USAGE_PRIVATE_MM_HEAP)
134 ionFlags |= ION_HEAP(ION_CP_MM_HEAP_ID);
135
136 if(usage & GRALLOC_USAGE_PRIVATE_WRITEBACK_HEAP)
137 ionFlags |= ION_HEAP(ION_CP_WB_HEAP_ID);
138
139 if(usage & GRALLOC_USAGE_PRIVATE_CAMERA_HEAP)
140 ionFlags |= ION_HEAP(ION_CAMERA_HEAP_ID);
141
Naseer Ahmed29a26812012-06-14 00:56:20 -0700142 if(usage & GRALLOC_USAGE_PRIVATE_CP_BUFFER)
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700143 ionFlags |= ION_SECURE;
144
145 if(usage & GRALLOC_USAGE_PRIVATE_DO_NOT_MAP)
Naseer Ahmed29a26812012-06-14 00:56:20 -0700146 data.allocType |= private_handle_t::PRIV_FLAGS_NOT_MAPPED;
147 else
148 data.allocType &= ~(private_handle_t::PRIV_FLAGS_NOT_MAPPED);
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700149
150 // if no flags are set, default to
151 // SF + IOMMU heaps, so that bypass can work
152 // we can fall back to system heap if
153 // we run out.
154 if(!ionFlags)
155 ionFlags = ION_HEAP(ION_SF_HEAP_ID) | ION_HEAP(ION_IOMMU_HEAP_ID);
156
157 data.flags = ionFlags;
158 ret = mIonAlloc->alloc_buffer(data);
Naseer Ahmed29a26812012-06-14 00:56:20 -0700159
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700160 // Fallback
Naseer Ahmed29a26812012-06-14 00:56:20 -0700161 if(ret < 0 && canFallback(usage,
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700162 (ionFlags & ION_SYSTEM_HEAP_ID)))
163 {
164 ALOGW("Falling back to system heap");
165 data.flags = ION_HEAP(ION_SYSTEM_HEAP_ID);
166 noncontig = true;
167 ret = mIonAlloc->alloc_buffer(data);
168 }
169
170 if(ret >= 0 ) {
Naseer Ahmed29a26812012-06-14 00:56:20 -0700171 data.allocType |= private_handle_t::PRIV_FLAGS_USES_ION;
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700172 if(noncontig)
173 data.allocType |= private_handle_t::PRIV_FLAGS_NONCONTIGUOUS_MEM;
174 if(ionFlags & ION_SECURE)
175 data.allocType |= private_handle_t::PRIV_FLAGS_SECURE_BUFFER;
176 }
177
178 return ret;
179}
180
181sp<IMemAlloc> IonController::getAllocator(int flags)
182{
183 sp<IMemAlloc> memalloc;
184 if (flags & private_handle_t::PRIV_FLAGS_USES_ION) {
185 memalloc = mIonAlloc;
186 } else {
187 ALOGE("%s: Invalid flags passed: 0x%x", __FUNCTION__, flags);
188 }
189
190 return memalloc;
191}
192
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700193//-------------- PmemKernelController-----------------------//
Naseer Ahmed29a26812012-06-14 00:56:20 -0700194//XXX: Remove - we're not using pmem anymore
195#if 0
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700196PmemKernelController::PmemKernelController()
197{
Naseer Ahmed29a26812012-06-14 00:56:20 -0700198 mPmemAdspAlloc = new PmemKernelAlloc(DEVICE_PMEM_ADSP);
199 // XXX: Right now, there is no need to maintain an instance
200 // of the SMI allocator as we need it only in a few cases
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700201}
202
203PmemKernelController::~PmemKernelController()
204{
205}
206
207int PmemKernelController::allocate(alloc_data& data, int usage,
Naseer Ahmed29a26812012-06-14 00:56:20 -0700208 int compositionType)
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700209{
210 int ret = 0;
211 bool adspFallback = false;
212 if (!(usage & GRALLOC_USAGE_PRIVATE_SMI_HEAP))
213 adspFallback = true;
214
215 // Try SMI first
216 if ((usage & GRALLOC_USAGE_PRIVATE_SMI_HEAP) ||
217 (usage & GRALLOC_USAGE_EXTERNAL_DISP) ||
218 (usage & GRALLOC_USAGE_PROTECTED))
219 {
220 int tempFd = open(DEVICE_PMEM_SMIPOOL, O_RDWR, 0);
221 if(tempFd > 0) {
222 close(tempFd);
223 sp<IMemAlloc> memalloc;
224 memalloc = new PmemKernelAlloc(DEVICE_PMEM_SMIPOOL);
225 ret = memalloc->alloc_buffer(data);
226 if(ret >= 0)
227 return ret;
228 else {
229 if(adspFallback)
230 ALOGW("Allocation from SMI failed, trying ADSP");
231 }
232 }
233 }
234
235 if ((usage & GRALLOC_USAGE_PRIVATE_ADSP_HEAP) || adspFallback) {
236 ret = mPmemAdspAlloc->alloc_buffer(data);
237 }
238 return ret;
239}
240
241sp<IMemAlloc> PmemKernelController::getAllocator(int flags)
242{
243 sp<IMemAlloc> memalloc;
244 if (flags & private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP)
245 memalloc = mPmemAdspAlloc;
246 else {
247 ALOGE("%s: Invalid flags passed: 0x%x", __FUNCTION__, flags);
248 memalloc = NULL;
249 }
250
251 return memalloc;
252}
253
254//-------------- PmemAshmmemController-----------------------//
255
256PmemAshmemController::PmemAshmemController()
257{
258 mPmemUserspaceAlloc = new PmemUserspaceAlloc();
259 mAshmemAlloc = new AshmemAlloc();
260 mPmemKernelCtrl = new PmemKernelController();
261}
262
263PmemAshmemController::~PmemAshmemController()
264{
265}
266
267int PmemAshmemController::allocate(alloc_data& data, int usage,
Naseer Ahmed29a26812012-06-14 00:56:20 -0700268 int compositionType)
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700269{
270 int ret = 0;
Naseer Ahmed29a26812012-06-14 00:56:20 -0700271 data.allocType = 0;
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700272
273 // Make buffers cacheable by default
Naseer Ahmed29a26812012-06-14 00:56:20 -0700274 data.uncached = false;
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700275
276 // Override if we explicitly need uncached buffers
277 if (usage & GRALLOC_USAGE_PRIVATE_UNCACHED)
278 data.uncached = true;
279
280 // If ADSP or SMI is requested use the kernel controller
281 if(usage & (GRALLOC_USAGE_PRIVATE_ADSP_HEAP|
282 GRALLOC_USAGE_PRIVATE_SMI_HEAP)) {
283 ret = mPmemKernelCtrl->allocate(data, usage, compositionType);
284 if(ret < 0)
285 ALOGE("%s: Failed to allocate ADSP/SMI memory", __func__);
286 else
287 data.allocType = private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP;
288 return ret;
289 }
290
291 if(usage & GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP) {
292 ret = mAshmemAlloc->alloc_buffer(data);
293 if(ret >= 0) {
294 data.allocType = private_handle_t::PRIV_FLAGS_USES_ASHMEM;
295 data.allocType |= private_handle_t::PRIV_FLAGS_NONCONTIGUOUS_MEM;
296 }
297 return ret;
298 }
299
300 // if no memory specific flags are set,
301 // default to EBI heap, so that bypass
302 // can work. We can fall back to system
303 // heap if we run out.
304 ret = mPmemUserspaceAlloc->alloc_buffer(data);
305
306 // Fallback
307 if(ret >= 0 ) {
308 data.allocType = private_handle_t::PRIV_FLAGS_USES_PMEM;
Naseer Ahmed29a26812012-06-14 00:56:20 -0700309 } else if(ret < 0 && canFallback(usage, false)) {
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700310 ALOGW("Falling back to ashmem");
311 ret = mAshmemAlloc->alloc_buffer(data);
312 if(ret >= 0) {
313 data.allocType = private_handle_t::PRIV_FLAGS_USES_ASHMEM;
314 data.allocType |= private_handle_t::PRIV_FLAGS_NONCONTIGUOUS_MEM;
315 }
316 }
317
318 return ret;
319}
320
321sp<IMemAlloc> PmemAshmemController::getAllocator(int flags)
322{
323 sp<IMemAlloc> memalloc;
324 if (flags & private_handle_t::PRIV_FLAGS_USES_PMEM)
325 memalloc = mPmemUserspaceAlloc;
326 else if (flags & private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP)
327 memalloc = mPmemKernelCtrl->getAllocator(flags);
328 else if (flags & private_handle_t::PRIV_FLAGS_USES_ASHMEM)
329 memalloc = mAshmemAlloc;
330 else {
331 ALOGE("%s: Invalid flags passed: 0x%x", __FUNCTION__, flags);
332 memalloc = NULL;
333 }
334
335 return memalloc;
336}
337#endif
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700338size_t getBufferSizeAndDimensions(int width, int height, int format,
Naseer Ahmed29a26812012-06-14 00:56:20 -0700339 int& alignedw, int &alignedh)
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700340{
341 size_t size;
342
343 alignedw = ALIGN(width, 32);
344 alignedh = ALIGN(height, 32);
345 switch (format) {
346 case HAL_PIXEL_FORMAT_RGBA_8888:
347 case HAL_PIXEL_FORMAT_RGBX_8888:
348 case HAL_PIXEL_FORMAT_BGRA_8888:
349 size = alignedw * alignedh * 4;
350 break;
351 case HAL_PIXEL_FORMAT_RGB_888:
352 size = alignedw * alignedh * 3;
353 break;
354 case HAL_PIXEL_FORMAT_RGB_565:
355 case HAL_PIXEL_FORMAT_RGBA_5551:
356 case HAL_PIXEL_FORMAT_RGBA_4444:
357 size = alignedw * alignedh * 2;
358 break;
359
360 // adreno formats
361 case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO: // NV21
362 size = ALIGN(alignedw*alignedh, 4096);
363 size += ALIGN(2 * ALIGN(width/2, 32) * ALIGN(height/2, 32), 4096);
364 break;
365 case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: // NV12
366 // The chroma plane is subsampled,
367 // but the pitch in bytes is unchanged
368 // The GPU needs 4K alignment, but the video decoder needs 8K
369 alignedw = ALIGN(width, 128);
370 size = ALIGN( alignedw * alignedh, 8192);
371 size += ALIGN( alignedw * ALIGN(height/2, 32), 8192);
372 break;
373 case HAL_PIXEL_FORMAT_NV12_ENCODEABLE:
374 case HAL_PIXEL_FORMAT_YCbCr_420_SP:
375 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
376 case HAL_PIXEL_FORMAT_YV12:
377 if ((format == HAL_PIXEL_FORMAT_YV12) && ((width&1) || (height&1))) {
378 ALOGE("w or h is odd for the YV12 format");
379 return -EINVAL;
380 }
381 alignedw = ALIGN(width, 16);
382 alignedh = height;
383 if (HAL_PIXEL_FORMAT_NV12_ENCODEABLE == format) {
384 // The encoder requires a 2K aligned chroma offset.
385 size = ALIGN(alignedw*alignedh, 2048) +
Naseer Ahmed29a26812012-06-14 00:56:20 -0700386 (ALIGN(alignedw/2, 16) * (alignedh/2))*2;
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700387 } else {
388 size = alignedw*alignedh +
389 (ALIGN(alignedw/2, 16) * (alignedh/2))*2;
390 }
391 size = ALIGN(size, 4096);
392 break;
Naseer Ahmed29a26812012-06-14 00:56:20 -0700393 case HAL_PIXEL_FORMAT_YCbCr_422_SP:
394 case HAL_PIXEL_FORMAT_YCrCb_422_SP:
395 if(width & 1) {
396 ALOGE("width is odd for the YUV422_SP format");
397 return -EINVAL;
398 }
399 alignedw = ALIGN(width, 16);
400 alignedh = height;
401 size = ALIGN(alignedw * alignedh * 2, 4096);
402 break;
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700403 default:
Naseer Ahmed29a26812012-06-14 00:56:20 -0700404 ALOGE("unrecognized pixel format: 0x%x", format);
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700405 return -EINVAL;
406 }
407
408 return size;
409}
410
411// Allocate buffer from width, height and format into a
412// private_handle_t. It is the responsibility of the caller
413// to free the buffer using the free_buffer function
414int alloc_buffer(private_handle_t **pHnd, int w, int h, int format, int usage)
415{
Naseer Ahmed29a26812012-06-14 00:56:20 -0700416 alloc_data data;
417 int alignedw, alignedh;
418 android::sp<gralloc::IAllocController> sAlloc =
419 gralloc::IAllocController::getInstance(false);
420 data.base = 0;
421 data.fd = -1;
422 data.offset = 0;
423 data.size = getBufferSizeAndDimensions(w, h, format, alignedw, alignedh);
424 data.align = getpagesize();
425 data.uncached = useUncached(usage);
426 int allocFlags = usage;
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700427
Naseer Ahmed29a26812012-06-14 00:56:20 -0700428 int err = sAlloc->allocate(data, allocFlags, 0);
429 if (0 != err) {
430 ALOGE("%s: allocate failed", __FUNCTION__);
431 return -ENOMEM;
432 }
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700433
Naseer Ahmed29a26812012-06-14 00:56:20 -0700434 private_handle_t* hnd = new private_handle_t(data.fd, data.size,
435 data.allocType, 0, format, alignedw, alignedh);
436 hnd->base = (int) data.base;
437 hnd->offset = data.offset;
438 hnd->gpuaddr = 0;
439 *pHnd = hnd;
440 return 0;
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700441}
442
443void free_buffer(private_handle_t *hnd)
444{
445 android::sp<gralloc::IAllocController> sAlloc =
446 gralloc::IAllocController::getInstance(false);
447 if (hnd && hnd->fd > 0) {
448 sp<IMemAlloc> memalloc = sAlloc->getAllocator(hnd->flags);
449 memalloc->free_buffer((void*)hnd->base, hnd->size, hnd->offset, hnd->fd);
450 }
451 if(hnd)
452 delete hnd;
453
454}