1 /*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include "VideoTex.h"
17
18 #include "glError.h"
19
20 #include <ui/GraphicBuffer.h>
21 #include <ui/GraphicBufferAllocator.h>
22 #include <ui/GraphicBufferMapper.h>
23
24 #include <alloca.h>
25 #include <fcntl.h>
26 #include <malloc.h>
27 #include <png.h>
28 #include <stdio.h>
29 #include <sys/ioctl.h>
30 #include <unistd.h>
31
32 #include <vector>
33
34 namespace android {
35 namespace automotive {
36 namespace evs {
37 namespace support {
38
39 // Eventually we shouldn't need this dependency, but for now the
40 // graphics allocator interface isn't fully supported on all platforms
41 // and this is our work around.
42 using ::android::GraphicBuffer;
43
VideoTex(EGLDisplay glDisplay)44 VideoTex::VideoTex(EGLDisplay glDisplay) : TexWrapper(), mDisplay(glDisplay) {
45 // Nothing but initialization here...
46 }
47
~VideoTex()48 VideoTex::~VideoTex() {
49 // Drop our device texture image
50 if (mKHRimage != EGL_NO_IMAGE_KHR) {
51 eglDestroyImageKHR(mDisplay, mKHRimage);
52 mKHRimage = EGL_NO_IMAGE_KHR;
53 }
54 }
55
56 // Return true if the texture contents are changed
refresh(const BufferDesc & imageBuffer)57 bool VideoTex::refresh(const BufferDesc& imageBuffer) {
58 // No new image has been delivered, so there's nothing to do here
59 if (imageBuffer.memHandle.getNativeHandle() == nullptr) {
60 return false;
61 }
62
63 // Drop our device texture image
64 if (mKHRimage != EGL_NO_IMAGE_KHR) {
65 eglDestroyImageKHR(mDisplay, mKHRimage);
66 mKHRimage = EGL_NO_IMAGE_KHR;
67 }
68
69 // create a GraphicBuffer from the existing handle
70 sp<GraphicBuffer> imageGraphicBuffer =
71 new GraphicBuffer(imageBuffer.memHandle, GraphicBuffer::CLONE_HANDLE, imageBuffer.width,
72 imageBuffer.height, imageBuffer.format, 1, // layer count
73 GRALLOC_USAGE_HW_TEXTURE, imageBuffer.stride);
74
75 if (imageGraphicBuffer.get() == nullptr) {
76 ALOGE("Failed to allocate GraphicBuffer to wrap image handle");
77 // Returning "true" in this error condition because we already released the
78 // previous image (if any) and so the texture may change in unpredictable ways now!
79 return true;
80 }
81
82 // Get a GL compatible reference to the graphics buffer we've been given
83 EGLint eglImageAttributes[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
84 EGLClientBuffer clientBuf = static_cast<EGLClientBuffer>(imageGraphicBuffer->getNativeBuffer());
85 mKHRimage = eglCreateImageKHR(mDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, clientBuf,
86 eglImageAttributes);
87 if (mKHRimage == EGL_NO_IMAGE_KHR) {
88 const char* msg = getEGLError();
89 ALOGE("error creating EGLImage: %s", msg);
90 return false;
91 } else {
92 // Update the texture handle we already created to refer to this gralloc buffer
93 glActiveTexture(GL_TEXTURE0);
94 glBindTexture(GL_TEXTURE_2D, glId());
95 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, static_cast<GLeglImageOES>(mKHRimage));
96
97 // Initialize the sampling properties (it seems the sample may not work if this isn't done)
98 // The user of this texture may very well want to set their own filtering, but we're going
99 // to pay the (minor) price of setting this up for them to avoid the dreaded "black image"
100 // if they forget.
101 // TODO: Can we do this once for the texture ID rather than ever refresh?
102 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
103 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
104 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
105 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
106 }
107
108 return true;
109 }
110 } // namespace support
111 } // namespace evs
112 } // namespace automotive
113 } // namespace android
114