gralloc: add BOARD_USES_LEGACY_QCOM
Change-Id: I7fae5cf67ed4a1f00012c64c384bb621ab8bb183
This commit is contained in:
parent
0cba1f7659
commit
bd4bfd035d
@ -1,7 +1,11 @@
|
||||
#Enables the listed display HAL modules
|
||||
|
||||
ifeq ($(BOARD_USES_QCOM_HARDWARE),true)
|
||||
ifeq ($(BOARD_USES_LEGACY_QCOM),true)
|
||||
display-hals := libgralloc-legacy libcopybit
|
||||
else
|
||||
display-hals := libhwcomposer liboverlay libgralloc libcopybit libgenlock libtilerenderer
|
||||
display-hals += libqcomui
|
||||
endif
|
||||
include $(call all-named-subdir-makefiles,$(display-hals))
|
||||
endif
|
||||
|
49
libgralloc-legacy/Android.mk
Normal file
49
libgralloc-legacy/Android.mk
Normal file
@ -0,0 +1,49 @@
|
||||
# Copyright (C) 2008 The Android Open Source Project
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
# HAL module implemenation stored in
|
||||
# hw/<OVERLAY_HARDWARE_MODULE_ID>.<ro.product.board>.so
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
|
||||
LOCAL_SHARED_LIBRARIES := liblog libcutils libGLESv1_CM
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
allocator.cpp \
|
||||
framebuffer.cpp \
|
||||
gpu.cpp \
|
||||
gralloc.cpp \
|
||||
mapper.cpp \
|
||||
pmemalloc.cpp
|
||||
|
||||
LOCAL_MODULE := gralloc.$(TARGET_BOARD_PLATFORM)
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_CFLAGS:= -DLOG_TAG=\"$(TARGET_BOARD_PLATFORM).gralloc\"
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
# Build a host library for testing
|
||||
ifeq ($(HOST_OS),linux)
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_SRC_FILES := \
|
||||
gpu.cpp \
|
||||
pmemalloc.cpp
|
||||
|
||||
LOCAL_MODULE_TAGS := tests
|
||||
LOCAL_MODULE := libgralloc_qsd8k_host
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_CFLAGS:= -DLOG_TAG=\"gralloc-qsd8k\"
|
||||
include $(BUILD_HOST_STATIC_LIBRARY)
|
||||
endif
|
0
libgralloc-legacy/MODULE_LICENSE_APACHE2
Normal file
0
libgralloc-legacy/MODULE_LICENSE_APACHE2
Normal file
190
libgralloc-legacy/NOTICE
Normal file
190
libgralloc-legacy/NOTICE
Normal file
@ -0,0 +1,190 @@
|
||||
|
||||
Copyright (c) 2008-2009, The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
165
libgralloc-legacy/allocator.cpp
Normal file
165
libgralloc-legacy/allocator.cpp
Normal file
@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <cutils/log.h>
|
||||
|
||||
#include "allocator.h"
|
||||
|
||||
|
||||
// align all the memory blocks on a cache-line boundary
|
||||
const int SimpleBestFitAllocator::kMemoryAlign = 32;
|
||||
|
||||
SimpleBestFitAllocator::SimpleBestFitAllocator()
|
||||
: mHeapSize(0)
|
||||
{
|
||||
}
|
||||
|
||||
SimpleBestFitAllocator::SimpleBestFitAllocator(size_t size)
|
||||
: mHeapSize(0)
|
||||
{
|
||||
setSize(size);
|
||||
}
|
||||
|
||||
SimpleBestFitAllocator::~SimpleBestFitAllocator()
|
||||
{
|
||||
while(!mList.isEmpty()) {
|
||||
delete mList.remove(mList.head());
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t SimpleBestFitAllocator::setSize(size_t size)
|
||||
{
|
||||
Locker::Autolock _l(mLock);
|
||||
if (mHeapSize != 0) return -EINVAL;
|
||||
size_t pagesize = getpagesize();
|
||||
mHeapSize = ((size + pagesize-1) & ~(pagesize-1));
|
||||
chunk_t* node = new chunk_t(0, mHeapSize / kMemoryAlign);
|
||||
mList.insertHead(node);
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
size_t SimpleBestFitAllocator::size() const
|
||||
{
|
||||
return mHeapSize;
|
||||
}
|
||||
|
||||
ssize_t SimpleBestFitAllocator::allocate(size_t size, uint32_t flags)
|
||||
{
|
||||
Locker::Autolock _l(mLock);
|
||||
if (mHeapSize == 0) return -EINVAL;
|
||||
ssize_t offset = alloc(size, flags);
|
||||
return offset;
|
||||
}
|
||||
|
||||
ssize_t SimpleBestFitAllocator::deallocate(size_t offset)
|
||||
{
|
||||
Locker::Autolock _l(mLock);
|
||||
if (mHeapSize == 0) return -EINVAL;
|
||||
chunk_t const * const freed = dealloc(offset);
|
||||
if (freed) {
|
||||
return 0;
|
||||
}
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
ssize_t SimpleBestFitAllocator::alloc(size_t size, uint32_t flags)
|
||||
{
|
||||
if (size == 0) {
|
||||
return 0;
|
||||
}
|
||||
size = (size + kMemoryAlign-1) / kMemoryAlign;
|
||||
chunk_t* free_chunk = 0;
|
||||
chunk_t* cur = mList.head();
|
||||
|
||||
size_t pagesize = getpagesize();
|
||||
while (cur) {
|
||||
int extra = ( -cur->start & ((pagesize/kMemoryAlign)-1) ) ;
|
||||
|
||||
// best fit
|
||||
if (cur->free && (cur->size >= (size+extra))) {
|
||||
if ((!free_chunk) || (cur->size < free_chunk->size)) {
|
||||
free_chunk = cur;
|
||||
}
|
||||
if (cur->size == size) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
if (free_chunk) {
|
||||
const size_t free_size = free_chunk->size;
|
||||
free_chunk->free = 0;
|
||||
free_chunk->size = size;
|
||||
if (free_size > size) {
|
||||
int extra = ( -free_chunk->start & ((pagesize/kMemoryAlign)-1) ) ;
|
||||
if (extra) {
|
||||
chunk_t* split = new chunk_t(free_chunk->start, extra);
|
||||
free_chunk->start += extra;
|
||||
mList.insertBefore(free_chunk, split);
|
||||
}
|
||||
|
||||
LOGE_IF(((free_chunk->start*kMemoryAlign)&(pagesize-1)),
|
||||
"page is not aligned!!!");
|
||||
|
||||
const ssize_t tail_free = free_size - (size+extra);
|
||||
if (tail_free > 0) {
|
||||
chunk_t* split = new chunk_t(
|
||||
free_chunk->start + free_chunk->size, tail_free);
|
||||
mList.insertAfter(free_chunk, split);
|
||||
}
|
||||
}
|
||||
return (free_chunk->start)*kMemoryAlign;
|
||||
}
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
SimpleBestFitAllocator::chunk_t* SimpleBestFitAllocator::dealloc(size_t start)
|
||||
{
|
||||
start = start / kMemoryAlign;
|
||||
chunk_t* cur = mList.head();
|
||||
while (cur) {
|
||||
if (cur->start == start) {
|
||||
LOG_FATAL_IF(cur->free,
|
||||
"block at offset 0x%08lX of size 0x%08lX already freed",
|
||||
cur->start*kMemoryAlign, cur->size*kMemoryAlign);
|
||||
|
||||
// merge freed blocks together
|
||||
chunk_t* freed = cur;
|
||||
cur->free = 1;
|
||||
do {
|
||||
chunk_t* const p = cur->prev;
|
||||
chunk_t* const n = cur->next;
|
||||
if (p && (p->free || !cur->size)) {
|
||||
freed = p;
|
||||
p->size += cur->size;
|
||||
mList.remove(cur);
|
||||
delete cur;
|
||||
}
|
||||
cur = n;
|
||||
} while (cur && cur->free);
|
||||
|
||||
LOG_FATAL_IF(!freed->free,
|
||||
"freed block at offset 0x%08lX of size 0x%08lX is not free!",
|
||||
freed->start * kMemoryAlign, freed->size * kMemoryAlign);
|
||||
|
||||
return freed;
|
||||
}
|
||||
cur = cur->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
130
libgralloc-legacy/allocator.h
Normal file
130
libgralloc-legacy/allocator.h
Normal file
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef GRALLOC_ALLOCATOR_H_
|
||||
#define GRALLOC_ALLOCATOR_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "gr.h"
|
||||
#include "pmemalloc.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* A simple templatized doubly linked-list implementation
|
||||
*/
|
||||
|
||||
template <typename NODE>
|
||||
class LinkedList
|
||||
{
|
||||
NODE* mFirst;
|
||||
NODE* mLast;
|
||||
|
||||
public:
|
||||
LinkedList() : mFirst(0), mLast(0) { }
|
||||
bool isEmpty() const { return mFirst == 0; }
|
||||
NODE const* head() const { return mFirst; }
|
||||
NODE* head() { return mFirst; }
|
||||
NODE const* tail() const { return mLast; }
|
||||
NODE* tail() { return mLast; }
|
||||
|
||||
void insertAfter(NODE* node, NODE* newNode) {
|
||||
newNode->prev = node;
|
||||
newNode->next = node->next;
|
||||
if (node->next == 0) mLast = newNode;
|
||||
else node->next->prev = newNode;
|
||||
node->next = newNode;
|
||||
}
|
||||
|
||||
void insertBefore(NODE* node, NODE* newNode) {
|
||||
newNode->prev = node->prev;
|
||||
newNode->next = node;
|
||||
if (node->prev == 0) mFirst = newNode;
|
||||
else node->prev->next = newNode;
|
||||
node->prev = newNode;
|
||||
}
|
||||
|
||||
void insertHead(NODE* newNode) {
|
||||
if (mFirst == 0) {
|
||||
mFirst = mLast = newNode;
|
||||
newNode->prev = newNode->next = 0;
|
||||
} else {
|
||||
newNode->prev = 0;
|
||||
newNode->next = mFirst;
|
||||
mFirst->prev = newNode;
|
||||
mFirst = newNode;
|
||||
}
|
||||
}
|
||||
|
||||
void insertTail(NODE* newNode) {
|
||||
if (mLast == 0) {
|
||||
insertHead(newNode);
|
||||
} else {
|
||||
newNode->prev = mLast;
|
||||
newNode->next = 0;
|
||||
mLast->next = newNode;
|
||||
mLast = newNode;
|
||||
}
|
||||
}
|
||||
|
||||
NODE* remove(NODE* node) {
|
||||
if (node->prev == 0) mFirst = node->next;
|
||||
else node->prev->next = node->next;
|
||||
if (node->next == 0) mLast = node->prev;
|
||||
else node->next->prev = node->prev;
|
||||
return node;
|
||||
}
|
||||
};
|
||||
|
||||
class SimpleBestFitAllocator : public PmemUserspaceAllocator::Deps::Allocator
|
||||
{
|
||||
public:
|
||||
|
||||
SimpleBestFitAllocator();
|
||||
SimpleBestFitAllocator(size_t size);
|
||||
virtual ~SimpleBestFitAllocator();
|
||||
|
||||
virtual ssize_t setSize(size_t size);
|
||||
|
||||
virtual ssize_t allocate(size_t size, uint32_t flags = 0);
|
||||
virtual ssize_t deallocate(size_t offset);
|
||||
virtual size_t size() const;
|
||||
|
||||
private:
|
||||
struct chunk_t {
|
||||
chunk_t(size_t start, size_t size)
|
||||
: start(start), size(size), free(1), prev(0), next(0) {
|
||||
}
|
||||
size_t start;
|
||||
size_t size : 28;
|
||||
int free : 4;
|
||||
mutable chunk_t* prev;
|
||||
mutable chunk_t* next;
|
||||
};
|
||||
|
||||
ssize_t alloc(size_t size, uint32_t flags);
|
||||
chunk_t* dealloc(size_t start);
|
||||
|
||||
static const int kMemoryAlign;
|
||||
mutable Locker mLock;
|
||||
LinkedList<chunk_t> mList;
|
||||
size_t mHeapSize;
|
||||
};
|
||||
|
||||
#endif /* GRALLOC_ALLOCATOR_H_ */
|
457
libgralloc-legacy/framebuffer.cpp
Normal file
457
libgralloc-legacy/framebuffer.cpp
Normal file
@ -0,0 +1,457 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include <cutils/ashmem.h>
|
||||
#include <cutils/log.h>
|
||||
#include <cutils/properties.h>
|
||||
|
||||
#include <hardware/hardware.h>
|
||||
#include <hardware/gralloc.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <cutils/log.h>
|
||||
#include <cutils/atomic.h>
|
||||
|
||||
#include <linux/fb.h>
|
||||
#include <linux/msm_mdp.h>
|
||||
|
||||
#include <GLES/gl.h>
|
||||
|
||||
#include "gralloc_priv.h"
|
||||
#include "gr.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
// numbers of buffers for page flipping
|
||||
#define NUM_BUFFERS 2
|
||||
|
||||
|
||||
enum {
|
||||
PAGE_FLIP = 0x00000001,
|
||||
LOCKED = 0x00000002
|
||||
};
|
||||
|
||||
struct fb_context_t {
|
||||
framebuffer_device_t device;
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
msm_copy_buffer(buffer_handle_t handle, int fd,
|
||||
int width, int height, int format,
|
||||
int x, int y, int w, int h);
|
||||
|
||||
static int fb_setSwapInterval(struct framebuffer_device_t* dev,
|
||||
int interval)
|
||||
{
|
||||
fb_context_t* ctx = (fb_context_t*)dev;
|
||||
if (interval < dev->minSwapInterval || interval > dev->maxSwapInterval)
|
||||
return -EINVAL;
|
||||
// FIXME: implement fb_setSwapInterval
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fb_setUpdateRect(struct framebuffer_device_t* dev,
|
||||
int l, int t, int w, int h)
|
||||
{
|
||||
if (((w|h) <= 0) || ((l|t)<0))
|
||||
return -EINVAL;
|
||||
|
||||
fb_context_t* ctx = (fb_context_t*)dev;
|
||||
private_module_t* m = reinterpret_cast<private_module_t*>(
|
||||
dev->common.module);
|
||||
m->info.reserved[0] = 0x54445055; // "UPDT";
|
||||
m->info.reserved[1] = (uint16_t)l | ((uint32_t)t << 16);
|
||||
m->info.reserved[2] = (uint16_t)(l+w) | ((uint32_t)(t+h) << 16);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer)
|
||||
{
|
||||
if (private_handle_t::validate(buffer) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
fb_context_t* ctx = (fb_context_t*)dev;
|
||||
|
||||
private_handle_t const* hnd = reinterpret_cast<private_handle_t const*>(buffer);
|
||||
private_module_t* m = reinterpret_cast<private_module_t*>(
|
||||
dev->common.module);
|
||||
|
||||
if (m->currentBuffer) {
|
||||
m->base.unlock(&m->base, m->currentBuffer);
|
||||
m->currentBuffer = 0;
|
||||
}
|
||||
|
||||
if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) {
|
||||
|
||||
m->base.lock(&m->base, buffer,
|
||||
private_module_t::PRIV_USAGE_LOCKED_FOR_POST,
|
||||
0, 0, m->info.xres, m->info.yres, NULL);
|
||||
|
||||
const size_t offset = hnd->base - m->framebuffer->base;
|
||||
m->info.activate = FB_ACTIVATE_VBL;
|
||||
m->info.yoffset = offset / m->finfo.line_length;
|
||||
if (ioctl(m->framebuffer->fd, FBIOPUT_VSCREENINFO, &m->info) == -1) {
|
||||
LOGE("FBIOPUT_VSCREENINFO failed");
|
||||
m->base.unlock(&m->base, buffer);
|
||||
return -errno;
|
||||
}
|
||||
m->currentBuffer = buffer;
|
||||
|
||||
} else {
|
||||
void* fb_vaddr;
|
||||
void* buffer_vaddr;
|
||||
|
||||
m->base.lock(&m->base, m->framebuffer,
|
||||
GRALLOC_USAGE_SW_WRITE_RARELY,
|
||||
0, 0, m->info.xres, m->info.yres,
|
||||
&fb_vaddr);
|
||||
|
||||
m->base.lock(&m->base, buffer,
|
||||
GRALLOC_USAGE_SW_READ_RARELY,
|
||||
0, 0, m->info.xres, m->info.yres,
|
||||
&buffer_vaddr);
|
||||
|
||||
//memcpy(fb_vaddr, buffer_vaddr, m->finfo.line_length * m->info.yres);
|
||||
|
||||
msm_copy_buffer(
|
||||
m->framebuffer, m->framebuffer->fd,
|
||||
m->info.xres, m->info.yres, m->fbFormat,
|
||||
m->info.xoffset, m->info.yoffset,
|
||||
m->info.width, m->info.height);
|
||||
|
||||
m->base.unlock(&m->base, buffer);
|
||||
m->base.unlock(&m->base, m->framebuffer);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fb_compositionComplete(struct framebuffer_device_t* dev)
|
||||
{
|
||||
// TODO: Properly implement composition complete callback
|
||||
glFinish();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int mapFrameBufferLocked(struct private_module_t* module)
|
||||
{
|
||||
// already initialized...
|
||||
if (module->framebuffer) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
char const * const device_template[] = {
|
||||
"/dev/graphics/fb%u",
|
||||
"/dev/fb%u",
|
||||
0 };
|
||||
|
||||
int fd = -1;
|
||||
int i=0;
|
||||
char name[64];
|
||||
|
||||
while ((fd==-1) && device_template[i]) {
|
||||
snprintf(name, 64, device_template[i], 0);
|
||||
fd = open(name, O_RDWR, 0);
|
||||
i++;
|
||||
}
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
struct fb_fix_screeninfo finfo;
|
||||
if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
|
||||
return -errno;
|
||||
|
||||
struct fb_var_screeninfo info;
|
||||
if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
|
||||
return -errno;
|
||||
|
||||
info.reserved[0] = 0;
|
||||
info.reserved[1] = 0;
|
||||
info.reserved[2] = 0;
|
||||
info.xoffset = 0;
|
||||
info.yoffset = 0;
|
||||
info.activate = FB_ACTIVATE_NOW;
|
||||
|
||||
/* Interpretation of offset for color fields: All offsets are from the right,
|
||||
* inside a "pixel" value, which is exactly 'bits_per_pixel' wide (means: you
|
||||
* can use the offset as right argument to <<). A pixel afterwards is a bit
|
||||
* stream and is written to video memory as that unmodified. This implies
|
||||
* big-endian byte order if bits_per_pixel is greater than 8.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Explicitly request RGBA_8888
|
||||
*/
|
||||
info.bits_per_pixel = 32;
|
||||
info.red.offset = 24;
|
||||
info.red.length = 8;
|
||||
info.green.offset = 16;
|
||||
info.green.length = 8;
|
||||
info.blue.offset = 8;
|
||||
info.blue.length = 8;
|
||||
info.transp.offset = 0;
|
||||
info.transp.length = 0;
|
||||
|
||||
/* Note: the GL driver does not have a r=8 g=8 b=8 a=0 config, so if we do
|
||||
* not use the MDP for composition (i.e. hw composition == 0), ask for
|
||||
* RGBA instead of RGBX. */
|
||||
char property[PROPERTY_VALUE_MAX];
|
||||
if (property_get("debug.sf.hw", property, NULL) > 0 && atoi(property) == 0)
|
||||
module->fbFormat = HAL_PIXEL_FORMAT_RGBX_8888;
|
||||
else
|
||||
module->fbFormat = HAL_PIXEL_FORMAT_RGBA_8888;
|
||||
|
||||
/*
|
||||
* Request NUM_BUFFERS screens (at lest 2 for page flipping)
|
||||
*/
|
||||
info.yres_virtual = info.yres * NUM_BUFFERS;
|
||||
|
||||
|
||||
uint32_t flags = PAGE_FLIP;
|
||||
if (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1) {
|
||||
info.yres_virtual = info.yres;
|
||||
flags &= ~PAGE_FLIP;
|
||||
LOGW("FBIOPUT_VSCREENINFO failed, page flipping not supported");
|
||||
}
|
||||
|
||||
if (info.yres_virtual < info.yres * 2) {
|
||||
// we need at least 2 for page-flipping
|
||||
info.yres_virtual = info.yres;
|
||||
flags &= ~PAGE_FLIP;
|
||||
LOGW("page flipping not supported (yres_virtual=%d, requested=%d)",
|
||||
info.yres_virtual, info.yres*2);
|
||||
}
|
||||
|
||||
if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
|
||||
return -errno;
|
||||
|
||||
uint64_t refreshQuotient =
|
||||
(
|
||||
uint64_t( info.upper_margin + info.lower_margin + info.yres )
|
||||
* ( info.left_margin + info.right_margin + info.xres )
|
||||
* info.pixclock
|
||||
);
|
||||
|
||||
/* Beware, info.pixclock might be 0 under emulation, so avoid a
|
||||
* division-by-0 here (SIGFPE on ARM) */
|
||||
int refreshRate = refreshQuotient > 0 ? (int)(1000000000000000LLU / refreshQuotient) : 0;
|
||||
|
||||
if (refreshRate == 0) {
|
||||
// bleagh, bad info from the driver
|
||||
refreshRate = 60*1000; // 60 Hz
|
||||
}
|
||||
|
||||
if (int(info.width) <= 0 || int(info.height) <= 0) {
|
||||
// the driver doesn't return that information
|
||||
// default to 160 dpi
|
||||
info.width = ((info.xres * 25.4f)/160.0f + 0.5f);
|
||||
info.height = ((info.yres * 25.4f)/160.0f + 0.5f);
|
||||
}
|
||||
|
||||
float xdpi = (info.xres * 25.4f) / info.width;
|
||||
float ydpi = (info.yres * 25.4f) / info.height;
|
||||
float fps = refreshRate / 1000.0f;
|
||||
|
||||
LOGI( "using (fd=%d)\n"
|
||||
"id = %s\n"
|
||||
"xres = %d px\n"
|
||||
"yres = %d px\n"
|
||||
"xres_virtual = %d px\n"
|
||||
"yres_virtual = %d px\n"
|
||||
"bpp = %d\n"
|
||||
"r = %2u:%u\n"
|
||||
"g = %2u:%u\n"
|
||||
"b = %2u:%u\n",
|
||||
fd,
|
||||
finfo.id,
|
||||
info.xres,
|
||||
info.yres,
|
||||
info.xres_virtual,
|
||||
info.yres_virtual,
|
||||
info.bits_per_pixel,
|
||||
info.red.offset, info.red.length,
|
||||
info.green.offset, info.green.length,
|
||||
info.blue.offset, info.blue.length
|
||||
);
|
||||
|
||||
LOGI( "width = %d mm (%f dpi)\n"
|
||||
"height = %d mm (%f dpi)\n"
|
||||
"refresh rate = %.2f Hz\n",
|
||||
info.width, xdpi,
|
||||
info.height, ydpi,
|
||||
fps
|
||||
);
|
||||
|
||||
|
||||
if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
|
||||
return -errno;
|
||||
|
||||
if (finfo.smem_len <= 0)
|
||||
return -errno;
|
||||
|
||||
|
||||
module->flags = flags;
|
||||
module->info = info;
|
||||
module->finfo = finfo;
|
||||
module->xdpi = xdpi;
|
||||
module->ydpi = ydpi;
|
||||
module->fps = fps;
|
||||
|
||||
/*
|
||||
* map the framebuffer
|
||||
*/
|
||||
|
||||
int err;
|
||||
size_t fbSize = roundUpToPageSize(finfo.line_length * info.yres_virtual);
|
||||
module->framebuffer = new private_handle_t(dup(fd), fbSize,
|
||||
private_handle_t::PRIV_FLAGS_USES_PMEM);
|
||||
|
||||
module->numBuffers = info.yres_virtual / info.yres;
|
||||
module->bufferMask = 0;
|
||||
|
||||
void* vaddr = mmap(0, fbSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (vaddr == MAP_FAILED) {
|
||||
LOGE("Error mapping the framebuffer (%s)", strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
module->framebuffer->base = intptr_t(vaddr);
|
||||
memset(vaddr, 0, fbSize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mapFrameBuffer(struct private_module_t* module)
|
||||
{
|
||||
pthread_mutex_lock(&module->lock);
|
||||
int err = mapFrameBufferLocked(module);
|
||||
pthread_mutex_unlock(&module->lock);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static int fb_close(struct hw_device_t *dev)
|
||||
{
|
||||
fb_context_t* ctx = (fb_context_t*)dev;
|
||||
if (ctx) {
|
||||
free(ctx);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fb_device_open(hw_module_t const* module, const char* name,
|
||||
hw_device_t** device)
|
||||
{
|
||||
int status = -EINVAL;
|
||||
if (!strcmp(name, GRALLOC_HARDWARE_FB0)) {
|
||||
alloc_device_t* gralloc_device;
|
||||
status = gralloc_open(module, &gralloc_device);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
/* initialize our state here */
|
||||
fb_context_t *dev = (fb_context_t*)malloc(sizeof(*dev));
|
||||
memset(dev, 0, sizeof(*dev));
|
||||
|
||||
/* initialize the procs */
|
||||
dev->device.common.tag = HARDWARE_DEVICE_TAG;
|
||||
dev->device.common.version = 0;
|
||||
dev->device.common.module = const_cast<hw_module_t*>(module);
|
||||
dev->device.common.close = fb_close;
|
||||
dev->device.setSwapInterval = fb_setSwapInterval;
|
||||
dev->device.post = fb_post;
|
||||
dev->device.setUpdateRect = 0;
|
||||
dev->device.compositionComplete = fb_compositionComplete;
|
||||
|
||||
private_module_t* m = (private_module_t*)module;
|
||||
status = mapFrameBuffer(m);
|
||||
if (status >= 0) {
|
||||
int stride = m->finfo.line_length / (m->info.bits_per_pixel >> 3);
|
||||
const_cast<uint32_t&>(dev->device.flags) = 0;
|
||||
const_cast<uint32_t&>(dev->device.width) = m->info.xres;
|
||||
const_cast<uint32_t&>(dev->device.height) = m->info.yres;
|
||||
const_cast<int&>(dev->device.stride) = stride;
|
||||
const_cast<int&>(dev->device.format) = m->fbFormat;
|
||||
const_cast<float&>(dev->device.xdpi) = m->xdpi;
|
||||
const_cast<float&>(dev->device.ydpi) = m->ydpi;
|
||||
const_cast<float&>(dev->device.fps) = m->fps;
|
||||
const_cast<int&>(dev->device.minSwapInterval) = 1;
|
||||
const_cast<int&>(dev->device.maxSwapInterval) = 1;
|
||||
|
||||
if (m->finfo.reserved[0] == 0x5444 &&
|
||||
m->finfo.reserved[1] == 0x5055) {
|
||||
dev->device.setUpdateRect = fb_setUpdateRect;
|
||||
LOGD("UPDATE_ON_DEMAND supported");
|
||||
}
|
||||
|
||||
*device = &dev->device.common;
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Copy a pmem buffer to the framebuffer */
|
||||
|
||||
static void
|
||||
msm_copy_buffer(buffer_handle_t handle, int fd,
|
||||
int width, int height, int format,
|
||||
int x, int y, int w, int h)
|
||||
{
|
||||
struct {
|
||||
unsigned int count;
|
||||
mdp_blit_req req;
|
||||
} blit;
|
||||
private_handle_t *priv = (private_handle_t*) handle;
|
||||
|
||||
memset(&blit, 0, sizeof(blit));
|
||||
blit.count = 1;
|
||||
|
||||
blit.req.flags = 0;
|
||||
blit.req.alpha = 0xff;
|
||||
blit.req.transp_mask = 0xffffffff;
|
||||
|
||||
blit.req.src.width = width;
|
||||
blit.req.src.height = height;
|
||||
blit.req.src.offset = 0;
|
||||
blit.req.src.memory_id = priv->fd;
|
||||
|
||||
blit.req.dst.width = width;
|
||||
blit.req.dst.height = height;
|
||||
blit.req.dst.offset = 0;
|
||||
blit.req.dst.memory_id = fd;
|
||||
blit.req.dst.format = format;
|
||||
|
||||
blit.req.src_rect.x = blit.req.dst_rect.x = x;
|
||||
blit.req.src_rect.y = blit.req.dst_rect.y = y;
|
||||
blit.req.src_rect.w = blit.req.dst_rect.w = w;
|
||||
blit.req.src_rect.h = blit.req.dst_rect.h = h;
|
||||
|
||||
if (ioctl(fd, MSMFB_BLIT, &blit))
|
||||
LOGE("MSMFB_BLIT failed = %d", -errno);
|
||||
}
|
341
libgralloc-legacy/gpu.cpp
Normal file
341
libgralloc-legacy/gpu.cpp
Normal file
@ -0,0 +1,341 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "gr.h"
|
||||
#include "gpu.h"
|
||||
|
||||
gpu_context_t::gpu_context_t(Deps& deps, PmemAllocator& pmemAllocator,
|
||||
PmemAllocator& pmemAdspAllocator, const private_module_t* module) :
|
||||
deps(deps),
|
||||
pmemAllocator(pmemAllocator),
|
||||
pmemAdspAllocator(pmemAdspAllocator)
|
||||
{
|
||||
// Zero out the alloc_device_t
|
||||
memset(static_cast<alloc_device_t*>(this), 0, sizeof(alloc_device_t));
|
||||
|
||||
// Initialize the procs
|
||||
common.tag = HARDWARE_DEVICE_TAG;
|
||||
common.version = 0;
|
||||
common.module = const_cast<hw_module_t*>(&module->base.common);
|
||||
common.close = gralloc_close;
|
||||
alloc = gralloc_alloc;
|
||||
free = gralloc_free;
|
||||
}
|
||||
|
||||
int gpu_context_t::gralloc_alloc_framebuffer_locked(size_t size, int usage,
|
||||
buffer_handle_t* pHandle)
|
||||
{
|
||||
private_module_t* m = reinterpret_cast<private_module_t*>(common.module);
|
||||
|
||||
// we don't support allocations with both the FB and PMEM_ADSP flags
|
||||
if (usage & GRALLOC_USAGE_PRIVATE_PMEM_ADSP) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
// allocate the framebuffer
|
||||
if (m->framebuffer == NULL) {
|
||||
// initialize the framebuffer, the framebuffer is mapped once
|
||||
// and forever.
|
||||
int err = deps.mapFrameBufferLocked(m);
|
||||
if (err < 0) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
const uint32_t bufferMask = m->bufferMask;
|
||||
const uint32_t numBuffers = m->numBuffers;
|
||||
const size_t bufferSize = m->finfo.line_length * m->info.yres;
|
||||
if (numBuffers == 1) {
|
||||
// If we have only one buffer, we never use page-flipping. Instead,
|
||||
// we return a regular buffer which will be memcpy'ed to the main
|
||||
// screen when post is called.
|
||||
int newUsage = (usage & ~GRALLOC_USAGE_HW_FB) | GRALLOC_USAGE_HW_2D;
|
||||
return gralloc_alloc_buffer(bufferSize, newUsage, pHandle);
|
||||
}
|
||||
|
||||
if (bufferMask >= ((1LU<<numBuffers)-1)) {
|
||||
// We ran out of buffers.
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
// create a "fake" handles for it
|
||||
intptr_t vaddr = intptr_t(m->framebuffer->base);
|
||||
private_handle_t* hnd = new private_handle_t(dup(m->framebuffer->fd), size,
|
||||
private_handle_t::PRIV_FLAGS_USES_PMEM |
|
||||
private_handle_t::PRIV_FLAGS_FRAMEBUFFER);
|
||||
|
||||
// find a free slot
|
||||
for (uint32_t i=0 ; i<numBuffers ; i++) {
|
||||
if ((bufferMask & (1LU<<i)) == 0) {
|
||||
m->bufferMask |= (1LU<<i);
|
||||
break;
|
||||
}
|
||||
vaddr += bufferSize;
|
||||
}
|
||||
|
||||
hnd->base = vaddr;
|
||||
hnd->offset = vaddr - intptr_t(m->framebuffer->base);
|
||||
*pHandle = hnd;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int gpu_context_t::gralloc_alloc_framebuffer(size_t size, int usage,
|
||||
buffer_handle_t* pHandle)
|
||||
{
|
||||
private_module_t* m = reinterpret_cast<private_module_t*>(common.module);
|
||||
pthread_mutex_lock(&m->lock);
|
||||
int err = gralloc_alloc_framebuffer_locked(size, usage, pHandle);
|
||||
pthread_mutex_unlock(&m->lock);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
int gpu_context_t::gralloc_alloc_buffer(size_t size, int usage, buffer_handle_t* pHandle)
|
||||
{
|
||||
int err = 0;
|
||||
int flags = 0;
|
||||
|
||||
int fd = -1;
|
||||
void* base = 0; // XXX JMG: This should change to just get an address from
|
||||
// the PmemAllocator rather than getting the base & offset separately
|
||||
int offset = 0;
|
||||
int lockState = 0;
|
||||
|
||||
size = roundUpToPageSize(size);
|
||||
|
||||
if (usage & GRALLOC_USAGE_HW_TEXTURE) {
|
||||
// enable pmem in that case, so our software GL can fallback to
|
||||
// the copybit module.
|
||||
flags |= private_handle_t::PRIV_FLAGS_USES_PMEM;
|
||||
}
|
||||
|
||||
if (usage & GRALLOC_USAGE_HW_2D) {
|
||||
flags |= private_handle_t::PRIV_FLAGS_USES_PMEM;
|
||||
}
|
||||
|
||||
if (usage & GRALLOC_USAGE_PRIVATE_PMEM_ADSP) {
|
||||
flags |= private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP;
|
||||
flags &= ~private_handle_t::PRIV_FLAGS_USES_PMEM;
|
||||
}
|
||||
|
||||
private_module_t* m = reinterpret_cast<private_module_t*>(common.module);
|
||||
|
||||
if ((flags & private_handle_t::PRIV_FLAGS_USES_PMEM) != 0 ||
|
||||
(flags & private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP) != 0) {
|
||||
|
||||
PmemAllocator* pma = 0;
|
||||
|
||||
if ((flags & private_handle_t::PRIV_FLAGS_USES_PMEM) != 0) {
|
||||
if ((flags & private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP) != 0) {
|
||||
LOGE("attempting to allocate a gralloc buffer with both the "
|
||||
"USES_PMEM and USES_PMEM_ADSP flags. Unsetting the "
|
||||
"USES_PMEM_ADSP flag.");
|
||||
flags &= ~private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP;
|
||||
}
|
||||
pma = &pmemAllocator;
|
||||
} else { // (flags & private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP) != 0
|
||||
pma = &pmemAdspAllocator;
|
||||
}
|
||||
|
||||
// PMEM buffers are always mmapped
|
||||
lockState |= private_handle_t::LOCK_STATE_MAPPED;
|
||||
|
||||
// Allocate the buffer from pmem
|
||||
err = pma->alloc_pmem_buffer(size, usage, &base, &offset, &fd);
|
||||
if (err < 0) {
|
||||
if (((usage & GRALLOC_USAGE_HW_MASK) == 0) &&
|
||||
((usage & GRALLOC_USAGE_PRIVATE_PMEM_ADSP) == 0)) {
|
||||
// the caller didn't request PMEM, so we can try something else
|
||||
flags &= ~private_handle_t::PRIV_FLAGS_USES_PMEM;
|
||||
err = 0;
|
||||
goto try_ashmem;
|
||||
} else {
|
||||
LOGE("couldn't open pmem (%s)", strerror(errno));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try_ashmem:
|
||||
fd = deps.ashmem_create_region("gralloc-buffer", size);
|
||||
if (fd < 0) {
|
||||
LOGE("couldn't create ashmem (%s)", strerror(errno));
|
||||
err = -errno;
|
||||
}
|
||||
}
|
||||
|
||||
if (err == 0) {
|
||||
private_handle_t* hnd = new private_handle_t(fd, size, flags);
|
||||
hnd->offset = offset;
|
||||
hnd->base = int(base)+offset;
|
||||
hnd->lockState = lockState;
|
||||
*pHandle = hnd;
|
||||
}
|
||||
|
||||
LOGE_IF(err, "gralloc failed err=%s", strerror(-err));
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline size_t ALIGN(size_t x, size_t align) {
|
||||
return (x + align-1) & ~(align-1);
|
||||
}
|
||||
|
||||
int gpu_context_t::alloc_impl(int w, int h, int format, int usage,
|
||||
buffer_handle_t* pHandle, int* pStride) {
|
||||
if (!pHandle || !pStride)
|
||||
return -EINVAL;
|
||||
|
||||
size_t size, alignedw, alignedh;
|
||||
|
||||
alignedw = ALIGN(w, 32);
|
||||
alignedh = ALIGN(h, 32);
|
||||
switch (format) {
|
||||
case HAL_PIXEL_FORMAT_RGBA_8888:
|
||||
case HAL_PIXEL_FORMAT_RGBX_8888:
|
||||
case HAL_PIXEL_FORMAT_BGRA_8888:
|
||||
size = alignedw * alignedh * 4;
|
||||
break;
|
||||
case HAL_PIXEL_FORMAT_RGB_888:
|
||||
size = alignedw * alignedh * 3;
|
||||
break;
|
||||
case HAL_PIXEL_FORMAT_RGB_565:
|
||||
case HAL_PIXEL_FORMAT_RGBA_5551:
|
||||
case HAL_PIXEL_FORMAT_RGBA_4444:
|
||||
size = alignedw * alignedh * 2;
|
||||
break;
|
||||
|
||||
// adreno formats
|
||||
case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO: // NV21
|
||||
size = ALIGN(alignedw*alignedh, 4096);
|
||||
size += ALIGN(2 * ALIGN(w/2, 32) * ALIGN(h/2, 32), 4096);
|
||||
break;
|
||||
case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: // NV12
|
||||
// The chroma plane is subsampled,
|
||||
// but the pitch in bytes is unchanged
|
||||
// The GPU needs 4K alignment, but the video decoder needs 8K
|
||||
alignedw = ALIGN(w, 128);
|
||||
size = ALIGN( alignedw * alignedh, 8192);
|
||||
size += ALIGN( alignedw * ALIGN(h/2, 32), 4096);
|
||||
break;
|
||||
|
||||
case HAL_PIXEL_FORMAT_YV12:
|
||||
if ((w&1) || (h&1)) {
|
||||
LOGE("w or h is odd for HAL_PIXEL_FORMAT_YV12");
|
||||
return -EINVAL;
|
||||
}
|
||||
alignedw = ALIGN(w, 16);
|
||||
alignedh = h;
|
||||
size = alignedw*alignedh +
|
||||
(ALIGN(alignedw/2, 16) * (alignedh/2))*2;
|
||||
break;
|
||||
|
||||
default:
|
||||
LOGE("unrecognized pixel format: %d", format);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((ssize_t)size <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
int err;
|
||||
if (usage & GRALLOC_USAGE_HW_FB) {
|
||||
err = gralloc_alloc_framebuffer(size, usage, pHandle);
|
||||
} else {
|
||||
err = gralloc_alloc_buffer(size, usage, pHandle);
|
||||
}
|
||||
|
||||
if (err < 0) {
|
||||
return err;
|
||||
}
|
||||
|
||||
*pStride = alignedw;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gpu_context_t::free_impl(private_handle_t const* hnd) {
|
||||
private_module_t* m = reinterpret_cast<private_module_t*>(common.module);
|
||||
if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) {
|
||||
// free this buffer
|
||||
const size_t bufferSize = m->finfo.line_length * m->info.yres;
|
||||
int index = (hnd->base - m->framebuffer->base) / bufferSize;
|
||||
m->bufferMask &= ~(1<<index);
|
||||
} else {
|
||||
PmemAllocator* pmem_allocator = 0;
|
||||
if (hnd->flags & private_handle_t::PRIV_FLAGS_USES_PMEM) {
|
||||
pmem_allocator = &pmemAllocator;
|
||||
} else if (hnd->flags & private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP) {
|
||||
pmem_allocator = &pmemAdspAllocator;
|
||||
}
|
||||
if (pmem_allocator) {
|
||||
pmem_allocator->free_pmem_buffer(hnd->size, (void*)hnd->base,
|
||||
hnd->offset, hnd->fd);
|
||||
}
|
||||
deps.terminateBuffer(&m->base, const_cast<private_handle_t*>(hnd));
|
||||
}
|
||||
|
||||
deps.close(hnd->fd);
|
||||
delete hnd; // XXX JMG: move this to the deps
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Static functions
|
||||
*****************************************************************************/
|
||||
|
||||
int gpu_context_t::gralloc_alloc(alloc_device_t* dev, int w, int h, int format,
|
||||
int usage, buffer_handle_t* pHandle, int* pStride)
|
||||
{
|
||||
if (!dev) {
|
||||
return -EINVAL;
|
||||
}
|
||||
gpu_context_t* gpu = reinterpret_cast<gpu_context_t*>(dev);
|
||||
return gpu->alloc_impl(w, h, format, usage, pHandle, pStride);
|
||||
}
|
||||
|
||||
int gpu_context_t::gralloc_free(alloc_device_t* dev,
|
||||
buffer_handle_t handle)
|
||||
{
|
||||
if (private_handle_t::validate(handle) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
private_handle_t const* hnd = reinterpret_cast<private_handle_t const*>(handle);
|
||||
gpu_context_t* gpu = reinterpret_cast<gpu_context_t*>(dev);
|
||||
return gpu->free_impl(hnd);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int gpu_context_t::gralloc_close(struct hw_device_t *dev)
|
||||
{
|
||||
gpu_context_t* ctx = reinterpret_cast<gpu_context_t*>(dev);
|
||||
if (ctx) {
|
||||
/* TODO: keep a list of all buffer_handle_t created, and free them
|
||||
* all here.
|
||||
*/
|
||||
delete ctx;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
gpu_context_t::Deps::~Deps() {}
|
76
libgralloc-legacy/gpu.h
Normal file
76
libgralloc-legacy/gpu.h
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef GRALLOC_QSD8K_GPU_H_
|
||||
#define GRALLOC_QSD8K_GPU_H_
|
||||
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <cutils/log.h>
|
||||
#include <cutils/ashmem.h>
|
||||
|
||||
#include "gralloc_priv.h"
|
||||
#include "pmemalloc.h"
|
||||
|
||||
|
||||
class gpu_context_t : public alloc_device_t {
|
||||
public:
|
||||
|
||||
class Deps {
|
||||
public:
|
||||
|
||||
virtual ~Deps();
|
||||
|
||||
// ashmem
|
||||
virtual int ashmem_create_region(const char *name, size_t size) = 0;
|
||||
|
||||
// POSIX
|
||||
virtual int close(int fd) = 0;
|
||||
|
||||
// Framebuffer (locally defined)
|
||||
virtual int mapFrameBufferLocked(struct private_module_t* module) = 0;
|
||||
virtual int terminateBuffer(gralloc_module_t const* module,
|
||||
private_handle_t* hnd) = 0;
|
||||
};
|
||||
|
||||
gpu_context_t(Deps& deps, PmemAllocator& pmemAllocator,
|
||||
PmemAllocator& pmemAdspAllocator, const private_module_t* module);
|
||||
|
||||
int gralloc_alloc_framebuffer_locked(size_t size, int usage,
|
||||
buffer_handle_t* pHandle);
|
||||
int gralloc_alloc_framebuffer(size_t size, int usage,
|
||||
buffer_handle_t* pHandle);
|
||||
int gralloc_alloc_buffer(size_t size, int usage, buffer_handle_t* pHandle);
|
||||
int free_impl(private_handle_t const* hnd);
|
||||
int alloc_impl(int w, int h, int format, int usage,
|
||||
buffer_handle_t* pHandle, int* pStride);
|
||||
|
||||
static int gralloc_alloc(alloc_device_t* dev, int w, int h, int format,
|
||||
int usage, buffer_handle_t* pHandle, int* pStride);
|
||||
static int gralloc_free(alloc_device_t* dev, buffer_handle_t handle);
|
||||
static int gralloc_close(struct hw_device_t *dev);
|
||||
|
||||
private:
|
||||
|
||||
Deps& deps;
|
||||
PmemAllocator& pmemAllocator;
|
||||
PmemAllocator& pmemAdspAllocator;
|
||||
};
|
||||
|
||||
#endif // GRALLOC_QSD8K_GPU_H
|
63
libgralloc-legacy/gr.h
Normal file
63
libgralloc-legacy/gr.h
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef GR_H_
|
||||
#define GR_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#ifdef HAVE_ANDROID_OS // just want PAGE_SIZE define
|
||||
# include <asm/page.h>
|
||||
#else
|
||||
# include <sys/user.h>
|
||||
#endif
|
||||
#include <limits.h>
|
||||
#include <sys/cdefs.h>
|
||||
#include <hardware/gralloc.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <cutils/native_handle.h>
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
struct private_module_t;
|
||||
struct private_handle_t;
|
||||
|
||||
inline size_t roundUpToPageSize(size_t x) {
|
||||
return (x + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1);
|
||||
}
|
||||
|
||||
int mapFrameBufferLocked(struct private_module_t* module);
|
||||
int terminateBuffer(gralloc_module_t const* module, private_handle_t* hnd);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
class Locker {
|
||||
pthread_mutex_t mutex;
|
||||
public:
|
||||
class Autolock {
|
||||
Locker& locker;
|
||||
public:
|
||||
inline Autolock(Locker& locker) : locker(locker) { locker.lock(); }
|
||||
inline ~Autolock() { locker.unlock(); }
|
||||
};
|
||||
inline Locker() { pthread_mutex_init(&mutex, 0); }
|
||||
inline ~Locker() { pthread_mutex_destroy(&mutex); }
|
||||
inline void lock() { pthread_mutex_lock(&mutex); }
|
||||
inline void unlock() { pthread_mutex_unlock(&mutex); }
|
||||
};
|
||||
|
||||
#endif /* GR_H_ */
|
196
libgralloc-legacy/gralloc.cpp
Normal file
196
libgralloc-legacy/gralloc.cpp
Normal file
@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <linux/android_pmem.h>
|
||||
|
||||
#include "allocator.h"
|
||||
#include "gr.h"
|
||||
#include "gpu.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static int gralloc_alloc_buffer(alloc_device_t* dev,
|
||||
size_t size, int usage, buffer_handle_t* pHandle);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int fb_device_open(const hw_module_t* module, const char* name,
|
||||
hw_device_t** device);
|
||||
|
||||
static int gralloc_device_open(const hw_module_t* module, const char* name,
|
||||
hw_device_t** device);
|
||||
|
||||
extern int gralloc_lock(gralloc_module_t const* module,
|
||||
buffer_handle_t handle, int usage,
|
||||
int l, int t, int w, int h,
|
||||
void** vaddr);
|
||||
|
||||
extern int gralloc_unlock(gralloc_module_t const* module,
|
||||
buffer_handle_t handle);
|
||||
|
||||
extern int gralloc_register_buffer(gralloc_module_t const* module,
|
||||
buffer_handle_t handle);
|
||||
|
||||
extern int gralloc_unregister_buffer(gralloc_module_t const* module,
|
||||
buffer_handle_t handle);
|
||||
|
||||
extern int gralloc_perform(struct gralloc_module_t const* module,
|
||||
int operation, ... );
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/* On-device dependency implementation */
|
||||
class PmemAllocatorDepsDeviceImpl : public PmemUserspaceAllocator::Deps,
|
||||
public PmemKernelAllocator::Deps {
|
||||
|
||||
virtual size_t getPmemTotalSize(int fd, size_t* size) {
|
||||
pmem_region region;
|
||||
int err = ioctl(fd, PMEM_GET_TOTAL_SIZE, ®ion);
|
||||
if (err == 0) {
|
||||
*size = region.len;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
virtual int connectPmem(int fd, int master_fd) {
|
||||
return ioctl(fd, PMEM_CONNECT, master_fd);
|
||||
}
|
||||
|
||||
virtual int mapPmem(int fd, int offset, size_t size) {
|
||||
struct pmem_region sub = { offset, size };
|
||||
return ioctl(fd, PMEM_MAP, &sub);
|
||||
}
|
||||
|
||||
virtual int unmapPmem(int fd, int offset, size_t size) {
|
||||
struct pmem_region sub = { offset, size };
|
||||
return ioctl(fd, PMEM_UNMAP, &sub);
|
||||
}
|
||||
|
||||
virtual int getErrno() {
|
||||
return errno;
|
||||
}
|
||||
|
||||
virtual void* mmap(void* start, size_t length, int prot, int flags, int fd,
|
||||
off_t offset) {
|
||||
return ::mmap(start, length, prot, flags, fd, offset);
|
||||
}
|
||||
|
||||
virtual int munmap(void* start, size_t length) {
|
||||
return ::munmap(start, length);
|
||||
}
|
||||
|
||||
virtual int open(const char* pathname, int flags, int mode) {
|
||||
return ::open(pathname, flags, mode);
|
||||
}
|
||||
|
||||
virtual int close(int fd) {
|
||||
return ::close(fd);
|
||||
}
|
||||
};
|
||||
|
||||
class GpuContextDepsDeviceImpl : public gpu_context_t::Deps {
|
||||
|
||||
public:
|
||||
|
||||
virtual int ashmem_create_region(const char *name, size_t size) {
|
||||
return ::ashmem_create_region(name, size);
|
||||
}
|
||||
|
||||
virtual int mapFrameBufferLocked(struct private_module_t* module) {
|
||||
return ::mapFrameBufferLocked(module);
|
||||
}
|
||||
|
||||
virtual int terminateBuffer(gralloc_module_t const* module,
|
||||
private_handle_t* hnd) {
|
||||
return ::terminateBuffer(module, hnd);
|
||||
}
|
||||
|
||||
virtual int close(int fd) {
|
||||
return ::close(fd);
|
||||
}
|
||||
};
|
||||
|
||||
static PmemAllocatorDepsDeviceImpl pmemAllocatorDeviceDepsImpl;
|
||||
static GpuContextDepsDeviceImpl gpuContextDeviceDepsImpl;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static SimpleBestFitAllocator pmemAllocMgr;
|
||||
static PmemUserspaceAllocator pmemAllocator(pmemAllocatorDeviceDepsImpl, pmemAllocMgr,
|
||||
"/dev/pmem");
|
||||
|
||||
static PmemKernelAllocator pmemAdspAllocator(pmemAllocatorDeviceDepsImpl,
|
||||
"/dev/pmem_adsp");
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static struct hw_module_methods_t gralloc_module_methods = {
|
||||
open: gralloc_device_open
|
||||
};
|
||||
|
||||
struct private_module_t HAL_MODULE_INFO_SYM = {
|
||||
base: {
|
||||
common: {
|
||||
tag: HARDWARE_MODULE_TAG,
|
||||
version_major: 1,
|
||||
version_minor: 0,
|
||||
id: GRALLOC_HARDWARE_MODULE_ID,
|
||||
name: "Graphics Memory Allocator Module",
|
||||
author: "The Android Open Source Project",
|
||||
methods: &gralloc_module_methods
|
||||
},
|
||||
registerBuffer: gralloc_register_buffer,
|
||||
unregisterBuffer: gralloc_unregister_buffer,
|
||||
lock: gralloc_lock,
|
||||
unlock: gralloc_unlock,
|
||||
perform: gralloc_perform,
|
||||
},
|
||||
framebuffer: 0,
|
||||
fbFormat: 0,
|
||||
flags: 0,
|
||||
numBuffers: 0,
|
||||
bufferMask: 0,
|
||||
lock: PTHREAD_MUTEX_INITIALIZER,
|
||||
currentBuffer: 0,
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int gralloc_device_open(const hw_module_t* module, const char* name,
|
||||
hw_device_t** device)
|
||||
{
|
||||
int status = -EINVAL;
|
||||
if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) {
|
||||
const private_module_t* m = reinterpret_cast<const private_module_t*>(
|
||||
module);
|
||||
gpu_context_t *dev;
|
||||
dev = new gpu_context_t(gpuContextDeviceDepsImpl, pmemAllocator,
|
||||
pmemAdspAllocator, m);
|
||||
*device = &dev->common;
|
||||
status = 0;
|
||||
} else {
|
||||
status = fb_device_open(module, name, device);
|
||||
}
|
||||
return status;
|
||||
}
|
165
libgralloc-legacy/gralloc_priv.h
Normal file
165
libgralloc-legacy/gralloc_priv.h
Normal file
@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef GRALLOC_PRIV_H_
|
||||
#define GRALLOC_PRIV_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include <sys/cdefs.h>
|
||||
#include <hardware/gralloc.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cutils/native_handle.h>
|
||||
|
||||
#include <linux/fb.h>
|
||||
|
||||
enum {
|
||||
/* gralloc usage bit indicating a pmem_adsp allocation should be used */
|
||||
GRALLOC_USAGE_PRIVATE_PMEM_ADSP = GRALLOC_USAGE_PRIVATE_0,
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
enum {
|
||||
/* OEM specific HAL formats */
|
||||
//HAL_PIXEL_FORMAT_YCbCr_422_SP = 0x100, // defined in hardware.h
|
||||
//HAL_PIXEL_FORMAT_YCrCb_420_SP = 0x101, // defined in hardware.h
|
||||
HAL_PIXEL_FORMAT_YCbCr_422_P = 0x102,
|
||||
HAL_PIXEL_FORMAT_YCbCr_420_P = 0x103,
|
||||
//HAL_PIXEL_FORMAT_YCbCr_422_I = 0x104, // defined in hardware.h
|
||||
HAL_PIXEL_FORMAT_YCbCr_420_I = 0x105,
|
||||
HAL_PIXEL_FORMAT_CbYCrY_422_I = 0x106,
|
||||
HAL_PIXEL_FORMAT_CbYCrY_420_I = 0x107,
|
||||
HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED = 0x108,
|
||||
HAL_PIXEL_FORMAT_YCbCr_420_SP = 0x109,
|
||||
HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO = 0x10A,
|
||||
HAL_PIXEL_FORMAT_YCrCb_422_SP = 0x10B,
|
||||
HAL_PIXEL_FORMAT_YCrCb_420_SP_INTERLACE = 0x10C,
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
struct private_module_t;
|
||||
struct private_handle_t;
|
||||
struct PmemAllocator;
|
||||
|
||||
struct private_module_t {
|
||||
gralloc_module_t base;
|
||||
|
||||
struct private_handle_t* framebuffer;
|
||||
uint32_t fbFormat;
|
||||
uint32_t flags;
|
||||
uint32_t numBuffers;
|
||||
uint32_t bufferMask;
|
||||
pthread_mutex_t lock;
|
||||
buffer_handle_t currentBuffer;
|
||||
|
||||
struct fb_var_screeninfo info;
|
||||
struct fb_fix_screeninfo finfo;
|
||||
float xdpi;
|
||||
float ydpi;
|
||||
float fps;
|
||||
|
||||
enum {
|
||||
// flag to indicate we'll post this buffer
|
||||
PRIV_USAGE_LOCKED_FOR_POST = 0x80000000
|
||||
};
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
struct private_handle_t : public native_handle {
|
||||
#else
|
||||
struct private_handle_t {
|
||||
native_handle_t nativeHandle;
|
||||
#endif
|
||||
|
||||
enum {
|
||||
PRIV_FLAGS_FRAMEBUFFER = 0x00000001,
|
||||
PRIV_FLAGS_USES_PMEM = 0x00000002,
|
||||
PRIV_FLAGS_USES_PMEM_ADSP = 0x00000004,
|
||||
PRIV_FLAGS_NEEDS_FLUSH = 0x00000008,
|
||||
};
|
||||
|
||||
enum {
|
||||
LOCK_STATE_WRITE = 1<<31,
|
||||
LOCK_STATE_MAPPED = 1<<30,
|
||||
LOCK_STATE_READ_MASK = 0x3FFFFFFF
|
||||
};
|
||||
|
||||
// file-descriptors
|
||||
int fd;
|
||||
// ints
|
||||
int magic;
|
||||
int flags;
|
||||
int size;
|
||||
int offset;
|
||||
int gpu_fd; // stored as an int, b/c we don't want it marshalled
|
||||
|
||||
// FIXME: the attributes below should be out-of-line
|
||||
int base;
|
||||
int lockState;
|
||||
int writeOwner;
|
||||
int gpuaddr; // The gpu address mapped into the mmu. If using ashmem, set to 0 They don't care
|
||||
int pid;
|
||||
|
||||
#ifdef __cplusplus
|
||||
static const int sNumInts = 10;
|
||||
static const int sNumFds = 1;
|
||||
static const int sMagic = 'gmsm';
|
||||
|
||||
private_handle_t(int fd, int size, int flags) :
|
||||
fd(fd), magic(sMagic), flags(flags), size(size), offset(0), gpu_fd(-1),
|
||||
base(0), lockState(0), writeOwner(0), gpuaddr(0), pid(getpid())
|
||||
{
|
||||
version = sizeof(native_handle);
|
||||
numInts = sNumInts;
|
||||
numFds = sNumFds;
|
||||
}
|
||||
~private_handle_t() {
|
||||
magic = 0;
|
||||
}
|
||||
|
||||
bool usesPhysicallyContiguousMemory() {
|
||||
return (flags & PRIV_FLAGS_USES_PMEM) != 0;
|
||||
}
|
||||
|
||||
static int validate(const native_handle* h) {
|
||||
const private_handle_t* hnd = (const private_handle_t*)h;
|
||||
if (!h || h->version != sizeof(native_handle) ||
|
||||
h->numInts != sNumInts || h->numFds != sNumFds ||
|
||||
hnd->magic != sMagic)
|
||||
{
|
||||
LOGE("invalid gralloc handle (at %p)", h);
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static private_handle_t* dynamicCast(const native_handle* in) {
|
||||
if (validate(in) == 0) {
|
||||
return (private_handle_t*) in;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif /* GRALLOC_PRIV_H_ */
|
325
libgralloc-legacy/mapper.cpp
Normal file
325
libgralloc-legacy/mapper.cpp
Normal file
@ -0,0 +1,325 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <cutils/log.h>
|
||||
#include <cutils/atomic.h>
|
||||
|
||||
#include <hardware/hardware.h>
|
||||
#include <hardware/gralloc.h>
|
||||
|
||||
#include <linux/android_pmem.h>
|
||||
|
||||
#include "gralloc_priv.h"
|
||||
|
||||
|
||||
// we need this for now because pmem cannot mmap at an offset
|
||||
#define PMEM_HACK 1
|
||||
|
||||
/* desktop Linux needs a little help with gettid() */
|
||||
#if defined(ARCH_X86) && !defined(HAVE_ANDROID_OS)
|
||||
#define __KERNEL__
|
||||
# include <linux/unistd.h>
|
||||
pid_t gettid() { return syscall(__NR_gettid);}
|
||||
#undef __KERNEL__
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static int gralloc_map(gralloc_module_t const* module,
|
||||
buffer_handle_t handle,
|
||||
void** vaddr)
|
||||
{
|
||||
private_handle_t* hnd = (private_handle_t*)handle;
|
||||
if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) {
|
||||
size_t size = hnd->size;
|
||||
#if PMEM_HACK
|
||||
size += hnd->offset;
|
||||
#endif
|
||||
void* mappedAddress = mmap(0, size,
|
||||
PROT_READ|PROT_WRITE, MAP_SHARED, hnd->fd, 0);
|
||||
if (mappedAddress == MAP_FAILED) {
|
||||
LOGE("Could not mmap handle %p, fd=%d (%s)",
|
||||
handle, hnd->fd, strerror(errno));
|
||||
hnd->base = 0;
|
||||
return -errno;
|
||||
}
|
||||
hnd->base = intptr_t(mappedAddress) + hnd->offset;
|
||||
//LOGD("gralloc_map() succeeded fd=%d, off=%d, size=%d, vaddr=%p",
|
||||
// hnd->fd, hnd->offset, hnd->size, mappedAddress);
|
||||
}
|
||||
*vaddr = (void*)hnd->base;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gralloc_unmap(gralloc_module_t const* module,
|
||||
buffer_handle_t handle)
|
||||
{
|
||||
private_handle_t* hnd = (private_handle_t*)handle;
|
||||
if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) {
|
||||
void* base = (void*)hnd->base;
|
||||
size_t size = hnd->size;
|
||||
#if PMEM_HACK
|
||||
base = (void*)(intptr_t(base) - hnd->offset);
|
||||
size += hnd->offset;
|
||||
#endif
|
||||
//LOGD("unmapping from %p, size=%d", base, size);
|
||||
if (munmap(base, size) < 0) {
|
||||
LOGE("Could not unmap %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
hnd->base = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static pthread_mutex_t sMapLock = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int gralloc_register_buffer(gralloc_module_t const* module,
|
||||
buffer_handle_t handle)
|
||||
{
|
||||
if (private_handle_t::validate(handle) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
// In this implementation, we don't need to do anything here
|
||||
|
||||
/* NOTE: we need to initialize the buffer as not mapped/not locked
|
||||
* because it shouldn't when this function is called the first time
|
||||
* in a new process. Ideally these flags shouldn't be part of the
|
||||
* handle, but instead maintained in the kernel or at least
|
||||
* out-of-line
|
||||
*/
|
||||
|
||||
// if this handle was created in this process, then we keep it as is.
|
||||
private_handle_t* hnd = (private_handle_t*)handle;
|
||||
if (hnd->pid != getpid()) {
|
||||
hnd->base = 0;
|
||||
hnd->lockState = 0;
|
||||
hnd->writeOwner = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gralloc_unregister_buffer(gralloc_module_t const* module,
|
||||
buffer_handle_t handle)
|
||||
{
|
||||
if (private_handle_t::validate(handle) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* If the buffer has been mapped during a lock operation, it's time
|
||||
* to un-map it. It's an error to be here with a locked buffer.
|
||||
* NOTE: the framebuffer is handled differently and is never unmapped.
|
||||
*/
|
||||
|
||||
private_handle_t* hnd = (private_handle_t*)handle;
|
||||
|
||||
LOGE_IF(hnd->lockState & private_handle_t::LOCK_STATE_READ_MASK,
|
||||
"[unregister] handle %p still locked (state=%08x)",
|
||||
hnd, hnd->lockState);
|
||||
|
||||
// never unmap buffers that were created in this process
|
||||
if (hnd->pid != getpid()) {
|
||||
if (hnd->lockState & private_handle_t::LOCK_STATE_MAPPED) {
|
||||
gralloc_unmap(module, handle);
|
||||
}
|
||||
hnd->base = 0;
|
||||
hnd->lockState = 0;
|
||||
hnd->writeOwner = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int terminateBuffer(gralloc_module_t const* module,
|
||||
private_handle_t* hnd)
|
||||
{
|
||||
/*
|
||||
* If the buffer has been mapped during a lock operation, it's time
|
||||
* to un-map it. It's an error to be here with a locked buffer.
|
||||
*/
|
||||
|
||||
LOGE_IF(hnd->lockState & private_handle_t::LOCK_STATE_READ_MASK,
|
||||
"[terminate] handle %p still locked (state=%08x)",
|
||||
hnd, hnd->lockState);
|
||||
|
||||
if (hnd->lockState & private_handle_t::LOCK_STATE_MAPPED) {
|
||||
// this buffer was mapped, unmap it now
|
||||
if ((hnd->flags & private_handle_t::PRIV_FLAGS_USES_PMEM) ||
|
||||
(hnd->flags & private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP)) {
|
||||
if (hnd->pid != getpid()) {
|
||||
// ... unless it's a "master" pmem buffer, that is a buffer
|
||||
// mapped in the process it's been allocated.
|
||||
// (see gralloc_alloc_buffer())
|
||||
gralloc_unmap(module, hnd);
|
||||
}
|
||||
} else {
|
||||
gralloc_unmap(module, hnd);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gralloc_lock(gralloc_module_t const* module,
|
||||
buffer_handle_t handle, int usage,
|
||||
int l, int t, int w, int h,
|
||||
void** vaddr)
|
||||
{
|
||||
if (private_handle_t::validate(handle) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
int err = 0;
|
||||
private_handle_t* hnd = (private_handle_t*)handle;
|
||||
int32_t current_value, new_value;
|
||||
int retry;
|
||||
|
||||
do {
|
||||
current_value = hnd->lockState;
|
||||
new_value = current_value;
|
||||
|
||||
if (current_value & private_handle_t::LOCK_STATE_WRITE) {
|
||||
// already locked for write
|
||||
LOGE("handle %p already locked for write", handle);
|
||||
return -EBUSY;
|
||||
} else if (current_value & private_handle_t::LOCK_STATE_READ_MASK) {
|
||||
// already locked for read
|
||||
if (usage & (GRALLOC_USAGE_SW_WRITE_MASK | GRALLOC_USAGE_HW_RENDER)) {
|
||||
LOGE("handle %p already locked for read", handle);
|
||||
return -EBUSY;
|
||||
} else {
|
||||
// this is not an error
|
||||
//LOGD("%p already locked for read... count = %d",
|
||||
// handle, (current_value & ~(1<<31)));
|
||||
}
|
||||
}
|
||||
|
||||
// not currently locked
|
||||
if (usage & (GRALLOC_USAGE_SW_WRITE_MASK | GRALLOC_USAGE_HW_RENDER)) {
|
||||
// locking for write
|
||||
new_value |= private_handle_t::LOCK_STATE_WRITE;
|
||||
}
|
||||
new_value++;
|
||||
|
||||
retry = android_atomic_cmpxchg(current_value, new_value,
|
||||
(volatile int32_t*)&hnd->lockState);
|
||||
} while (retry);
|
||||
|
||||
if (new_value & private_handle_t::LOCK_STATE_WRITE) {
|
||||
// locking for write, store the tid
|
||||
hnd->writeOwner = gettid();
|
||||
}
|
||||
|
||||
// if requesting sw write for non-framebuffer handles, flag for
|
||||
// flushing at unlock
|
||||
|
||||
const uint32_t pmemMask =
|
||||
private_handle_t::PRIV_FLAGS_USES_PMEM |
|
||||
private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP;
|
||||
|
||||
if ((usage & GRALLOC_USAGE_SW_WRITE_MASK) &&
|
||||
(hnd->flags & pmemMask) &&
|
||||
!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) {
|
||||
hnd->flags |= private_handle_t::PRIV_FLAGS_NEEDS_FLUSH;
|
||||
}
|
||||
|
||||
if (usage & (GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK)) {
|
||||
if (!(current_value & private_handle_t::LOCK_STATE_MAPPED)) {
|
||||
// we need to map for real
|
||||
pthread_mutex_t* const lock = &sMapLock;
|
||||
pthread_mutex_lock(lock);
|
||||
if (!(hnd->lockState & private_handle_t::LOCK_STATE_MAPPED)) {
|
||||
err = gralloc_map(module, handle, vaddr);
|
||||
if (err == 0) {
|
||||
android_atomic_or(private_handle_t::LOCK_STATE_MAPPED,
|
||||
(volatile int32_t*)&(hnd->lockState));
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(lock);
|
||||
}
|
||||
*vaddr = (void*)hnd->base;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int gralloc_unlock(gralloc_module_t const* module,
|
||||
buffer_handle_t handle)
|
||||
{
|
||||
if (private_handle_t::validate(handle) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
private_handle_t* hnd = (private_handle_t*)handle;
|
||||
int32_t current_value, new_value;
|
||||
|
||||
if (hnd->flags & private_handle_t::PRIV_FLAGS_NEEDS_FLUSH) {
|
||||
struct pmem_region region;
|
||||
int err;
|
||||
|
||||
region.offset = hnd->offset;
|
||||
region.len = hnd->size;
|
||||
err = ioctl(hnd->fd, PMEM_CACHE_FLUSH, ®ion);
|
||||
LOGE_IF(err < 0, "cannot flush handle %p (offs=%x len=%x)\n",
|
||||
hnd, hnd->offset, hnd->size);
|
||||
hnd->flags &= ~private_handle_t::PRIV_FLAGS_NEEDS_FLUSH;
|
||||
}
|
||||
|
||||
do {
|
||||
current_value = hnd->lockState;
|
||||
new_value = current_value;
|
||||
|
||||
if (current_value & private_handle_t::LOCK_STATE_WRITE) {
|
||||
// locked for write
|
||||
if (hnd->writeOwner == gettid()) {
|
||||
hnd->writeOwner = 0;
|
||||
new_value &= ~private_handle_t::LOCK_STATE_WRITE;
|
||||
}
|
||||
}
|
||||
|
||||
if ((new_value & private_handle_t::LOCK_STATE_READ_MASK) == 0) {
|
||||
LOGE("handle %p not locked", handle);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
new_value--;
|
||||
|
||||
} while (android_atomic_cmpxchg(current_value, new_value,
|
||||
(volatile int32_t*)&hnd->lockState));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int gralloc_perform(struct gralloc_module_t const* module,
|
||||
int operation, ... )
|
||||
{
|
||||
int res = -EINVAL;
|
||||
return res;
|
||||
}
|
324
libgralloc-legacy/pmemalloc.cpp
Normal file
324
libgralloc-legacy/pmemalloc.cpp
Normal file
@ -0,0 +1,324 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
//#define LOG_NDEBUG 0
|
||||
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <cutils/log.h>
|
||||
#include <cutils/ashmem.h>
|
||||
|
||||
#include "gralloc_priv.h"
|
||||
#include "pmemalloc.h"
|
||||
|
||||
|
||||
#define BEGIN_FUNC LOGV("%s begin", __PRETTY_FUNCTION__)
|
||||
#define END_FUNC LOGV("%s end", __PRETTY_FUNCTION__)
|
||||
|
||||
|
||||
static int get_open_flags(int usage) {
|
||||
int openFlags = O_RDWR | O_SYNC;
|
||||
uint32_t uread = usage & GRALLOC_USAGE_SW_READ_MASK;
|
||||
uint32_t uwrite = usage & GRALLOC_USAGE_SW_WRITE_MASK;
|
||||
if (uread == GRALLOC_USAGE_SW_READ_OFTEN ||
|
||||
uwrite == GRALLOC_USAGE_SW_WRITE_OFTEN) {
|
||||
openFlags &= ~O_SYNC;
|
||||
}
|
||||
return openFlags;
|
||||
}
|
||||
|
||||
PmemAllocator::~PmemAllocator()
|
||||
{
|
||||
BEGIN_FUNC;
|
||||
END_FUNC;
|
||||
}
|
||||
|
||||
|
||||
PmemUserspaceAllocator::PmemUserspaceAllocator(Deps& deps, Deps::Allocator& allocator, const char* pmemdev):
|
||||
deps(deps),
|
||||
allocator(allocator),
|
||||
pmemdev(pmemdev),
|
||||
master_fd(MASTER_FD_INIT)
|
||||
{
|
||||
BEGIN_FUNC;
|
||||
pthread_mutex_init(&lock, NULL);
|
||||
END_FUNC;
|
||||
}
|
||||
|
||||
|
||||
PmemUserspaceAllocator::~PmemUserspaceAllocator()
|
||||
{
|
||||
BEGIN_FUNC;
|
||||
END_FUNC;
|
||||
}
|
||||
|
||||
|
||||
void* PmemUserspaceAllocator::get_base_address() {
|
||||
BEGIN_FUNC;
|
||||
END_FUNC;
|
||||
return master_base;
|
||||
}
|
||||
|
||||
|
||||
int PmemUserspaceAllocator::init_pmem_area_locked()
|
||||
{
|
||||
BEGIN_FUNC;
|
||||
int err = 0;
|
||||
int fd = deps.open(pmemdev, O_RDWR, 0);
|
||||
if (fd >= 0) {
|
||||
size_t size = 0;
|
||||
err = deps.getPmemTotalSize(fd, &size);
|
||||
if (err < 0) {
|
||||
LOGE("%s: PMEM_GET_TOTAL_SIZE failed (%d), limp mode", pmemdev,
|
||||
err);
|
||||
size = 8<<20; // 8 MiB
|
||||
}
|
||||
allocator.setSize(size);
|
||||
|
||||
void* base = deps.mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd,
|
||||
0);
|
||||
if (base == MAP_FAILED) {
|
||||
LOGE("%s: failed to map pmem master fd: %s", pmemdev,
|
||||
strerror(deps.getErrno()));
|
||||
err = -deps.getErrno();
|
||||
base = 0;
|
||||
deps.close(fd);
|
||||
fd = -1;
|
||||
} else {
|
||||
master_fd = fd;
|
||||
master_base = base;
|
||||
}
|
||||
} else {
|
||||
LOGE("%s: failed to open pmem device: %s", pmemdev,
|
||||
strerror(deps.getErrno()));
|
||||
err = -deps.getErrno();
|
||||
}
|
||||
END_FUNC;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
int PmemUserspaceAllocator::init_pmem_area()
|
||||
{
|
||||
BEGIN_FUNC;
|
||||
pthread_mutex_lock(&lock);
|
||||
int err = master_fd;
|
||||
if (err == MASTER_FD_INIT) {
|
||||
// first time, try to initialize pmem
|
||||
err = init_pmem_area_locked();
|
||||
if (err) {
|
||||
LOGE("%s: failed to initialize pmem area", pmemdev);
|
||||
master_fd = err;
|
||||
}
|
||||
} else if (err < 0) {
|
||||
// pmem couldn't be initialized, never use it
|
||||
} else {
|
||||
// pmem OK
|
||||
err = 0;
|
||||
}
|
||||
pthread_mutex_unlock(&lock);
|
||||
END_FUNC;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
int PmemUserspaceAllocator::alloc_pmem_buffer(size_t size, int usage,
|
||||
void** pBase, int* pOffset, int* pFd)
|
||||
{
|
||||
BEGIN_FUNC;
|
||||
int err = init_pmem_area();
|
||||
if (err == 0) {
|
||||
void* base = master_base;
|
||||
int offset = allocator.allocate(size);
|
||||
if (offset < 0) {
|
||||
// no more pmem memory
|
||||
LOGE("%s: no more pmem available", pmemdev);
|
||||
err = -ENOMEM;
|
||||
} else {
|
||||
int openFlags = get_open_flags(usage);
|
||||
|
||||
//LOGD("%s: allocating pmem at offset 0x%p", pmemdev, offset);
|
||||
|
||||
// now create the "sub-heap"
|
||||
int fd = deps.open(pmemdev, openFlags, 0);
|
||||
err = fd < 0 ? fd : 0;
|
||||
|
||||
// and connect to it
|
||||
if (err == 0)
|
||||
err = deps.connectPmem(fd, master_fd);
|
||||
|
||||
// and make it available to the client process
|
||||
if (err == 0)
|
||||
err = deps.mapPmem(fd, offset, size);
|
||||
|
||||
if (err < 0) {
|
||||
LOGE("%s: failed to initialize pmem sub-heap: %d", pmemdev,
|
||||
err);
|
||||
err = -deps.getErrno();
|
||||
deps.close(fd);
|
||||
allocator.deallocate(offset);
|
||||
fd = -1;
|
||||
} else {
|
||||
LOGV("%s: mapped fd %d at offset %d, size %d", pmemdev, fd, offset, size);
|
||||
memset((char*)base + offset, 0, size);
|
||||
*pBase = base;
|
||||
*pOffset = offset;
|
||||
*pFd = fd;
|
||||
}
|
||||
//LOGD_IF(!err, "%s: allocating pmem size=%d, offset=%d", pmemdev, size, offset);
|
||||
}
|
||||
}
|
||||
END_FUNC;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
int PmemUserspaceAllocator::free_pmem_buffer(size_t size, void* base, int offset, int fd)
|
||||
{
|
||||
BEGIN_FUNC;
|
||||
int err = 0;
|
||||
if (fd >= 0) {
|
||||
int err = deps.unmapPmem(fd, offset, size);
|
||||
LOGE_IF(err<0, "PMEM_UNMAP failed (%s), fd=%d, sub.offset=%u, "
|
||||
"sub.size=%u", strerror(deps.getErrno()), fd, offset, size);
|
||||
if (err == 0) {
|
||||
// we can't deallocate the memory in case of UNMAP failure
|
||||
// because it would give that process access to someone else's
|
||||
// surfaces, which would be a security breach.
|
||||
allocator.deallocate(offset);
|
||||
}
|
||||
}
|
||||
END_FUNC;
|
||||
return err;
|
||||
}
|
||||
|
||||
PmemUserspaceAllocator::Deps::Allocator::~Allocator()
|
||||
{
|
||||
BEGIN_FUNC;
|
||||
END_FUNC;
|
||||
}
|
||||
|
||||
PmemUserspaceAllocator::Deps::~Deps()
|
||||
{
|
||||
BEGIN_FUNC;
|
||||
END_FUNC;
|
||||
}
|
||||
|
||||
PmemKernelAllocator::PmemKernelAllocator(Deps& deps, const char* pmemdev):
|
||||
deps(deps),
|
||||
pmemdev(pmemdev)
|
||||
{
|
||||
BEGIN_FUNC;
|
||||
END_FUNC;
|
||||
}
|
||||
|
||||
|
||||
PmemKernelAllocator::~PmemKernelAllocator()
|
||||
{
|
||||
BEGIN_FUNC;
|
||||
END_FUNC;
|
||||
}
|
||||
|
||||
|
||||
void* PmemKernelAllocator::get_base_address() {
|
||||
BEGIN_FUNC;
|
||||
END_FUNC;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static unsigned clp2(unsigned x) {
|
||||
x = x - 1;
|
||||
x = x | (x >> 1);
|
||||
x = x | (x >> 2);
|
||||
x = x | (x >> 4);
|
||||
x = x | (x >> 8);
|
||||
x = x | (x >>16);
|
||||
return x + 1;
|
||||
}
|
||||
|
||||
|
||||
int PmemKernelAllocator::alloc_pmem_buffer(size_t size, int usage,
|
||||
void** pBase,int* pOffset, int* pFd)
|
||||
{
|
||||
BEGIN_FUNC;
|
||||
|
||||
*pBase = 0;
|
||||
*pOffset = 0;
|
||||
*pFd = -1;
|
||||
|
||||
int err;
|
||||
int openFlags = get_open_flags(usage);
|
||||
int fd = deps.open(pmemdev, openFlags, 0);
|
||||
if (fd < 0) {
|
||||
err = -deps.getErrno();
|
||||
END_FUNC;
|
||||
return err;
|
||||
}
|
||||
|
||||
// The size should already be page aligned, now round it up to a power of 2.
|
||||
size = clp2(size);
|
||||
|
||||
void* base = deps.mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (base == MAP_FAILED) {
|
||||
LOGE("%s: failed to map pmem fd: %s", pmemdev,
|
||||
strerror(deps.getErrno()));
|
||||
err = -deps.getErrno();
|
||||
deps.close(fd);
|
||||
END_FUNC;
|
||||
return err;
|
||||
}
|
||||
|
||||
memset(base, 0, size);
|
||||
|
||||
*pBase = base;
|
||||
*pOffset = 0;
|
||||
*pFd = fd;
|
||||
|
||||
END_FUNC;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int PmemKernelAllocator::free_pmem_buffer(size_t size, void* base, int offset, int fd)
|
||||
{
|
||||
BEGIN_FUNC;
|
||||
// The size should already be page aligned, now round it up to a power of 2
|
||||
// like we did when allocating.
|
||||
size = clp2(size);
|
||||
|
||||
int err = deps.munmap(base, size);
|
||||
if (err < 0) {
|
||||
err = deps.getErrno();
|
||||
LOGW("%s: error unmapping pmem fd: %s", pmemdev, strerror(err));
|
||||
return -err;
|
||||
}
|
||||
END_FUNC;
|
||||
return 0;
|
||||
}
|
||||
|
||||
PmemKernelAllocator::Deps::~Deps()
|
||||
{
|
||||
BEGIN_FUNC;
|
||||
END_FUNC;
|
||||
}
|
161
libgralloc-legacy/pmemalloc.h
Normal file
161
libgralloc-legacy/pmemalloc.h
Normal file
@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef GRALLOC_QSD8K_PMEMALLOC_H
|
||||
#define GRALLOC_QSD8K_PMEMALLOC_H
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
/**
|
||||
* An interface to the PMEM allocators.
|
||||
*/
|
||||
class PmemAllocator {
|
||||
|
||||
public:
|
||||
|
||||
virtual ~PmemAllocator();
|
||||
|
||||
// Only valid after init_pmem_area() has completed successfully.
|
||||
virtual void* get_base_address() = 0;
|
||||
|
||||
virtual int alloc_pmem_buffer(size_t size, int usage, void** pBase,
|
||||
int* pOffset, int* pFd) = 0;
|
||||
virtual int free_pmem_buffer(size_t size, void* base, int offset, int fd) = 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A PMEM allocator that allocates the entire pmem memory from the kernel and
|
||||
* then uses a user-space allocator to suballocate from that. This requires
|
||||
* that the PMEM device driver have kernel allocation disabled.
|
||||
*/
|
||||
class PmemUserspaceAllocator: public PmemAllocator {
|
||||
|
||||
public:
|
||||
|
||||
class Deps {
|
||||
public:
|
||||
|
||||
class Allocator {
|
||||
public:
|
||||
virtual ~Allocator();
|
||||
virtual ssize_t setSize(size_t size) = 0;
|
||||
virtual size_t size() const = 0;
|
||||
virtual ssize_t allocate(size_t size, uint32_t flags = 0) = 0;
|
||||
virtual ssize_t deallocate(size_t offset) = 0;
|
||||
};
|
||||
|
||||
virtual ~Deps();
|
||||
|
||||
// pmem
|
||||
virtual size_t getPmemTotalSize(int fd, size_t* size) = 0;
|
||||
virtual int connectPmem(int fd, int master_fd) = 0;
|
||||
virtual int mapPmem(int fd, int offset, size_t size) = 0;
|
||||
virtual int unmapPmem(int fd, int offset, size_t size) = 0;
|
||||
|
||||
// C99
|
||||
virtual int getErrno() = 0;
|
||||
|
||||
// POSIX
|
||||
virtual void* mmap(void* start, size_t length, int prot, int flags, int fd,
|
||||
off_t offset) = 0;
|
||||
virtual int open(const char* pathname, int flags, int mode) = 0;
|
||||
virtual int close(int fd) = 0;
|
||||
};
|
||||
|
||||
PmemUserspaceAllocator(Deps& deps, Deps::Allocator& allocator, const char* pmemdev);
|
||||
virtual ~PmemUserspaceAllocator();
|
||||
|
||||
// Only valid after init_pmem_area() has completed successfully.
|
||||
virtual void* get_base_address();
|
||||
|
||||
virtual int init_pmem_area_locked();
|
||||
virtual int init_pmem_area();
|
||||
virtual int alloc_pmem_buffer(size_t size, int usage, void** pBase,
|
||||
int* pOffset, int* pFd);
|
||||
virtual int free_pmem_buffer(size_t size, void* base, int offset, int fd);
|
||||
|
||||
#ifndef ANDROID_OS
|
||||
// DO NOT USE: For testing purposes only.
|
||||
void set_master_values(int fd, void* base) {
|
||||
master_fd = fd;
|
||||
master_base = base;
|
||||
}
|
||||
#endif // ANDROID_OS
|
||||
|
||||
private:
|
||||
|
||||
enum {
|
||||
MASTER_FD_INIT = -1,
|
||||
};
|
||||
|
||||
Deps& deps;
|
||||
Deps::Allocator& allocator;
|
||||
|
||||
pthread_mutex_t lock;
|
||||
const char* pmemdev;
|
||||
int master_fd;
|
||||
void* master_base;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A PMEM allocator that allocates each individual allocation from the kernel
|
||||
* (using the kernel's allocator). This requires the kernel driver for the
|
||||
* particular PMEM device being allocated from to support kernel allocation.
|
||||
*/
|
||||
class PmemKernelAllocator: public PmemAllocator {
|
||||
|
||||
public:
|
||||
|
||||
class Deps {
|
||||
public:
|
||||
|
||||
virtual ~Deps();
|
||||
|
||||
// C99
|
||||
virtual int getErrno() = 0;
|
||||
|
||||
// POSIX
|
||||
virtual void* mmap(void* start, size_t length, int prot, int flags, int fd,
|
||||
off_t offset) = 0;
|
||||
virtual int munmap(void* start, size_t length) = 0;
|
||||
virtual int open(const char* pathname, int flags, int mode) = 0;
|
||||
virtual int close(int fd) = 0;
|
||||
};
|
||||
|
||||
PmemKernelAllocator(Deps& deps, const char* pmemdev);
|
||||
virtual ~PmemKernelAllocator();
|
||||
|
||||
// Only valid after init_pmem_area() has completed successfully.
|
||||
virtual void* get_base_address();
|
||||
|
||||
virtual int alloc_pmem_buffer(size_t size, int usage, void** pBase,
|
||||
int* pOffset, int* pFd);
|
||||
virtual int free_pmem_buffer(size_t size, void* base, int offset, int fd);
|
||||
|
||||
private:
|
||||
|
||||
Deps& deps;
|
||||
|
||||
const char* pmemdev;
|
||||
};
|
||||
|
||||
#endif // GRALLOC_QSD8K_PMEMALLOC_H
|
55
libgralloc-legacy/tests/Android.mk
Normal file
55
libgralloc-legacy/tests/Android.mk
Normal file
@ -0,0 +1,55 @@
|
||||
# Copyright (C) 2008 The Android Open Source Project
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
# you can use EXTRA_CFLAGS to indicate additional CFLAGS to use
|
||||
# in the build. The variables will be cleaned on exit
|
||||
#
|
||||
#
|
||||
|
||||
libgralloc_test_includes:= \
|
||||
bionic/libstdc++/include \
|
||||
external/astl/include \
|
||||
external/gtest/include \
|
||||
$(LOCAL_PATH)/..
|
||||
|
||||
libgralloc_test_static_libs := \
|
||||
libgralloc_qsd8k_host \
|
||||
libgtest_main_host \
|
||||
libgtest_host \
|
||||
libastl_host \
|
||||
liblog
|
||||
|
||||
define host-test
|
||||
$(foreach file,$(1), \
|
||||
$(eval include $(CLEAR_VARS)) \
|
||||
$(eval LOCAL_CPP_EXTENSION := .cpp) \
|
||||
$(eval LOCAL_SRC_FILES := $(file)) \
|
||||
$(eval LOCAL_C_INCLUDES := $(libgralloc_test_includes)) \
|
||||
$(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
|
||||
$(eval LOCAL_CFLAGS += $(EXTRA_CFLAGS)) \
|
||||
$(eval LOCAL_LDLIBS += $(EXTRA_LDLIBS)) \
|
||||
$(eval LOCAL_STATIC_LIBRARIES := $(libgralloc_test_static_libs)) \
|
||||
$(eval LOCAL_MODULE_TAGS := eng tests) \
|
||||
$(eval include $(BUILD_HOST_EXECUTABLE)) \
|
||||
) \
|
||||
$(eval EXTRA_CFLAGS :=) \
|
||||
$(eval EXTRA_LDLIBS :=)
|
||||
endef
|
||||
|
||||
TEST_SRC_FILES := \
|
||||
pmemalloc_test.cpp
|
||||
|
||||
$(call host-test, $(TEST_SRC_FILES))
|
601
libgralloc-legacy/tests/pmemalloc_test.cpp
Normal file
601
libgralloc-legacy/tests/pmemalloc_test.cpp
Normal file
@ -0,0 +1,601 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "pmemalloc.h"
|
||||
|
||||
class DepsStub : public PmemUserspaceAllocator::Deps, public PmemKernelAllocator::Deps {
|
||||
|
||||
public:
|
||||
|
||||
virtual size_t getPmemTotalSize(int fd, size_t* size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual int connectPmem(int fd, int master_fd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual int mapPmem(int fd, int offset, size_t size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual int unmapPmem(int fd, int offset, size_t size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual int getErrno() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual void* mmap(void* start, size_t length, int prot, int flags, int fd,
|
||||
off_t offset) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual int munmap(void* start, size_t length) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual int open(const char* pathname, int flags, int mode) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual int close(int fd) {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
class AllocatorStub : public PmemUserspaceAllocator::Deps::Allocator {
|
||||
virtual ssize_t setSize(size_t size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual size_t size() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual ssize_t allocate(size_t size, uint32_t flags = 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual ssize_t deallocate(size_t offset) {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static const char* fakePmemDev = "/foo/bar";
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
struct Deps_InitPmemAreaLockedWithSuccessfulCompletion : public DepsStub {
|
||||
|
||||
virtual int open(const char* pathname, int flags, int mode) {
|
||||
EXPECT_EQ(fakePmemDev, pathname);
|
||||
EXPECT_EQ(O_RDWR, flags);
|
||||
EXPECT_EQ(0, mode);
|
||||
return 1234;
|
||||
}
|
||||
|
||||
virtual size_t getPmemTotalSize(int fd, size_t* size) {
|
||||
EXPECT_EQ(1234, fd);
|
||||
*size = 16 << 20;
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual void* mmap(void* start, size_t length, int prot, int flags, int fd,
|
||||
off_t offset) {
|
||||
EXPECT_EQ(1234, fd);
|
||||
return (void*)0x87654321;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct Allocator_InitPmemAreaLockedWithSuccessfulCompletion : public AllocatorStub {
|
||||
|
||||
virtual ssize_t setSize(size_t size) {
|
||||
EXPECT_EQ(size_t(16 << 20), size);
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
TEST(test_pmem_userspace_allocator, testInitPmemAreaLockedWithSuccessfulCompletion) {
|
||||
Deps_InitPmemAreaLockedWithSuccessfulCompletion depsMock;
|
||||
Allocator_InitPmemAreaLockedWithSuccessfulCompletion allocMock;
|
||||
PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev);
|
||||
|
||||
int result = pma.init_pmem_area_locked();
|
||||
ASSERT_EQ(0, result);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
struct Deps_InitPmemAreaLockedWithEnomemOnMmap : public DepsStub {
|
||||
|
||||
virtual int open(const char* pathname, int flags, int mode) {
|
||||
EXPECT_EQ(fakePmemDev, pathname);
|
||||
EXPECT_EQ(O_RDWR, flags);
|
||||
EXPECT_EQ(0, mode);
|
||||
return 1234;
|
||||
}
|
||||
|
||||
virtual size_t getPmemTotalSize(int fd, size_t* size) {
|
||||
EXPECT_EQ(1234, fd);
|
||||
*size = 16 << 20;
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual int getErrno() {
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
virtual void* mmap(void* start, size_t length, int prot, int flags, int fd,
|
||||
off_t offset) {
|
||||
return (void*)MAP_FAILED;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct Allocator_InitPmemAreaLockedWithEnomemOnMmap : public AllocatorStub {
|
||||
|
||||
virtual ssize_t setSize(size_t size) {
|
||||
EXPECT_EQ(size_t(16 << 20), size);
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
TEST(test_pmem_userspace_allocator, testInitPmemAreaLockedWthEnomemOnMmap) {
|
||||
Deps_InitPmemAreaLockedWithEnomemOnMmap depsMock;
|
||||
Allocator_InitPmemAreaLockedWithEnomemOnMmap allocMock;
|
||||
PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev);
|
||||
|
||||
int result = pma.init_pmem_area_locked();
|
||||
ASSERT_EQ(-ENOMEM, result);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
struct Deps_InitPmemAreaLockedWithEaccesOnGetPmemTotalSize : public DepsStub {
|
||||
|
||||
virtual int open(const char* pathname, int flags, int mode) {
|
||||
EXPECT_EQ(fakePmemDev, pathname);
|
||||
EXPECT_EQ(O_RDWR, flags);
|
||||
EXPECT_EQ(0, mode);
|
||||
return 1234;
|
||||
}
|
||||
|
||||
virtual size_t getPmemTotalSize(int fd, size_t* size) {
|
||||
EXPECT_EQ(1234, fd);
|
||||
return -EACCES;
|
||||
}
|
||||
};
|
||||
|
||||
TEST(test_pmem_userspace_allocator, testInitPmemAreaLockedWthEaccesOnGetPmemTotalSize) {
|
||||
Deps_InitPmemAreaLockedWithEaccesOnGetPmemTotalSize depsMock;
|
||||
AllocatorStub allocStub;
|
||||
PmemUserspaceAllocator pma(depsMock, allocStub, fakePmemDev);
|
||||
|
||||
int result = pma.init_pmem_area_locked();
|
||||
ASSERT_EQ(-EACCES, result);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
struct Deps_InitPmemAreaLockedWithEaccesOnOpen : public DepsStub {
|
||||
|
||||
virtual int getErrno() {
|
||||
return EACCES;
|
||||
}
|
||||
|
||||
virtual int open(const char* pathname, int flags, int mode) {
|
||||
EXPECT_EQ(fakePmemDev, pathname);
|
||||
EXPECT_EQ(O_RDWR, flags);
|
||||
EXPECT_EQ(0, mode);
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
TEST(test_pmem_userspace_allocator, testInitPmemAreaLockedWithEaccesOnOpenMaster) {
|
||||
Deps_InitPmemAreaLockedWithEaccesOnOpen depsMock;
|
||||
AllocatorStub allocStub;
|
||||
PmemUserspaceAllocator pma(depsMock, allocStub, fakePmemDev);
|
||||
|
||||
int result = pma.init_pmem_area_locked();
|
||||
ASSERT_EQ(-EACCES, result);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
typedef Deps_InitPmemAreaLockedWithSuccessfulCompletion Deps_InitPmemAreaWithSuccessfulInitialCompletion;
|
||||
|
||||
TEST(test_pmem_userspace_allocator, testInitPmemAreaWithSuccessfulInitialCompletion) {
|
||||
Deps_InitPmemAreaWithSuccessfulInitialCompletion depsMock;
|
||||
AllocatorStub allocStub;
|
||||
PmemUserspaceAllocator pma(depsMock, allocStub, fakePmemDev);
|
||||
|
||||
int result = pma.init_pmem_area();
|
||||
ASSERT_EQ(0, result);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
typedef Deps_InitPmemAreaLockedWithEaccesOnOpen Deps_InitPmemAreaWithEaccesOnInitLocked;
|
||||
|
||||
TEST(test_pmem_userspace_allocator, testInitPmemAreaWithEaccesOnInitLocked) {
|
||||
Deps_InitPmemAreaWithEaccesOnInitLocked depsMock;
|
||||
AllocatorStub allocStub;
|
||||
PmemUserspaceAllocator pma(depsMock, allocStub, fakePmemDev);
|
||||
|
||||
int result = pma.init_pmem_area();
|
||||
ASSERT_EQ(-EACCES, result);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
TEST(test_pmem_userspace_allocator, testInitPmemAreaAfterSuccessfulInitialCompletion) {
|
||||
DepsStub depsStub;
|
||||
AllocatorStub allocStub;
|
||||
PmemUserspaceAllocator pma(depsStub, allocStub, fakePmemDev);
|
||||
|
||||
pma.set_master_values(1234, 0); // Indicate that the pma has been successfully init'd
|
||||
|
||||
int result = pma.init_pmem_area();
|
||||
ASSERT_EQ(0, result);
|
||||
//XXX JMG: Add this back in maybe? ASSERT_EQ(1234, pmi.master); // Make sure the master fd wasn't changed
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
TEST(test_pmem_userspace_allocator, testInitPmemAreaAfterFailedInit) {
|
||||
DepsStub depsStub;
|
||||
AllocatorStub allocStub;
|
||||
PmemUserspaceAllocator pma(depsStub, allocStub, fakePmemDev);
|
||||
|
||||
pma.set_master_values(-EACCES, 0); // Indicate that the pma has failed init
|
||||
|
||||
int result = pma.init_pmem_area();
|
||||
ASSERT_EQ(-EACCES, result);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
struct Deps_InitPmemAreaLockedWithSuccessfulCompletionWithNoFlags : public DepsStub {
|
||||
|
||||
virtual int open(const char* pathname, int flags, int mode) {
|
||||
EXPECT_EQ(fakePmemDev, pathname);
|
||||
EXPECT_EQ(O_RDWR, flags & O_RDWR);
|
||||
EXPECT_EQ(0, mode);
|
||||
return 5678;
|
||||
}
|
||||
|
||||
virtual int connectPmem(int fd, int master_fd) {
|
||||
EXPECT_EQ(5678, fd);
|
||||
EXPECT_EQ(1234, master_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual int mapPmem(int fd, int offset, size_t size) {
|
||||
EXPECT_EQ(5678, fd);
|
||||
EXPECT_EQ(0x300, offset);
|
||||
EXPECT_EQ(size_t(0x100), size);
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct Allocator_AllocPmemBufferWithSuccessfulCompletionWithNoFlags : public AllocatorStub {
|
||||
|
||||
virtual ssize_t allocate(size_t size, uint32_t flags = 0) {
|
||||
EXPECT_EQ(size_t(0x100), size);
|
||||
EXPECT_EQ(uint32_t(0x0), flags);
|
||||
return 0x300;
|
||||
}
|
||||
};
|
||||
|
||||
TEST(test_pmem_userspace_allocator, testAllocPmemBufferWithSuccessfulCompletionWithNoFlags) {
|
||||
Deps_InitPmemAreaLockedWithSuccessfulCompletionWithNoFlags depsMock;
|
||||
Allocator_AllocPmemBufferWithSuccessfulCompletionWithNoFlags allocMock;
|
||||
PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev);
|
||||
|
||||
uint8_t buf[0x300 + 0x100]; // Create a buffer to get memzero'd
|
||||
pma.set_master_values(1234, buf); // Indicate that the pma has been successfully init'd
|
||||
|
||||
void* base = 0;
|
||||
int offset = -9182, fd = -9182;
|
||||
int size = 0x100;
|
||||
int flags = 0;
|
||||
int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
|
||||
ASSERT_EQ(0, result);
|
||||
ASSERT_EQ(0x300, offset);
|
||||
ASSERT_EQ(5678, fd);
|
||||
for (int i = 0x300; i < 0x400; ++i) {
|
||||
ASSERT_EQ(uint8_t(0), buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
typedef Deps_InitPmemAreaLockedWithSuccessfulCompletionWithNoFlags Deps_InitPmemAreaLockedWithSuccessfulCompletionWithAllFlags;
|
||||
|
||||
typedef Allocator_AllocPmemBufferWithSuccessfulCompletionWithNoFlags Allocator_AllocPmemBufferWithSuccessfulCompletionWithAllFlags;
|
||||
|
||||
TEST(test_pmem_userspace_allocator, testAllocPmemBufferWithSuccessfulCompletionWithAllFlags) {
|
||||
Deps_InitPmemAreaLockedWithSuccessfulCompletionWithAllFlags depsMock;
|
||||
Allocator_AllocPmemBufferWithSuccessfulCompletionWithAllFlags allocMock;
|
||||
PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev);
|
||||
|
||||
uint8_t buf[0x300 + 0x100]; // Create a buffer to get memzero'd
|
||||
pma.set_master_values(1234, buf); // Indicate that the pma has been successfully init'd
|
||||
|
||||
void* base = 0;
|
||||
int offset = -9182, fd = -9182;
|
||||
int size = 0x100;
|
||||
int flags = ~0;
|
||||
int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
|
||||
ASSERT_EQ(0, result);
|
||||
ASSERT_EQ(0x300, offset);
|
||||
ASSERT_EQ(5678, fd);
|
||||
for (int i = 0x300; i < 0x400; ++i) {
|
||||
ASSERT_EQ(0, buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
struct Deps_InitPmemAreaLockedWithEnodevOnOpen : public Deps_InitPmemAreaLockedWithSuccessfulCompletionWithNoFlags {
|
||||
|
||||
virtual int getErrno() {
|
||||
return ENODEV;
|
||||
}
|
||||
|
||||
virtual int open(const char* pathname, int flags, int mode) {
|
||||
EXPECT_EQ(fakePmemDev, pathname);
|
||||
EXPECT_EQ(O_RDWR, flags & O_RDWR);
|
||||
EXPECT_EQ(0, mode);
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
typedef Allocator_AllocPmemBufferWithSuccessfulCompletionWithNoFlags Allocator_AllocPmemBufferWithEnodevOnOpen;
|
||||
|
||||
TEST(test_pmem_userspace_allocator, testAllocPmemBufferWithSuccessfulCompletionWithEnodevOnOpen) {
|
||||
Deps_InitPmemAreaLockedWithEnodevOnOpen depsMock;
|
||||
Allocator_AllocPmemBufferWithEnodevOnOpen allocMock;
|
||||
PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev);
|
||||
|
||||
uint8_t buf[0x300 + 0x100]; // Create a buffer to get memzero'd
|
||||
pma.set_master_values(1234, buf); // Indicate that the pma has been successfully init'd
|
||||
|
||||
void* base = 0;
|
||||
int offset = -9182, fd = -9182;
|
||||
int size = 0x100;
|
||||
int flags = ~0;
|
||||
int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
|
||||
ASSERT_EQ(-ENODEV, result);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
struct Deps_InitPmemAreaLockedWithEnomemOnConnectPmem : public Deps_InitPmemAreaLockedWithSuccessfulCompletionWithNoFlags {
|
||||
|
||||
virtual int getErrno() {
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
virtual int connectPmem(int fd, int master_fd) {
|
||||
EXPECT_EQ(5678, fd);
|
||||
EXPECT_EQ(1234, master_fd);
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
typedef Allocator_AllocPmemBufferWithSuccessfulCompletionWithNoFlags Allocator_AllocPmemBufferWithEnomemOnConnectPmem;
|
||||
|
||||
TEST(test_pmem_userspace_allocator, testAllocPmemBufferWithSuccessfulCompletionWithEnomemOnConnectPmem) {
|
||||
Deps_InitPmemAreaLockedWithEnomemOnConnectPmem depsMock;
|
||||
Allocator_AllocPmemBufferWithEnomemOnConnectPmem allocMock;
|
||||
PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev);
|
||||
|
||||
uint8_t buf[0x300 + 0x100]; // Create a buffer to get memzero'd
|
||||
pma.set_master_values(1234, buf); // Indicate that the pma has been successfully init'd
|
||||
|
||||
void* base = 0;
|
||||
int offset = -9182, fd = -9182;
|
||||
int size = 0x100;
|
||||
int flags = ~0;
|
||||
int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
|
||||
ASSERT_EQ(-ENOMEM, result);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
struct Deps_InitPmemAreaLockedWithEnomemOnMapPmem : public Deps_InitPmemAreaLockedWithSuccessfulCompletionWithNoFlags {
|
||||
|
||||
virtual int getErrno() {
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
virtual int mapPmem(int fd, int offset, size_t size) {
|
||||
EXPECT_EQ(5678, fd);
|
||||
EXPECT_EQ(0x300, offset);
|
||||
EXPECT_EQ(size_t(0x100), size);
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
typedef Allocator_AllocPmemBufferWithSuccessfulCompletionWithNoFlags Allocator_AllocPmemBufferWithEnomemOnMapPmem;
|
||||
|
||||
TEST(test_pmem_userspace_allocator, testAllocPmemBufferWithEnomemOnMapPmem) {
|
||||
Deps_InitPmemAreaLockedWithEnomemOnMapPmem depsMock;
|
||||
Allocator_AllocPmemBufferWithEnomemOnMapPmem allocMock;
|
||||
PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev);
|
||||
|
||||
uint8_t buf[0x300 + 0x100]; // Create a buffer to get memzero'd
|
||||
pma.set_master_values(1234, buf); // Indicate that the pma has been successfully init'd
|
||||
|
||||
void* base = 0;
|
||||
int offset = -9182, fd = -9182;
|
||||
int size = 0x100;
|
||||
int flags = ~0;
|
||||
int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
|
||||
ASSERT_EQ(-ENOMEM, result);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
struct Deps_KernelAllocPmemBufferWithSuccessfulCompletionWithNoFlags : public DepsStub {
|
||||
|
||||
void* mmapResult;
|
||||
|
||||
Deps_KernelAllocPmemBufferWithSuccessfulCompletionWithNoFlags(void* mmapResult) :
|
||||
mmapResult(mmapResult) {}
|
||||
|
||||
virtual int open(const char* pathname, int flags, int mode) {
|
||||
EXPECT_EQ(fakePmemDev, pathname);
|
||||
EXPECT_EQ(O_RDWR, flags & O_RDWR);
|
||||
EXPECT_EQ(0, mode);
|
||||
return 5678;
|
||||
}
|
||||
|
||||
virtual void* mmap(void* start, size_t length, int prot, int flags, int fd,
|
||||
off_t offset) {
|
||||
EXPECT_EQ(5678, fd);
|
||||
return mmapResult;
|
||||
}
|
||||
};
|
||||
|
||||
TEST(test_pmem_kernel_allocator, testAllocPmemBufferWithSuccessfulCompletionWithNoFlags) {
|
||||
uint8_t buf[0x100]; // Create a buffer to get memzero'd
|
||||
Deps_KernelAllocPmemBufferWithSuccessfulCompletionWithNoFlags depsMock(buf);
|
||||
PmemKernelAllocator pma(depsMock, fakePmemDev);
|
||||
|
||||
void* base = 0;
|
||||
int offset = -9182, fd = -9182;
|
||||
int size = 0x100;
|
||||
int flags = 0;
|
||||
int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
|
||||
ASSERT_EQ(0, result);
|
||||
ASSERT_EQ(buf, base);
|
||||
ASSERT_EQ(0, offset);
|
||||
ASSERT_EQ(5678, fd);
|
||||
for (int i = 0; i < 0x100; ++i) {
|
||||
ASSERT_EQ(0, buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
typedef Deps_KernelAllocPmemBufferWithSuccessfulCompletionWithNoFlags Deps_KernelAllocPmemBufferWithSuccessfulCompletionWithAllFlags;
|
||||
|
||||
TEST(test_pmem_kernel_allocator, testAllocPmemBufferWithSuccessfulCompletionWithAllFlags) {
|
||||
uint8_t buf[0x100]; // Create a buffer to get memzero'd
|
||||
Deps_KernelAllocPmemBufferWithSuccessfulCompletionWithAllFlags depsMock(buf);
|
||||
PmemKernelAllocator pma(depsMock, fakePmemDev);
|
||||
|
||||
void* base = 0;
|
||||
int offset = -9182, fd = -9182;
|
||||
int size = 0x100;
|
||||
int flags = ~0;
|
||||
int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
|
||||
ASSERT_EQ(0, result);
|
||||
ASSERT_EQ(buf, base);
|
||||
ASSERT_EQ(0, offset);
|
||||
ASSERT_EQ(5678, fd);
|
||||
for (int i = 0; i < 0x100; ++i) {
|
||||
ASSERT_EQ(0, buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
struct Deps_KernelAllocPmemBufferWithEpermOnOpen : public DepsStub {
|
||||
|
||||
virtual int getErrno() {
|
||||
return EPERM;
|
||||
}
|
||||
|
||||
virtual int open(const char* pathname, int flags, int mode) {
|
||||
EXPECT_EQ(fakePmemDev, pathname);
|
||||
EXPECT_EQ(O_RDWR, flags & O_RDWR);
|
||||
EXPECT_EQ(0, mode);
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
TEST(test_pmem_kernel_allocator, testAllocPmemBufferWithEpermOnOpen) {
|
||||
Deps_KernelAllocPmemBufferWithEpermOnOpen depsMock;
|
||||
PmemKernelAllocator pma(depsMock, fakePmemDev);
|
||||
|
||||
void* base = 0;
|
||||
int offset = -9182, fd = -9182;
|
||||
int size = 0x100;
|
||||
int flags = ~0;
|
||||
int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
|
||||
ASSERT_EQ(-EPERM, result);
|
||||
ASSERT_EQ(0, base);
|
||||
ASSERT_EQ(0, offset);
|
||||
ASSERT_EQ(-1, fd);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
struct Deps_KernelAllocPmemBufferWithEnomemOnMmap : DepsStub {
|
||||
|
||||
virtual int open(const char* pathname, int flags, int mode) {
|
||||
EXPECT_EQ(fakePmemDev, pathname);
|
||||
EXPECT_EQ(O_RDWR, flags & O_RDWR);
|
||||
EXPECT_EQ(0, mode);
|
||||
return 5678;
|
||||
}
|
||||
|
||||
virtual void* mmap(void* start, size_t length, int prot, int flags, int fd,
|
||||
off_t offset) {
|
||||
return (void*)MAP_FAILED;
|
||||
}
|
||||
|
||||
virtual int getErrno() {
|
||||
return ENOMEM;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
TEST(test_pmem_kernel_allocator, testAllocPmemBufferWithEnomemOnMmap) {
|
||||
Deps_KernelAllocPmemBufferWithEnomemOnMmap depsMock;
|
||||
PmemKernelAllocator pma(depsMock, fakePmemDev);
|
||||
|
||||
void* base = 0;
|
||||
int offset = -9182, fd = -9182;
|
||||
int size = 0x100;
|
||||
int flags = ~0;
|
||||
int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
|
||||
ASSERT_EQ(-ENOMEM, result);
|
||||
ASSERT_EQ(0, base);
|
||||
ASSERT_EQ(0, offset);
|
||||
ASSERT_EQ(-1, fd);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
Loading…
Reference in New Issue
Block a user